java学习-继承和final方法
1. 继承
1.1 继承的概述
- 继承面向对象中的一大特征
- 继承 : 让类与类之间发生关系(关联), 子父类关系 ; 使用extends关键字,让类与类之间具有子父类继承关系
- 举例 :
class A{}
class B extends A{}
上述代码:
A类被继承的类 : 称为父类, 超类, 基类
B类用于继承 : 称为子类, 派生类
1.2继承发生场景
如果同一个类别的多个事物之间, 具有共性, 将共性内容向上抽取, 抽取到一个父类中,剩下的类作为这个父类的子类 ; 父类中实现共性内容, 每一个子类只需要实现其特有的内容即可, 子类可以通过继承关系使用父类中的共性内容
注意 : 不要为了节省几个方法的设计,贸然使用继承关系; 继承关系通常都是属于关系(is a), 举例 : 猫和狗都属于动物, 因此猫和狗可以作为动物的子类
代码
public class Animal { public void eat() { System.out.println("动物都需要吃饭"); } public void sleep() { System.out.println("动物都需要睡觉"); } }
public class Cat extends Animal{ public void catchMouse() { System.out.println("猫能抓老鼠"); } }
public class Dog extends Animal { public void lookHome() { System.out.println("狗可以看家"); } }
public class TestAnimal { public static void main(String[] args) { // 1. 创建出一个Cat对象 Cat c = new Cat(); c.eat();// eat方法从父类Animal类中继承使用 c.sleep();// sleep方法从父类Animal类中继承使用 c.catchMouse();// catchMouse方法是Cat类型特有方法 // 2. 创建出一个Dog对象 Dog d = new Dog(); d.eat(); d.sleep(); d.lookHome(); } }
1.3 继承使用的注意事项
- 父类中的私有成员变量和方法, 无法被子类继承使用
私有都是使用private关键字修饰的, 私有只能在当前类型中使用, 子类不是父类类型本身, 私有因为权限使用范围,所以子类无法继承使用父类中的私有成员
- 父类的构造方法无法被子类继承, 但是子类可以调用父类构造
父类构造是父类类名; 子类构造是子类类名, 如果可以继承父类构造,就会发生构造名称与子类类名不一致的情况,矛盾, 因此子类不能继承父类构造
1.4 继承的特点
- java中, 继承关系都是单继承, 不支持多继承,可以多层继承
- 单继承 : 一个子类只能有一个直接父类
- 不支持多继承 : 不支持一个子类同时继承多个父类
-
多层继承:
C类继承B类 : C是B的子类
B类继承A类 : B是A的子类
C类可以继承到B类,A类中的所有的可继承内容
代码
public class A { public void eat() { System.out.println("Aeat"); } public void fun() { System.out.println("A玩"); } }
public class B extends A { public void sleep() { System.out.println("Bsleep"); } public void fun() { System.out.println("B玩"); } }
public class C extends B{ }
public class TestABC { public static void main(String[] args) { C c = new C(); c.fun();// fun使用从父类B继承来的方法 c.eat();// eat使用从爷爷A继承来的方法 c.sleep();// fun使用从父类B继承来的方法 } }
1.5 继承中的成员变量
子类可以继承使用父类中的非私有成员变量
1 子父类成员变量不重名
如果子类中定义了与父类不重名的成员变量, 子类可以使用从父类继承来的成员变量,也可以使用子类特有的变量
2 super关键字区分子父类成员变量重名
如果子类中定义了与父类中同名的成员变量
1) 变量的使用需要符合就近原则:
a : 方法中使用变量,如果方法中已经定义出了局部变量, 优先使用局部
b : 没有定义局部变量,使用当前类型中成员变量
c : 如果类型中没有定义出成员变量,到父类中寻找可继承的成员...一直找最顶层的父类处(Object)
2) 区分子父类变量的重名问题 : 可以在子类中使用super关键字
super : 关键字, 表示当前类型对应的父类对象的引用
在子类代码中 : super.调用变量, 带有super关键字的变量,表示父类成员变量的调用
代码
public class Father { // 1. 继承中的成员变量使用 int i = 10; int w = 20; }
public class Son extends Father { // 1. 继承中成员变量 // Son从父类中继承到变量i = 10; w = 20; int j = 99; // 子类定义出了与父类同名的成员变量w int w = 88; public void useVariable() { int w = 999; System.out.println(w);// 999 System.out.println(this.w);// 88 // 使用父类中的w变量 System.out.println(super.w);// 20 } }
public class TestFatherAndSon { public static void main(String[] args) { // 1. 创建出一个Son子类 对象 Son son = new Son(); System.out.println(son.i);// 父类变量i System.out.println(son.j);// 子类特有变量j System.out.println(son.w);// 与父类重名的变量w, 使用子类的w,88 System.out.println("----------------"); son.useVariable(); } }
1.7继承中的成员方法
- 父类中的私有方法无法被子类继承
- 如果子类中定义的方法功能与父类中的方法功能不重名,不重复, 子类可以使用自己定义的方法功能,也可以使用从父类继承来的方法
- 如果子类对于从父类继承而来的方法功能, 认为不能实现子类的要求, 那么子类可以重写父类中继承而来的方法, 重写的目的是为了让方法越来越好
1) 方法重写 : 方法声明上与父类一致,方法的实现逻辑上与父类不一致
2) 方法重写规则:
要求 :
a : 方法返回值类型, 方法名, 参数列表, 与父类方法保持一致
b : 方法体可以做任意逻辑实现
c : 子类重写的方法在权限修饰上, 大于等于父类的使用权限
public ---->默认权限(没有任何权限修饰)--->private(私有)
d : 验证这个方法是否是子类重写方法, @Override (Override表示重写), 写在方法声明之上
4.如果子父类具有重名的方法, 如何区分:
super.父类方法名(实际参数);
super关键字调用的方法表示父类方法的调用,记得super关键字用于子类中
1.8 this和super关键字的使用总结
- this 关键字 : 表示本类(当前类型)对象引用
1) 用于区分局部变量和成员变量重名问题
带有this.关键字的变量,表示成员变量的使用
2) 本类的构造方法之间互相调用
this(构造需要的实际参数); // 必须写在构造方法中有效行第一行
2.super关键字 : 表示当前类型父类对象的引用
1) 用于区分子类和父类中的重名的变量和方法问题
带有super.关键字的变量和方法, 表示父类的变量或方法的使用
3) 子类的构造方法调用父类的构造
super(父类构造需要的实际参数); // 必须写在构造方法中有效行第一行
3.静态方法中,不能使用this和super关键字, 静态中不能直接使用非静态
This() 和 super() 作为构造中的调用语句都要放在第一行, 因此两者不能同时出现在同一个构造中, 二选一
2. final关键字
- final关键字 : 修饰符, 表示最终的,最后的,不可改变的
- final关键字可以修饰 : 类, 方法, 变量
1) final修饰类 : 这个类就是一个不可改变的类,最终类
使用final修饰的类,不能当父类; 最终就体现在没有子类重写改变父类中内容; final修饰的类使用一切正常
2) final修饰方法 : 这个方法就是最终方法,不可改变
使用final修饰的方法,能被子类继承使用,但是不能被子类重写
3) final修饰变量 : 这个变量只能手动赋值一次, 变量值再不可修改;
使用final修饰的变量称为 常量, 命名规则 : 全大写,多个英文单词之间使用_进行分隔
a : final修饰基本数据类型变量, 这个变量的值不可修改
b : final修饰的引用数据类型变量, 变量的地址值不能修改, 但是地址中的数据可以改变
c : final修饰成员变量, 需要在创建对象完成之前给final变量进行赋值
1) 定义final成员直接赋值
2) 可以在构造中,以及构造之前进行赋值
final修饰类代码:
// 定义出一个使用final修饰类, 名字FinalClass public final class FinalClass { int i = 10; public void fun() { System.out.println("-------------"); } }
//The type FinalClassZi cannot subclass the final class FinalClass // FinalClassZi 无法成为一个使用final关键字修饰的类的子类 public class FinalClassZi extends FinalClass { }
public class TestFinal { public static void main(String[] args) { // 1. 使用final修饰的类不能作为父类,但是可以正常使用 FinalClass fc = new FinalClass(); System.out.println(fc.i);// 10 fc.fun(); // ------------- } }
Final修饰方法代码
public class FinalMethod { public final int getSum(int x, int y) { return x + y; } }
public class FinalMethodZi extends FinalMethod { // FinalMethodZi继承了父类中的final方法getSum // Cannot override the final method from FinalMethod // 使用final修饰的方法不能重写 /*@Override public final int getSum(int x, int y) { return x + y; }*/ }
public class TestFinal { public static void main(String[] args) { // 2. 使用final修饰的方法,不能被子类重写, 但是可以正常继承和使用 FinalMethodZi fmz = new FinalMethodZi(); System.out.println(fmz.getSum(3, 5)); } }
final修饰变量
public class FinalVariable { final static String SCHOOL_NAME = "第一中学"; // The blank final field j may not have been initialized final static int j; static { j = 99; } // 4. final修饰成员变量 : 赋值机制, 创建对象完成之前必须手动赋值完毕 /*public FinalVariable() { j = 25; } */ public static void main(String[] args) { final int i = 10; // 1. 报错 : 使用final修饰的变量i, 值不能修改 // i = 20; System.out.println(FinalVariable.SCHOOL_NAME); // 2. 报错 : 使用final修饰的变量SCHOOL_NAME, 值不能修改 // FinalVariable.SCHOOL_NAME = "一中"; final FinalClass fc = new FinalClass(); // 3. final修饰引用数据类型: 不可改变的是这个引用对应的内存地址, 这个地址中的数据可以改变 // fc = new FinalClass(); fc.i = 99; System.out.println(fc.i);// 99 } }