一、继承
1.格式:class 子类 extends 父类
2.好处:提高代码的复用性;让类与类之间产生了关系,是多态的前提。
3.弊端:
(1)类的耦合性增强了,而开发的原则是高内聚,低耦合。内聚是指类独立完成某件事的能力,耦合指类和类产生关系。
(2)打破了封装性(子类继承了父类所有非私有成员)
4.特点
(1)Java只支持单继承,不支持多继承,即类只能有一个直接的父类。
(2)Java支持多层继承(继承体系)
5.注意事项
(1)子类只能继承父类所有非私有的成员
(2)子类不能继承父类的构造方法,但子类的构造方法中通过super()去访问了父类的构造方法
(3)不要为了部分的功能去使用继承,继承体现的是" is a "的关系,使用继承的类必须是所属关系。
6.super关键字
(1)含义:代表父类存储空间的标识,可以理解为对父类的引用,可以操作父类的成员,用法和this类似。
(2)super()用法:调用父类的无参数的构造方法
A:子类所有构造方法的第一行,都隐含一条语句super(); ,所以子类初始化之前会进行父类的初始化
B:如果父类没有无参数构造方法,子类的构造方法会报错
解决办法:a:在父类中加一个无参数构造方法(推荐在开发时尽量这么做)
b:在子类构造方法的第一行中显式的使用super去调用父类的带参构造方法
c:子类通过this去调用本类的其他构造方法
子类中一定要有一个去访问了父类的构造方法,否则父类数据没有初始化
C:在构造器中,注意this(形参列表)和super(形参列表)一定要定义第一行,因为是调用用于初始化的构织函数。
D:在构造器内部,this(形参列表)和super(形参列表)只能出现一个,因为只有一个“第一行”!
(3)子父类的初始化(分层初始化):先进行父类的初始化,再进行子类的初始化
A:注意:子类构造方法中的super()仅仅代表要先初始化父类的数据,在初始化子类的数据,而不是按照上下文顺序依次执行到super()。
B:面试题:看程序写结果
class X{
Y b = new Y();
X(){
System.out.println("X");
}
}
class Y{
Y(){
System.out.println("Y");
}
}
class Z extends X{
Y y = new Y();
Z(){
super();
System.out.println("Z");
}
public void static main(String[] args){
new Z();
}
}
结果是:YXYZ,而不是YYXZ,原因参考A。
7.成员方法的重写
(1)概述:子类中出现了和父类一样的方法声明,也被称为方法覆盖,方法覆写。
(2)好处:当子类需要父类的功能,而子类有自己特有的内容时,可以重写父类的方法。
(3)注意事项
A:父类中的私有成员方法不能被重写,因为父类私有方法不能被继承
B:子类重写父类方法时,访问权限不能更低,即修饰符不能小于父类,最好一致
C:父类静态方法,子类也必须通过静态方法进行重写。(其实算不上方法重写,见多态)
D:若父类方法抛异常,那么子类方法的异常类型不能大于父类的
(4)方法重载和方法重写的区别
Overload重载:同一个类中,出现的方法名相同,参数列表不同的现象。注意,方法重载能改变返回值的类型,因为它和返回值类型无关。
Override重写:子类中,出现和父类中一摸一样的方法声明的现象。
8.final关键字
(1)概述:是一个修饰符,可以修饰类、方法、变量
(2)特点:
A:被final修饰的类是一个最终类,不能被继承
B:被final修饰的方法是一个最终方法,不能被覆盖,就阻止了父类中的方法被子类重写
C:被final修饰的变量是一个常量,只能赋值一次
(3)注意事项
final修饰局部变量,若该变量是基本类型,其值不能改变;若是引用数据类型,是其地址值不能改变。
面试题:final修饰局部变量的问题
class Student{
int age = 10;
}
class FinalTest{
public static void main(String[] args){
//局部变量是基本数据类型
int x = 10;
x = 100;
System.out.println(x);
final int y = 10;
y = 100;//报错,无法为final变量赋值
System.out.println(y);
//局部变量是引用数据类型
Student s = new Student();
System.out.println(s.age);
S.age = 100;
System.out.println(s.age);
final Student ss = new Student();
System.out.println(ss.age);
ss.age = 100;//不报错,age可以被赋值
System.out.println(ss.age);
//重新给ss分配内存空间
ss = new Student();//报错,final修饰的引用数据类型的变量不能修改其指向的内存空间
}
}