继承中构造方法

继承中构造方法

子类中所有的构造方法默认都会访问父类中空参数的构造方法,子类每一个构造方法的第一条语句默认都是:super();。因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。

父类有无参构造

class Father {
    int age;

    public Father() {
        System.out.println("Father的无参构造方法");
    }

    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}

class Son extends Father {
    public Son() {
        // super();
        System.out.println("Son的无参构造方法");
    }

    public Son(String name) {
        // super(name);
        System.out.println("Son的带参构造方法");
    }
}

class ExtendsDemo3 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        System.out.println("------------");
        Son s2 = new Son("林青霞");
    }
}

输出:
Father的无参构造方法
Son的无参构造方法
------------
Father的无参构造方法
Son的带参构造方法

如果代码20行注释放开,打印“Father的带参构造方法”。不指定父类构造方法时,默认使用父类空参数的构造方法 super(); 。

默认都会访问父类中空参数的构造方法。

注:如果类只有无参构造方法,那类的属性怎么赋值?

实例化类对象时,如果只有无参构造方法,类的属性会被赋默认值。(不管程序有没有显式的初始化,Java 虚拟机都会先自动给它初始化为默认值。)

  1. Boolean默认 false
  2. 整数类型(byte、short、int、long)的基本类型变量的默认值为0
  3. 单精度浮点型(float)的基本类型变量的默认值为0.0f
  4. 双精度浮点型(double)的基本类型变量的默认值为0.0d
  5. 字符型(char)的基本类型变量的默认为 /u0000
  6. 引用类型的变量是默认值为 null
  7. 数组引用类型的变量的默认值为 null。当数组变量的实例后,如果没有显式的为每个元素赋值,Java 就会把该数组的所有元素初始化为其相应类型的默认值。

父类无无参构造

如果父类没有无参构造方法,那么子类的构造方法就会报错。

class Father {
    /* 方法一:父类提供无参构造
    public Father() {
        System.out.println("Father的无参构造方法");
    }
    */

    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}

class Son extends Father {
    public Son() {
        // 方法三:子类通过this去调用本类的其他构造方法
        this("任意");
        System.out.println("Son的无参构造方法");
    }

    public Son(String name) {
        // 方法二:子类使用super关键字去显示的调用父类的带参构造方法
        super(name);
        System.out.println("Son的带参构造方法");
    }
}

class ExtendsDemo3 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        System.out.println("------------");
        Son s2 = new Son("lili");
    }
}

解决方案:

  • 父类提供无参构造方法
  • 子类使用super关键字去显示的调用父类的带参构造方法
  • 子类通过this去调用本类的其他构造方法

总之,子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。

子类重写父类构造方法

如果子类重写了父类的有参构造方法,就必须重写父类的无参构造方法。

class Father {
    public Father() {
        System.out.println("Father的无参构造方法");
    }

    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}

class Son extends Father {
    /*
    public Son() {
    }
    */

    public Son(String name) {
        super(name);
        System.out.println("Son的带参构造方法");
    }
}

class ExtendsDemo3 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        System.out.println("------------");
        Son s2 = new Son("lili");
    }
}

报错:27行报错无法找到对应的构造方法。
解决方法:Son子类编写空的无参构造方法,默认去调用父类空参数构造方法。

子类重写父类成员方法

class Phone {
    public void call(String name) {
        System.out.println("给"+name+"打电话");
    }
}

class NewPhone extends Phone {
    public void call(String name) {
        super.call(name);
        System.out.println("可以听天气预报了");
    }
}

class ExtendsDemo3 {
    public static void main(String[] args) {
        NewPhone np = new NewPhone();
        np.call("jack");
    }
}

输出:
给jack打电话
可以听天气预报了

当子类需要父类的功能,而子类有自己特有内容时,可以重写父类中的方法。继承重写父类方法,即沿袭了父类的功能,又定义了子类特有的内容。

继承中代码块

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");
    }
}

class ExtendsTest2 {
    public static void main(String[] args) {
        Zi z = new Zi();
    }
}

输出
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi

1、子类初始化之前先会进行父类的初始化
2、静态的内容是随着类的加载而加载,静态代码块的内容会优先执行

继承中分层初始化

class Y {
    Y() {
        System.out.println("Y");
    }
}

class X {
    Y b = new Y();
    static {
        System.out.println("X 静态代码块");
    }
    {
        System.out.println("X 构造代码块");
    }

    X() {
        System.out.println("X");
    }
}

public class Z extends X {
    Y y = new Y();
    static {
        System.out.println("Z 静态代码块");
    }

    Z() {
        //super()
        System.out.println("Z");
    }
    public static void main(String[] args) {
        new Z();
    }
}

输出:
X 静态代码块
Z 静态代码块
Y
X 构造代码块
X
Y
Z

1、分层初始化:先进行父类初始化,然后进行子类初始化。
2、类的初始化顺序:
父类–静态变量
父类–静态初始化块
子类–静态变量
子类–静态初始化块
子类main方法
父类–属性对象、变量 (执行顺序看代码位置由上到下)
父类–构造代码块
父类–构造函数
子类–属性对象、变量 (执行顺序看代码位置由上到下)
子类–构造代码块
子类–构造函数

总之,静态优先执行,属性优先执行。

注:
构造代码块属性对象、变量执行顺序代码位置

上述代码将属性对象Y y = new Y(); 放在构造代码块下面。Y y = new Y(); 放在构造方法下面。

class Y {
    Y() {
        System.out.println("Y");
    }
}

class X {
    static {
        System.out.println("X 静态代码块");
    }
    {
        System.out.println("X 构造代码块");
    }

    /* 属性对象放在构造代码块下面*/
    Y y = new Y();

    X() {
        System.out.println("X");
    }
}

public class Z extends X {
    static {
        System.out.println("Z 静态代码块");
    }

    Z() {
        //super()
        System.out.println("Z");
    }
    
    /* 属性对象放在构造方法下面*/
    Y b = new Y();
    
    public static void main(String[] args) {
        new Z();
    }
}

输出:
X 静态代码块
Z 静态代码块
X 构造代码块
Y
X
Y
Z

结果可见:
1、构造代码块和属性对象、变量的执行顺序看 代码位置
2、属性对象、变量的执行 优先 构造方法

构造方法特征

  1. 构造方法的名称必须与类名相同。
  2. 构造方法可以带参数。
  3. 构造方法没有返回值,返回类型不是void。如果在构造函数前面写上void ,那么构造函数就变成无效的了。
  4. 构造方法不能在方法中用 return 语句返回一个值。
  5. 当自定义了构造方法后,编译器将不再自动创建不带参数的构造方法 。
  6. 构造方法访问修饰符和其他方法一样,可以是public protected default private,访问范围也和其他方法一样。比如,protected修饰,其他包访问需要继承;default修饰,只能本包访问。
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会叫的狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值