为什么需要继承extends
编写两个类,一个是pupil,一个是graduate,两个类有许多相似的属性,怎么办?
使用继承(代码复用)
示意图
细节
- 子类继承了所有的属性和方法,私有属性不能在子类直接访问,要通过公共的方法去访问
父类
public class Base {
private int n1 = 100;
protected int n2 = 200;
int n3 = 300;
public int n4 = 400;
}
子类(无法访问n1)
子类只能通过父类提供的公共方法来访问
public class Base {
private int n1 = 100;
protected int n2 = 200;
int n3 = 300;
public int n4 = 400;
public int getN1() {
return n1;
}
}
public class Sub extends Base{
public int getn1(){
return this.getN1();
//return this.n1;
}
public int getn2(){
return this.n2;
}
}
- 子类必须调用父类的构造器,完成父类的初始化
public class Base {
private int n1 = 100;
protected int n2 = 200;
int n3 = 300;
public int n4 = 400;
public Base() {
System.out.println("调用了父类构造器");
}
public int getN1() {
return n1;
}
}
public class Sub extends Base{
public int getn1(){
return this.getN1();
//return this.n1;
}
public Sub() {
System.out.println("调用了子类构造器");
}
public int getn2(){
return this.n2;
}
}
public class Test {
public static void main(String[] args) {
Sub sub = new Sub();
}
}
结果
调用了父类构造器
调用了子类构造器
先调用的是父类,后调用的是子类,因为在子类的构造器中默认调用super(),即默认调用父类的构造器
- 当创建子类对象的时候,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
子类
package extendsDemo;
public class Sub extends Base{
public int getn1(){
return this.getN1();
//return this.n1;
}
public Sub() {
System.out.println("调用了子类无参构造器");
}
public Sub(int n2,int n3,int n4){
this.n2 = n2;
this.n3 = n3;
this.n4 = n4;
System.out.println("调用了子类构造器,带有参数n2,n3,n4");
}
public Sub(int n2,int n3){
this.n2 = n2;
this.n3 = n3;
System.out.println("调用了子类构造器,带有参数n2,n3");
}
public int getn2(){
return this.n2;
}
}
测试
public class Test {
public static void main(String[] args) {
Sub sub = new Sub(100,300,900);
}
}
结果
调用了父类构造器
调用了子类构造器,带有参数n2,n3,n4
默认调用了父类构造器
- 若父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不通过
package extendsDemo;
public class Base {
private int n1;
protected int n2;
int n3;
public int n4;
// public Base() {
// System.out.println("调用了父类构造器");
// }
public Base(int n2, int n3, int n4) {
this.n2 = n2;
this.n3 = n3;
this.n4 = n4;
}
public Base(int n2, int n3) {
this.n2 = n2;
this.n3 = n3;
}
public int getN1() {
return n1;
}
}
将父类改成不带无参构造器,则子类会报错
必须用super()指定用父类的哪个构造器
- 如果希望指定去调用父类的某个构造器,则显示的调用一下
- super()必须放在子类构造器的第一行,super只能在构造器中使用
- super和this都只能放在构造器的第一行,因此这两个方法不能共存在一个构造器
- Java所有的类都是object类的子类
- 父类构造器的调用不限于直接父类,可以一直往上追溯到Object类(顶级父类)
将继承关系改成如下图所示
public class Top {
public Top() {
System.out.println("调用了Top构造器");
}
}
public class Base extends Top {
private int n1;
protected int n2;
int n3;
public int n4;
public Base() {
System.out.println("调用了父类构造器");
}
}
public class Sub extends Base{
public int getn1(){
return this.getN1();
//return this.n1;
}
public Sub() {
System.out.println("调用了子类无参构造器");
}
}
public class Test {
public static void main(String[] args) {
Sub sub = new Sub();
}
}
结果
调用了Top构造器
调用了父类构造器
调用了子类无参构造器
- 子类最多只能继承一个父类(直接继承),即单继承机制
- 继承不可滥用,子类和父类之间必须满足is-a的逻辑关系
student is a person
teacher is a person
继承的本质
- 加载类,object,grandpa,father,son
Son son = new Son();
System.out.println(son.name);
a. 首先看子类是否有该属性
b. 有,并且可以访问,则返回该信息
c. 没有,则看其父类有没有这个属性,有,并且可以访问,则返回该信息,没有,则继续按照c的步骤继续
所以System.out.println(son.name);
打印的是大头儿子