继承:体现事物的共性功能
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可,通过extends关键字可以实现类与类的继承。单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。
语法:class 子类名 extends 父类名 {}
继承的好处
1.提高了代码的复用性。
2.一处修改多处使用提高了代码的可维护性。
3.让类与类之间产生了关系,是多态的前提。
4.增加了类的耦合性
继承的弊端
软件的开发设计遵守的原则是高内聚,低耦合。
内聚是从模块自身角度来审视模块的独立性。
如果模块内部相关性很高且都是围绕同一个功能,则该模块内聚程度高;反之则内聚程度低。
耦合指的是对象之间的依赖性。
对象之间的耦合越高,维护成本越高,因此对象的设计应使类之间的耦合最小。
观察者模式:观察者模式存在的意义就是「解耦」,它使观察者和被观察者的逻辑不再搅在一起,而是彼此独立、互不依赖。比如网易新闻的夜间模式,当用户切换成夜间模式之后,被观察者会通知所有的观察者「设置改变了,大家快蒙上遮罩吧」。QQ消息推送来了之后,既要在通知栏上弹个推送,又要在桌面上标个小红点,也是观察者与被观察者的巧妙配合。
观察者模式:
A:让类的耦合性增强,父类的改变,可能会影响其他和该类相关的类。
B:打破了封装性
单继承&&多层继承
Java只支持单继承,不支持多继承。
一个类只能有一个父类,不可以有多个父类,但是可以有爷爷类。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error
Java支持多层继承(继承体系)
class A{}
class B extends A{}
class C extends B{}
继承的注意事项
☆子类可继承父类非私有成员方法和成员变量
其实这也体现了继承的另一个弊端:打破了封装性。
子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
我们到底在什么时候使用继承呢?
不要为了部分功能而去继承,继承中类之间体现的是:”is a”的关系。
比如: dog is a animal.
继承中成员变量的关系
子类和父类中同名和不同名的成员变量
package study;
/*
类的组成:
成员变量:
构造方法:
成员方法:
而现在我们又讲解了继承,所以,我们就应该来考虑一下,类的组成部分的各自关系。
继承中成员变量的关系:
A:子类中的成员变量和父类中的成员变量名称不一样,这个太简单。
B:子类中的成员变量和父类中的成员变量名称一样,这个怎么玩呢?
在子类方法中访问一个变量的查找顺序:
a:在子类方法的局部范围找,有就使用
b:在子类的成员范围找,有就使用
c:在父类的成员范围找,有就使用
d:如果还找不到,就报错。
*/
public class Father {
public int num = 10;
private int num3 = 40;
public void method() {
int num = 50;
}
}
class Son extends Father {
public int num2 = 20;
public int num = 30;
public void show() {
//int num = 40;
System.out.println(num);
System.out.println(num2);
//have private access
//System.out.println(num3);
}
}
class ExtendsDemo4 {
public static void main(String[] args) {
//创建对象
Son s = new Son();
s.show();
}
}
输出:
30
20
在子类方法中访问一个变量
首先在子类局部范围找
然后在子类成员范围找
最后在父类成员范围找(肯定不能访问到父类局部范围)
如果还是没有就报错。(不考虑父亲的父亲的话…)
super 关键字
/*
问题是:
我不仅仅要输出局部范围的num,还要输出本类成员范围的num。怎么办呢?
我还想要输出父类成员范围的num。怎么办呢?
如果有一个东西和this相似,但是可以直接访问父类的数据就好了。
恭喜你,这个关键字是存在的:super。
this和super的区别?
分别是什么呢?
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)
怎么用呢?
A:调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
B:调用构造方法
this(...) 调用本类的构造方法
super(...) 调用父类的构造方法
C:调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
*/
class Father {
public int num = 10;
}
class Son extends Father {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);
//this调用的是成员变量
System.out.println(this.num);
//super调用的是父类成员变量
System.out.println(super.num);
}
}
class ExtendsDemo5 {
public static void main(String[] args) {
Son s = new Son();
s.show();
}
}
输出:
30
20
10
this和super关键字
含义
this:代表当前类对象的引用
super:代表父类存储空间的标识,可以理解为父类的引用,通过这个东西可以访问父类的成员
成员变量
this.成员变量
super.成员变量
构造方法
this(…);
super(…);
成员方法
this.成员方法
super.成员方法
super和this
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用)
super和this的用法
this.成员变量
super.成员变量
super和this访问构造方法
this(…)
super(…)
super和this访问成员方法
this.成员方法()
super.成员方法()
继承中构造方法的关系
package study.extend;
/*
1.父类没有显式声明无参构造方法,此时父类也是有默认的无参构造方法
子类初始化时,不用显式调用super()方法,默认会调用super();
2.父类显示声明了无参构造方法
子类初始化时,不用显式调用super()方法,默认会调用super();
3.父类存在有参构造方法,没有无参构造方法,子类没有显式调用父类无参构造方法。那么子类的构造方法会出现什么现象呢?
1.显式调用父类有参构造方法,编译通过。
2.编译报错:there is no default constructor available in study.extend.Father
如何解决呢?
A:在父类中加一个无参构造方法
B:通过使用super关键字去显示的调用父类的带参构造方法
C:子类通过this去调用本类的其他构造方法
其他构造方法必须访问了父类的构造方法,否则父类数据就没有初始化。
注意事项:
this(...)或者super(...)显式调用时 必须出现在第一条语句上。
如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。
报错 call to super() must be first statement in constructor body
*/
class Father {
public Father() {
System.out.println("Father的无参构造方法");
}
public Father(String name) {
System.out.println("Father的带参构造方法");
}
}
class Son extends Father {
public Son() {
System.out.println("Son的无参构造方法");
//报错 call to super() must be first statement in constructor body
//super("随便给");
}
public Son(String name) {
// 1.显式调用父类的无参构造方法
// super("随便给");
//2.子类通过this去调用本类的其他构造方法,子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。
this();
System.out.println("Son的带参构造方法");
//报错 call to super() must be first statement in constructor body
//this("随便给");
}
}
public class ExtendsDemo7 {
public static void main(String[] args) {
Son s = new Son();
System.out.println("----------------");
Son ss = new Son("林青霞");
}
}
为什么子类中所有的构造方法默认都会访问父类中无参构造方法呢?
因为子类会继承父类。
子类可能会使用父类的数据。
所以,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:super();
子类实例化时,默认调用父类的无参构造方法,再调用子类的有参/无参构造器。
不管子类的构造器有没有参数,子类只是继承的是父类的属性和方法。
只需要调用父类的无参构造器就可以继承父类的属性和方法,因此就不需要调用父类的有参构造器。
如果父类中没有无参构造方法,该怎么办呢?
–子类通过super去显示调用父类其他的带参的构造方法
–子类通过this去调用本类的其他构造方法,这个构造方法也必须首先访问了父类构造
一定要注意:
super(…)或者this(….)显式调用时必须出现在第一条语句上否则就会报错,因为父类数据会被多次初始化。
继承中成员方法的关系
通过子类对象去访问一个方法。
首先在子类中找
然后在父类中找
如果还是没有就报错。(不考虑父亲的父亲话…)
package study.extend;
/*
继承中成员方法的关系:
A:子类中的方法和父类中的方法声明不一样,这个太简单。
B:子类中的方法和父类中的方法声明一样,这个该怎么玩呢?
通过子类对象调用方法:
a:先找子类中,看有没有这个方法,有就使用
b:再看父类中,有没有这个方法,有就使用
c:如果没有就报错。
*/
class Father {
public void fucntion() {
System.out.println("show Father");
}
}
class Son extends Father {
public void method() {
System.out.println("method Son");
}
public void show() {
System.out.println("show Son");
}
}
public class ExtendsDemo8 {
public static void main(String[] args) {
//创建对象
Son s = new Son();
s.show();
s.method();
//s.fucntion();
//找不到符号,因为这是父类的方法,父类的方法必须左边声明的是父类才能调用
}
}
输出:
show Son
method Son