1.类的继承
1)继承
父类:所有子类所共有的属性和行为
子类:子类所特有的属性和行为
- 通过extends关键字来实现类的继承
- 子类(Sub class)可以继承父类(Super class)的成员变量及成员方法,同时也可以定义自己的成员变量和成员方法
- Java语言不支持多重继承,一个类只能继承一个父类(单一继承),但一个父类可以有多个子类
- 继承具有传递性,子类的子类可以继承父类的父类的成员变量及成员方法
2)继承中构造方法(super关键字)
- Java规定:构造子类之前必须先构造父类
- 子类的构造方法中必须通过super关键字调用父类的构造方法,这样可以妥善的初始化继承自父类的成员变量
- 如果子类的构造方法中没有调用父类的构造方法,Java编译器会自动的加入对父类无参构造方法的调用(如果该父类没有无参的构造方法,则会出现编译错误)
- super()调父类构造必须位于子类构造的第一句
- super指代当前对象的父类对象
super的用法:
- super.成员变量名:访问父类的成员变量
- super.方法名():调用父类的方法
- super():调用父类的构造方法
案例1:调用父类无参构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Person { String name; char gender; } public class Student extends Person { // super (); //编译错误,必须位于子类构造方法的第一句 double score; Student( double score){ super (); //编译器默认会自动加上 this .score = score; super .name = "Tom" ; } } |
案例2:调用父类有参构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class Person { String name; char gender; Person(String name, char gender){ this .name = name; this .gender = gender; } } public class Student extends Person { // super (); //编译错误,必须位于子类构造方法的第一句 double score; Student(String name, char gender, double score){ // super(); //编译错误,父类中没有无参构造 super (name,gender); //调用父类有参构造 this .score = score; super .name = "Tom" ; } } |
3)向上造型
- 一个子类的对象可以向上造型为父类的类型。即定义父类型的引用可以指向子类的对象
- 父类的引用可以指向子类的对象,但通过父类的引用只能访问父类所定义的成员,不能访问子类扩展的部分(能点出什么看引用)
案例3:向上造型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class Person { String name; char gender; Person(String name, char gender){ this .name = name; this .gender = gender; } } public class Student extends Person { double score; Student(String name, char gender, double score){ super (name,gender); //调用父类有参构造 this .score = score; super .name = "Tom" ; } public static void main(String[] args) { Person p = new Student( "Tom" , '男' , 80 ); //向上造型 p.score = 100 ; //编译错误,Java编译器会根据引用的类型(Person),而不是对象的类型(Student)来检查调用的方法是否匹配。 } } |
2.方法的重写(Override)
- 发生在父子类中,方法签名相同,方法体不同:子类可以重写(覆盖)继承自父类的方法,即方法名和参数列表与父类的方法相同,但方法的实现不同(方法体不同)
- 重写方法被调用时,看对象的类型:当子类对象的重写方法被调用时(无论是通过子类的引用调用还是通过父类的引用调用),运行的是子类的重写后的版本
- 子类在重写父类的方法时,可以通过super关键字调用父类的版本,这样的语法通常用于子类的重写方法在父类方法的基础之上进行功能扩展。
1).重写原则
重写遵循“两同两小一大”原则:
1)两同:
1.1)方法名相同
1.2)参数列表相同
2)两小:
2.1)子类方法的返回值类型要小于或等于父类
2.1.1)void时,必须相同
2.1.2)基本数据类型时,必须相同
2.1.3)引用类型时,小于或等于
2.2)子类方法抛出的异常要小于或等于父类的----异常之后
3)一大:
3.1)子类方法的访问权限要大于或等于父类的----访问控制修饰符之后
1 2 3 4 5 6 7 8 9 10 11 12 | class Aoo{ void show(){} double test(){ return 0.0 ;} Boo sayHi(){ return null ;} public Aoo say(){ return null ;} } class Boo extends Aoo{ //int show(){return 1;} //编译错误,void时必须相同 //int test(){return 0;} //编译错误,基本类型时必须相同 //Aoo sayHi(){return null;} //编译错误,引用类型必须小于或等于 public Boo say(){ return null ;} } |
案例4:方法重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class Student { public static void main(String[] args) { Goo o = new Goo(); o.f(); Foo oo = new Goo(); oo.f(); } } class Foo{ public void f(){ System.out.println( "Foo.f()" ); } } class Goo extends Foo{ public void f(){ System.out.println( "Goo.f()" ); } } //当子类对象的重写方法被调用时(无论通过子类的引用还是通过父类的引用),运行的都是子类重写后的方法。 /* 运行结果: Goo.f() Goo.f() */ |
案例5:方法重写,super调用父类版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public class Student { public static void main(String[] args) { Goo o = new Goo(); o.f(); Foo oo = new Goo(); oo.f(); } } class Foo{ public void f(){ System.out.println( "Foo.f()" ); } } class Goo extends Foo{ public void f(){ super .f(); //调用父类的方法 System.out.println( "Goo.f()" ); } } //子类重写方法中的super.f(); 调用了父类的版本,这样的语法通常用于子类的重写方法再父类方法的基础之上进行功能扩展。 /* 运行结果: Foo.f() Goo.f() Foo.f() Goo.f() */ |
2)重写和重载的区别
- 重写(Override):1.发生在父子类中,(方法签名相同)方法名称相同,参数列表相同,方法体不同 2.遵循“运行期”绑定,重写方法被调用时,看对象的类型
- 重载(Overload):1.发生在同一类中,方法名称相同,参数列表不同,方法体不同 2.遵循“编译期”绑定,看引用的类型绑定方法
案例6:重写与重载区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class OverrideAndOverload { public static void main(String[] args){ Super obj = new Sub(); //向上造型 Goo goo = new Goo(); goo.g(obj); } } class Super{ public void f(){ System.out.println( "super.f()" ); } } class Sub extends Super{ public void f(){ //方法重写 System.out.println( "sub.f()" ); } } class Goo{ public void g(Super obj){ System.out.println( "g(Super)" ); obj.f(); } public void g(Sub obj){ //方法重载 System.out.println( "g(Sub)" ); obj.f(); } } |
以上代码运行结果:
1 2 | g(Super) sub.f() |
All is well~
</div>