上次看了这篇文章,原文地址:
JAVA面试题解惑系列(三)——变量(属性)的覆盖
这篇文章给出了很好的解疑方法,我也是跟着他来。。。下面我的文章将讲到:java中成员变量和方法的覆盖问题
对那篇文章中的提到的变量覆盖,我不同意。因此,在这里首先提出我的观点:
当子类继承父类的成员变量或方法同名时,
同名静态方法被隐藏,同名实例方法被覆盖;可见同名成员变量均被隐藏;同名不可见方法和成员变量不存在覆盖或隐藏问题,因为不可见。
首先来解释下隐藏和覆盖的区别:隐藏是指在某种情况下仍可恢复,而覆盖则是指永远不可恢复。下面再来分别解释这三句话:
1、同名静态方法被隐藏,同名实例方法被覆盖
我们先看这段程序代码:
class ParentMethord{
// 静态方法
static void getClassName(){
System.out.println("static: "+ParentMethord.class.getName());
}
// 实例方法
void getName(){
System.out.println(ParentMethord.class.getName());
}
}
public class SubMethord extends ParentMethord{
// 重写父类静态方法
static void getClassName(){
System.out.println("static: "+SubMethord.class.getName());
}
// 重写父类实例方法
void getName(){
System.out.println(SubMethord.class.getName());
}
public static void main(String args[]){
ParentMethord parent= new SubMethord();
SubMethord sub=(SubMethord)parent;
parent.getClassName(); // 静态方法调用的仍然是父类的方法
parent.getName(); // 实例方法调用的是子类的方法
System.out.println();
sub.getClassName(); // 子类中调用的当然是子类的方法
sub.getName();
}
}
运行的结果为:
static: ParentMethord
SubMethord
static: SubMethord
SubMethord
从这里可以看出当把一个子类对象自动转型为父类对象(ParentMethord parent= new SubMethord(); )时,同名静态的方法只是被隐藏起来了,转型为父类后仍然可以调用;而同名实例方法是被覆盖,转型后调用的也是子类的方法,即方法的重写。
2、同名成员变量均被隐藏
下面来讨论这一点。这里所说的成员变量包括静态成员变量和实例成员变量,(包括final型的),当然均是指父类中对子类可见的变量。
看代码:
class Parent{
static String staticStr="父类静态变量";
String str="父类实例变量";
}
public class SubVariable extends Parent{
static String staticStr="子类静态变量";
String str="子类实例变量";
public static void main(String args[]){
Parent parent= new SubVariable();
SubVariable sub = (SubVariable)parent;
System.out.println(parent.staticStr);
System.out.println(parent.str);
System.out.println();
System.out.println(sub.staticStr);
System.out.println(sub.str);
}
}
运行结果为:
父类静态变量
父类实例变量
子类静态变量
子类实例变量
由此可见成员变量均只是被隐藏,当自动转型为父类时,仍然可见。final型的也一样,这里就不再讨论。
插入: 在这里还想扯到一个话题,以前总听胡总告诫:不要直接用点来访问对象成员变量,而用方法来访问。从这里有所体会。因为子类对象和父类对象成员变量如果出现重名 ,当把一个子类对象当作父类使用时,访问的是父类对象的那个成员变量,就会出现数据的不一致;而用方法来方法问成员变量,由于方法被重写就不会出现这个问题。可以看如下代码:
class Parent{
static String staticStr="父类静态变量";
String str="父类实例变量";
public static String getStaticStr() {
return staticStr;
}
public String getStr() {
return str;
}
}
public class SubVariable extends Parent{
static String staticStr="子类静态变量";
String str="子类实例变量";
public static String getStaticStr() {
return staticStr;
}
public String getStr() {
return str;
}
public static void main(String args[]){
Parent parent= new SubVariable();
SubVariable sub = (SubVariable)parent;
// 方法调用
System.out.println(parent.getStaticStr());
System.out.println(parent.getStr());
System.out.println();
System.out.println(sub.getStaticStr());
System.out.println(sub.getStr());
}
}
运行的结果为:
父类静态变量
子类实例变量
子类静态变量
子类实例变量
这里看出,当用实例方法访问实例成员变量时,不会出现数据的不一致;当然静态方法访问静态成员变量仍然会出现数据的不一致,因为静态方法不会被重写。
3、同名不可见方法和成员变量不存在覆盖或隐藏问题
这一点讨论的实际上是变量的修饰符问题。如果父类同名成员或方法对子类可见,即可符合前面两句话;如果父类成员或方法对子类不可见的话,既然看不到,其实就不存在同名问题。如果子类硬要访问父类中不可见成员变量或方法,就会出现非法,编译报错。所以大可不必去深究同名成员变量或方法的修饰符问题,而只是可见和不可见的问题。
对java中同名成员变量和方法的覆盖和隐藏问题就讨论到这里。欢迎大家发表自己的观点!