目录
继承细节
第一条
父类代码
子类代码
测试代码
运行结果
第二条
第三条
第三条-1
第三条-2
第四条
一、调用父类Base的无参构造器
二、一个参数的构造器
三、两个参数的构造器
第五条
第六条
第七条
第八条
第九条
第十条
继承细节
第一条
子类继承了父类所有的属性和方法,但是私有属性不能在子类直接访问,要通过父类的public方法去访问
父类代码
package com.hspedu.entends_;
public class Base {//父类
//四个属性,四个访问修饰符
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
//父类提供一个public方法,用于在子类访问父类中的private属性
public int getN4() {
return n4;
}
//默认的无参构造器
public Base() {
System.out.println("Base()....");
}
//四个方法,访问修饰符对应四个属性
public void test100(){
System.out.println("test100");
}
protected void test200(){
System.out.println("test200");
}
void test300(){
System.out.println("test300");
}
private void test400(){
System.out.println("test400");
}
//父类提供一个public方法,用于在子类访问父类中的private方法
public void callTest400(){
test400();
}
}
子类代码
package com.hspedu.entends_;
public class Sub extends Base{
//子类独有的两个方法
public Sub() {
System.out.println("Sub()....");
}
public void sayOk(){
//除了private属性和方法之外都可以访问
System.out.println("n1=" + n1 + " n2=" + n2 + " n3=" + n3);
test100();
test200();
test300();
//通过父类的public方法访问private属性和方法
System.out.println("n4=" + getN4());
callTest400();
}
}
在子类Sub类中不能直接访问父类Base中的private修饰的属性和方法(n4和方法test400())
解决办法:在父类中创建public方法,然后在子类中调用该方法
eg1:在Base中创建 getN4()
在Sub中调用
eg2:在Base中创建callTest400()
在sub中调用
测试代码
package com.hspedu.entends_;
public class ExtendsDetail {
public static void main(String[] args) {
Sub sub = new Sub();
sub.sayOk();
}
}
运行结果
第二条
子类必须调用父类的构造器, 完成父类的初始化
tips:当我们在新建一个对象时,这个对象所在的类的构造器就会被调用
上述代码的运行结果
可以看到:因为我们新建了一个Sub类对象,所以子类Sub的构造器被调用,同时还会首先调用子类Sub的父类Base的构造器(语法:super())
第三条
第三条-1
当创建子类对象时, 不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器
eg:
子类
package com.hspedu.entends_;
public class Sub extends Base{
public Sub() {
System.out.println("子类Sub()构造器被调用....");
}
//当创建子类对象时, 不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器
public Sub(String name) {
System.out.println("子类Sub()构造器被调用....");
}
父类
package com.hspedu.entends_;
public class Base {//父类
public Base() {
System.out.println("父类Base()构造器被调用....");
}
运行测试
package com.hspedu.entends_;
public class ExtendsDetail {
public static void main(String[] args) {
System.out.println("====创建第一个Sub对象====");
Sub sub = new Sub();
System.out.println("====创建第二个Sub对象====");
Sub sub1 = new Sub("karry");
}
}
运行结果
总结:两个Sub对象,一个调用Sub()无参构造器,一个调用Sub(String name)构造器,同时两个对象都会首先调用父类的无参构造器
第三条-2
如果父类没有提供无参构造器, 则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作, 否则, 编译不会通过
eg:
第一步:在Base中写一个有参构造器,覆盖了默认的无参构造器(此时子类中的构造器会报错)
There is no default constructor available in 'com.hspedu.entends_.Base':在父类Base中没有可用的默认构造器
第二步:解决方法,在子类Sub的构造器中指定父类Base的构造器
将super("smith", 10);和super("karry",23);传参给父类中的Base(String name, int age)构造器,这个构造器就会被调用
第三步:为了更好理解,在父类的有参构造器中输出传入的参数
运行结果
第四条
如果希望指定去调用父类的某个构造器, 则显式的调用一下 : super(参数列表),类似上述例子中的super("smith", 10);
例子:父类有三个构造器:默认的无参构造器、两个参数的构造器、一个参数的构造器
public Base() {
System.out.println("父类Base()构造器被调用....");
}
//有参构造器(两个参数的构造器)
public Base(String name, int age){
System.out.println("父类Base(String name, int age)构造器被调用...");
System.out.println("name=" + name + " age=" + age);
}
//有参构造器(一个参数的构造器)
public Base(String name){
System.out.println("父类Base(String name)构造器被调用...");
System.out.println("name=" + name);
}
在子类里依次调用这个三个构造器
一、调用父类Base的无参构造器
1).什么都不写,系统默认会调用, 2).super();
public Sub(String name,int age){
//一、调用父类Base的无参构造器,有两种方法
//1).什么都不写,系统默认会调用,2).super()
super();
System.out.println("子类Sub(String name,int age)构造器被调用");
}
结果
二、一个参数的构造器
public Sub(String name,int age){
//二、调用父类的一个参数的构造器
super("ada");
System.out.println("子类Sub(String name,int age)构造器被调用");
}
结果
三、两个参数的构造器
public Sub(String name,int age){
//三、调用父类两个参数的构造器
super("ada",37);
System.out.println("子类Sub(String name,int age)构造器被调用");
}
第五条
super 在使用时, 必须放在构造器第一行(super 只能在构造器中使用)
放在第二行时,IDEA会提示错误
Call to 'super()' must be first statement in constructor body:super()必须在构造器的第一行
原因:一定是先执行完父类的构造器,再来执行子类的构造器(先有爸爸再有儿子)
第六条
super() 和 this() 都只能放在构造器第一行, 因此这两个方法不能共存在一个构造器
第七条
java 所有类都是 Object 类的子类, Object 是所有类的基类、超类
查看一个类的层级关系 ctrl + H
第八条
父类构造器的调用不限于直接父类! 将一直往上追溯直到 Object 类(顶级父类)
继承自Object类是不用写明的,是隐藏的
构造器执行顺序 Object----->祖父类----->父类----->子类
创建一个TopBase类,让Base类继承TopBase
package com.hspedu.entends_;
public class TopBase {
public TopBase() {
System.out.println("TopBase()构造器被调用");
}
}
此时在创建新的子类Sub的对象时,会追溯到Object类的构造器(什么都不输出)
运行
第九条
子类最多只能继承一个父类(指直接继承), 即 java 中是单继承机制。
Q:如何让A同时继承B和C?
A:A继承B,B继承C
第十条
不能滥用继承, 子类和父类之间必须满足 is-a 的逻辑关系
Person is a Music? 答案是No,所以不能用继承
Cat is a Animal? 答案是Yes,所以不能用继承