Java 继承中的属性隐藏与方法重写

一、变量隐藏——变量不具有多态性

Java 中的变量不遵循多态性,所以重写仅适用于方法,而不适用于变量。 并且,当子类中的实例变量与父类中的实例变量具有相同的名称时,则从引用类型中选择该实例变量。

在 Java 中,当子类中的实例变量与父类中的实例变量具有相同的名称时,子类的变量将隐藏父类的变量,即使它们的类型不同。 这种概念称为可变隐藏。
在变量隐藏中,子类隐藏继承的变量而不是替换它们,这基本上意味着子类的对象包含两个变量,而子变量则隐藏了父变量。我们可以通过 super.x 来访问父类中的变量

示例:

class Parent {
    
    String x = "Parent`s Instance Variable";
 
    public void print() {
        System.out.println(x);
    }
}
 
class Child extends Parent {
 
    String x = "Child`s Instance Variable";
 
    @Override
    public void print() {
        System.out.print(x);
 
		// 可以通过 super.x 访问父类被隐藏的变量
        System.out.print(", " + super.x + "\n");
    }
}

Parent parent = new Child();
System.out.println(parent.x)
Child child = new Child();
System.out.println(child.x)

结果:

Parent`s Instance Variable
Child`s Instance Variable

解析:

在 Java 中,当我们在Child类中使用已经用于在Parent类中定义变量的名称定义变量时,Child类的变量将隐藏父类的变量。因此当我们尝试通过持有子对象来从父对象的引用访问该变量时,将调用父类中的变量。因此我们知道实例变量是从引用类型而不是实例类型中选择的,并且多态性不适用于变量

为什么变量被设计为跟随隐藏而不是覆盖?

因为如果我们在子类中更改其类型,则变量覆盖可能会破坏从父级继承的方法。
每个子类都从其父类继承变量和方法(状态和行为)。 如果 Java 允许变量覆盖,它将破坏使用该变量的任何方法,并且由于子代已从父代继承了这些方法,因此编译器将在子类中给出错误。

二、方法重写——方法具有多态性

在方法覆盖的情况下,覆盖方法完全替换了继承的方法,因此当我们尝试通过持有子对象来从父对象的引用访问该方法时,将调用子类中的方法。我们可以通过 super.x() 来访问父类中的方法

三、super 的使用

1、子类调用被隐藏的父类的变量

此时子类中有一个和父类一样的字段(父类字段被隐藏),为了获得父类的这个字段我们就必须加上super
我们通过 super 是不能访问父类 private 修饰的变量的,因为这个只属于父类的内部成员,一个对象是不能访问它的 private 成员的。

示例:

public class A {
	
	 String nameA="A";
 
}
 
public class B extends A{
	 String nameA="B";
	
	
	public void getName() {
		System.out.println("子类"+nameA);
		System.out.println("父类"+super.nameA);
	}
	
	public static void main(String[] args) {
		B b=new B();
		b.getName();	
	}

2、子类调用被重写的父类的方法

在子类中,我们重写了父类的方法,如果我们想去调用父类的相同方法,必须要通过 super 关键字显示的指明出来。如果不明确出来,按照子类优先的原则,相当于还是再调用被重写的方法

示例:

public class A {
	
	private String nameA="A";
	
	public void getName() {
		System.out.println("父类"+nameA);
	}
	public static void main(String[] args) {
	}
	
}
 
 
public class B extends A{
	private String nameB="B";
	
	@Override
	public void getName() {
		System.out.println("子类"+nameB);
		super.getName();
	}
	
	public static void main(String[] args) {
		B b=new B();
		b.getName();	
	}
}

3、调用父类的构造方法

因为父类的构造函数不能被继承,因此编译器会自动在子类构造函数的第一句加上 super() 来调用父类的无参构造器,此时可以省略不写,如果想写上的话必须在子类构造函数的第一句可以通过 super 来调用父类其他重载的构造方法,只要相应的把参数传过去就好。
注意:子类继承父类的时候会自动继承父类的默认构造函数(也就是继承那个无参数的构造函数)。如果你的类里面已经有一个带有参数的构造函数了,而你没有写那个默认的不带参数的构造函数的话,继承的时候子类就会报错,因为系统不知道要不继承哪个构造函数,必须明确的使用super()关键字来描述。所以我们一般为了避免这种错误的发生,在有带有多个构造函数的类里面都会写一个不带参数的构造函数

示例:

public class A {
	
	private String nameA="A";
	
	public A() {
		
	}
	public A(String nameA) {
		this.nameA = nameA;
	}
	
}
 
 
public class B extends A{
	
	private String nameB="B";
	
	public B() {
		super("lhj");
	}	
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值