1. 继承
1.1 继承的概述
继承面向对象中的一大特征
继承 : 让类与类之间发生关系(关联), 子父类关系 ; 使用extends关键字,让类与类之间具有子父类继承关系
举例 :
class A{}
class B extends A{}
上述代码:
A类被继承的类 : 称为父类, 超类, 基类
B类用于继承 : 称为子类, 派生类
1.2继承发生场景
如果同一个类别的多个事物之间, 具有共性, 将共性内容向上抽取, 抽取到一个父类中,剩下的类作为这个父类的子类 ; 父类中实现共性内容, 每一个子类只需要实现其特有的内容即可, 子类可以通过继承关系使用父类中的共性内容
注意 : 不要为了节省几个方法的设计,贸然使用继承关系; 继承关系通常都是属于关系(is a), 举例 : 猫和狗都属于动物, 因此猫和狗可以作为动物的子类
代码
public classAnimal {public voideat() {
System.out.println("动物都需要吃饭");
}public voidsleep() {
System.out.println("动物都需要睡觉");
}
}
public classCat extends Animal{public voidcatchMouse() {
System.out.println("猫能抓老鼠");
}
}
public class Dog extendsAnimal {public voidlookHome() {
System.out.println("狗可以看家");
}
}
public classTestAnimal {public static voidmain(String[] args) {//1. 创建出一个Cat对象
Cat c = newCat();
c.eat();//eat方法从父类Animal类中继承使用
c.sleep();//sleep方法从父类Animal类中继承使用
c.catchMouse();//catchMouse方法是Cat类型特有方法//2. 创建出一个Dog对象
Dog d = newDog();
d.eat();
d.sleep();
d.lookHome();
}
}
1.3 继承使用的注意事项
父类中的私有成员变量和方法, 无法被子类继承使用
私有都是使用private关键字修饰的, 私有只能在当前类型中使用, 子类不是父类类型本身, 私有因为权限使用范围,所以子类无法继承使用父类中的私有成员
父类的构造方法无法被子类继承, 但是子类可以调用父类构造
父类构造是父类类名; 子类构造是子类类名, 如果可以继承父类构造,就会发生构造名称与子类类名不一致的情况,矛盾, 因此子类不能继承父类构造
1.4 继承的特点
java中, 继承关系都是单继承, 不支持多继承,可以多层继承
单继承 : 一个子类只能有一个直接父类
不支持多继承 : 不支持一个子类同时继承多个父类
多层继承:
C类继承B类: C是B的子类
B类继承A类: B是A的子类
C类可以继承到B类,A类中的所有的可继承内容
代码
public classA {public voideat() {
System.out.println("Aeat");
}public voidfun() {
System.out.println("A玩");
}
}
public class B extendsA {public voidsleep() {
System.out.println("Bsleep");
}public voidfun() {
System.out.println("B玩");
}
}
public class C extendsB{
}
public classTestABC {public static voidmain(String[] args) {
C c= newC();
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 classFather {//1. 继承中的成员变量使用
int i = 10;int w = 20;
}
public class Son extendsFather {//1. 继承中成员变量//Son从父类中继承到变量i = 10; w = 20;
int j = 99;//子类定义出了与父类同名的成员变量w
int w = 88;public voiduseVariable() {int w = 999;
System.out.println(w);//999
System.out.println(this.w);//88//使用父类中的w变量
System.out.println(super.w);//20
}
}
public classTestFatherAndSon {public static voidmain(String[] args) {//1. 创建出一个Son子类 对象
Son son = newSon();
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 classFinalClass {int i = 10;public voidfun() {
System.out.println("-------------");
}
}
//The type FinalClassZi cannot subclass the final class FinalClass//FinalClassZi 无法成为一个使用final关键字修饰的类的子类
public class FinalClassZi extendsFinalClass {
}
public classTestFinal {public static voidmain(String[] args) {//1. 使用final修饰的类不能作为父类,但是可以正常使用
FinalClass fc = newFinalClass();
System.out.println(fc.i);//10
fc.fun(); //-------------
}
}
Final修饰方法代码
public classFinalMethod {public final int getSum(int x, inty) {return x +y;
}
}
public class FinalMethodZi extendsFinalMethod {//FinalMethodZi继承了父类中的final方法getSum//Cannot override the final method from FinalMethod//使用final修饰的方法不能重写
/*@Override
public final int getSum(int x, int y) {
return x + y;
}*/}
public classTestFinal {public static voidmain(String[] args) {//2. 使用final修饰的方法,不能被子类重写, 但是可以正常继承和使用
FinalMethodZi fmz = newFinalMethodZi();
System.out.println(fmz.getSum(3, 5));
}
}
final修饰变量
public classFinalVariable {final static String SCHOOL_NAME = "第一中学";//The blank final field j may not have been initialized
final static intj;static{
j= 99;
}//4. final修饰成员变量 : 赋值机制, 创建对象完成之前必须手动赋值完毕
/*public FinalVariable() {
j = 25;
}*/
public static voidmain(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 = newFinalClass();//3. final修饰引用数据类型: 不可改变的是这个引用对应的内存地址, 这个地址中的数据可以改变//fc = new FinalClass();
fc.i = 99;
System.out.println(fc.i);//99
}
}