四、继承中与构造器相关
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 方法无法生成重写方法。