Java面向对象之继承
一、继承的概述和特点
1,继承的好处以及弊端
* A:继承的好处* a:提高了代码的复用性
* b:提高了代码的维护性
* c:让类与类之间产生了关系,是多态的前提
* B:继承的弊端
* 类的耦合性增强了。
2,继承的特点
* Java只支持单继承,不支持多继承。(一个儿子只能有一个爹)
* 有些语言是支持多继承,格式:extends 类1,类2,...
* Java支持多层继承(继承体系)
* 如果想用这个体系的所有功能用最底层的类创建对象
* 如果想看这个体系的共性功能,看最顶层的类
二、this和super的区别和应用
* A:this和super都代表什么
* this:代表当前对象的引用,谁来调用我,我就代表谁
* super:代表当前对象父类的引用
* B:this和super的使用区别
* a:调用成员变量
* this.成员变量 调用本类的成员变量,也可以调用父类的成员变量
* super.成员变量 调用父类的成员变量
* b:调用构造方法
* this(...) 调用本类的构造方法
* super(...) 调用父类的构造方法
* c:调用成员方法
* this.成员方法 调用本类的成员方法,也可以调用父类的方法
* 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 |
class
Demo5_Extends { public static void main( String [] args) { Son s = new Son(); } } /* * A:案例演示 * 子类中所有的构造方法默认都会访问父类中空参数的构造方法 * B:为什么呢? * 因为子类会继承父类中的数据,可能还会使用父类的数据。 * 所以,子类初始化之前,一定要先完成父类数据的初始化。 * 其实: * 每一个构造方法的第一条语句默认都是:super() Object类最顶层的父类。 */ class Father extends Object { public Father() { super (); System.out.println( "Father 的构造方法" ); } } class Son extends Father { public Son() { super (); //这是一条语句,如果不写,系统会默认加上,用来访问父类中的空参构造 System.out.println( "Son 的构造方法" ); } } |
父类只有有参构造,没有无参构造方法,可以使用this或者super关键字解决:
1
2 3 4 5 6 7 8 9 10 11 12 |
class
Son
extends
Father { public Son() { //空参构造 this ( "王五" , 25 ); //本类中的构造方法 //super("李四",24); //调用父类中的构造方法 System.out.println( "Son 空参构造" ); } public Son( String name, int age) { //有参构造 super (name,age); System.out.println( "Son 有参构造" ); } } |
注意:super(…)或者this(….)只能出现一个且必须出现在构造方法的第一条语句上。
四、继承中的面试题
例1:看程序写结果1
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 |
class
Fu{ public int num = 10 ; public Fu(){ System.out.println( "fu" ); } } class Zi extends Fu{ public int num = 20 ; public Zi(){ //super(); System.out.println( "zi" ); } public void show(){ int num = 30 ; System.out.println(num); System.out.println( this .num); System.out.println( super .num); } } class Test1_Extends { public static void main( String [] args) { Zi z = new Zi(); z.show(); } } |
结果:fu,zi,30,20,10;
例2:看程序写结果2
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
static
void
main(
String
[] args) { Zi z = new Zi(); } } class Fu { static { System.out.println( "静态代码块Fu" ); } { System.out.println( "构造代码块Fu" ); } public Fu() { System.out.println( "构造方法Fu" ); } } class Zi extends Fu { static { System.out.println( "静态代码块Zi" ); } { System.out.println( "构造代码块Zi" ); } public Zi() { System.out.println( "构造方法Zi" ); } |
解析:
1,jvm调用了main方法,main进栈
2,遇到Zi z = new Zi();会先将Fu.class和Zi.class分别加载进内存,再创建对象,当Fu.class加载进内存
父类的静态代码块会随着Fu.class一起加载,当Zi.class加载进内存,子类的静态代码块会随着Zi.class一起加载
第一个输出,静态代码块Fu,第二个输出静态代码块Zi
3,走Zi类的构造方法,因为java中是分层初始化的,先初始化父类,再初始化子类,所以先走的父类构造,但是在执行
父类构造时,发现父类有构造代码块,构造代码块是优先于构造方法执行的所以
第三个输出构造代码块Fu,第四个输出构造方法Fu
4,Fu类初始化结束,子类初始化,第五个输出的是构造代码块Zi,构造方法Zi
五、方法重写
1,概述
* A:什么是方法重写
* 重写:子父类出现了一模一样的方法(注意:返回值类型可以是子父类,这个我们学完面向对象讲)
* B:方法重写的应用:
* 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容。
* C:案例演示
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 |
class
Demo7_Phone { public static void main( String [] args) { Ios8 i = new Ios8(); i.siri(); i.call(); } } /* ios7系统 siri speak English ios8系统 siri 说中文和speak English */ class Ios7 { public void call() { System.out.println( "打电话" ); } public void siri() { System.out.println( "speak English" ); } } class Ios8 extends Ios7 { public void siri() { super .siri(); System.out.println( "说中文" ); } } |
2,方法重写注意事项
* a:父类中私有方法不能被重写
* 因为父类私有方法子类根本就无法继承
* b:子类重写父类方法时,访问权限不能更低
* 最好就一致
* c:父类静态方法,子类也必须通过静态方法进行重写
* 其实这个算不上方法重写(静态只能覆盖静态)
3,Override和Overload的区别
* overload可以改变返回值类型,只看参数列表
* 方法重写:子类中出现了和父类中方法声明一模一样的方法。与返回值类型有关,返回值是一致(或者是子父类)的
* 方法重载:本类中出现的方法名一样,参数列表不同的方法。与返回值类型无关。
* 子类对象调用方法的时候:先找子类本身,再找父类。
六、final关键字
1,final修饰特点
* 修饰类,类不能被继承
* 修饰变量,变量就变成了常量,只能被赋值一次
* 修饰方法,方法不能被重写
如果修饰局部变量
* 基本类型,是值不能被改变
* 引用类型,是地址值不能被改变,对象中的属性可以改变
2,final修饰变量的初始化时机
* 显示初始化
* 在对象构造完毕前即可
演示:
1
2 3 4 5 6 7 8 9 10 |
class
Demo { final int num; //成员变量的默认初始化值是无效值 //final int num=10; //成员变量的默认初始化值是无效值 public Demo() { num = 10 ; //也可以在构造方法中,在对象构造完毕前即可 } public void print() { System.out.println(num); } } |