四、继承中与构造器相关

1、子类不继承父类的构造器(构造方法或者构造函数),它只是调用。

2、如果父类构造器没有参数,则在子类的构造器中不需要使用 super关键字调用父类构造器,系统会自动调用父类的无参构造器。

案例:父类,构造方法没有参数:

public class Father {
public int money=10_000_000;
private int car=2;
public static double tall=178;
protected String name="ThreePure";
public Father() {
System.out.println("父类的构造方法被调用了");
}
public Father(int a) {
System.out.println("父类的有参构造方法被调用了,传入参数为"+a);
}
}

子类,构造方法没有参数:

public class Son extends Father{
public Son() {
//此处默认super()
System.out.println("子类的构造方法被调用了");
}
public Son(int a) {
System.out.println("子类的有参构造方法被调用了,传入参数为"+a);
}
}

在子类中无参的构造方法默认调用了super()方法,不需要显性调用。如果一定要写,则必须写在子类无参构造器方法体的第一行。

main方法,用于启动程序:

public class Application {
public static void main(String[] args) {
System.out.println("-----------创建对象-----------");
Son erzi1=new Son();
#zs#System.out.println("-----------创建对象-----------");
Son erzi2=new Son(100);#fzs#
}
}

结果:

-----------创建对象-----------

父类的构造方法被调用了

子类的构造方法被调用了

3、如果子类构造器有参数,在创建一个子类对象时传入参数,那么系统也会自动调用父类的无参构造器。

main方法更改如下

public class Application {
public static void main(String[] args) {
#zs#System.out.println("-----------创建对象-----------");
Son erzi1=new Son();#fzs#
System.out.println("-----------创建对象-----------");
Son erzi2=new Son(100);
}
}

结果:

-----------创建对象-----------

父类的构造方法被调用了

子类的有参构造方法被调用了,传入参数为100

得出结论:创建子类对象时,系统会默认调用父类的无参构造器,需要显式地使用super()。

4、如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。

对子类的更改如下:

public class Son extends Father{
public Son() {
super(10);
System.out.println("子类的构造方法被调用了");
}
public Son(int a) {
super();
System.out.println("子类的有参构造方法被调用了,传入参数为"+a);
}
}

main方法更改如下:

public class Application {
public static void main(String[] args) {
System.out.println("-----------创建对象-----------");
Son erzi1=new Son();
System.out.println("-----------创建对象-----------");
Son erzi2=new Son(100);
}
}

结果:

-----------创建对象-----------

父类的有参构造方法被调用了,传入参数为10

子类的构造方法被调用了

-----------创建对象-----------

父类的构造方法被调用了

子类的有参构造方法被调用了,传入参数为100

五、super和this关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

this关键字:指向自己的引用。

父类代码

public class Father {
protected String name="ThreePure";
public void print(){
System.out.println("Father_print");
}
}

子类

public class Son extends Father{
private String name="HJB";
public Son() {
System.out.println(super.name);
System.out.println(this.name);
test1();
}
@Override
public void print(){
System.out.println("Son_print");
}
public void test1(){
//调用上面的print()方法,输出Son
print();
//Son
this.print();
//Father。调用父类的print方法
super.print();
}
}

main方法

public class Application {
public static void main(String[] args) {
System.out.println("-----------创建对象-----------");
Son erzi1=new Son();
}
}

结果:

-----------创建对象-----------

ThreePure //父类name属性

HJB

Son_print

Son_print

Father_print //父类方法

六、object类

java中,所有类都直接或者间接继承于Object类。

在IDEA中,使用快捷键Ctrl+H,能打开Hierarchy 面板,从中我们就可以知道当前类继承于哪个类以及被哪个类继承。比如我的当前Father类,继承于Object类,被Son,Daughter两个类继承。

七、重写

在子类中创建了一个与父类中名称相同、返回值类型相同、参数列表的方法相同,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(override),又称为方法覆盖、方法复写。

关于重写,详情参见【Java的重写】

八、注意事项

1、final 关键字声明类可以把类定义为不能继承的,即最终类;

public final class Father {}
public class Son extends Father{}
//报错:Cannot inherit from final 'characteristic.Father'

2、 implements 关键字是表示继承接口,接口是允许多继承的。

public interface A {
public void run();
}
public interface B {
public void show();
}
public class C implements A,B {
}

3、强烈建议在重写方法前加上 @Override 注解

父类:

public class Override1 {
private void method() {
System.out.println("Override1.method()");
}
}
//子类
public class Override2 extends Override1{
private void method() {
System.out.println("Override2.method()");
}
public void myMethod(){
method();
}
public static void main(String[] args) {
Override2 a = new Override2();
a.myMethod();
}
}

结果:编译通过

Override2.method()

这里父类的method()被设置成私有属性,private 的方法是无法被子类重写的,但是在子类中尝试覆盖method()方法,并且能编译通过和输出结果。

这是因为子类的method()并不是重写方法,而仅仅是与父类method()方法重名的方法。追其原因是因为缺少了@Override注解,java编译器以为这是一个普通的方法。在Override2 类中使用快捷键Alt+Insert快捷键插入重写方法,发现private 方法无法生成重写方法。