Java中的方法和变量在承继时的笼罩成绩
想必你已经浏览了一两本这样的Java书籍,它们在扫尾都指出了面向对象编程的3个次要概念:封装、承继和多态。理解这3个概念对于领会Java 言语来说至关重要,而搞懂方法的笼罩又是理解承继概念的要害局部。
这个例子摘自 Java 言语规范
01: class Super 02: { 03: static String greeting() 04: { 05: return "Goodnight"; 06: } 07: 08: String name() 09: { 10: return "Richard"; 11: } 12: } 01: class Sub extends Super 02: { 03: static String greeting() 04: { 05: return "Hello"; 06: } 07: 08: String name() 09: { 10: return "Dick"; 11: } 12: } 01: class Test 02: { 03: public static void main(String[] args) 04: { 05: Super s = new Sub(); 06: System.out.println(s.greeting() + ", " + s.name()); 07: } 08: }
运转 Test 类的后果如下
Goodnight, Dick
要是你得出了异样的输出后果,那么你或者对方法的笼罩有了较好的理解,假设你的后果和答案不分歧,那就让咱们一同找出缘由,咱们先剖析一下各个类:Super类由方法 greeting和name组成,Sub 类承继了 Super 类,而且异样含有 greeting 和 name方法。Test 类只要一个 main方法。在 Test 类的第5 行中,咱们创建了一个 Sub 类的实例。在这里,你必须明确的是:只管变量 s的数据类型为 Super 类,然而它依旧是 Sub 类的一个实例,假设你对此有些迷惑,那么可能这样理解: 变量s 是一个被强迫转换为 Super 型的Sub 类的实例。
下一行(第 6 行)显示了s.greeting()前往的值,加上一个字符串,紧随其后的是 s.name()的前往值。要害成绩就在这里,咱们调用的到底是Super类的方法还是Sub类的方法,让咱们首先判别调用的是哪个类的name()方法,两个类中的name()方法都不是静态方法,而是实例方法,由于Sub类承继了Super类,而且有一个和它父类异样标识的name()方法,所以Sub类中的name()
方法笼罩了Super类中的name()方法,那么后面提到的变量s又是Sub 类的一个实例,这样一来 s.name()的前往值就是“Dick”了。
至此,咱们处理了成绩的一半,如今咱们需求判别被调用的greeting()方法终究是Super类的还是Sub类的。需求留意的是,两个类中的greeting()方法都是静态方法,也称为类方法。虽然理想上Sub类的greeting()方法具备相反的前往类型、相反的方法名以及相反的方法参数。但是它并不笼罩Super类的greeting()方法,因为变量s被强迫转换为Super型并且Sub类的greeting()方法没有笼罩Super类的greeting()方法,因此 s.greeting()的前往值为Goodnight。
还是很迷惑?请记住这条规则:“实例方法被笼罩,静态方法被隐藏”。
如今你能够会问“隐藏和笼罩有什么区别”你兴许还未理解这点。但是实践上咱们刚刚在这个Super/Sub 类的例子中已经解释了两者的不同。利用类的全局名可能访问被隐藏的方法,即使变量s是Sub类的一个实例,而且Sub类的greeting()方法隐藏了Super 类的同名方法,咱们依旧可以将s强迫转换为Super型以便访问被隐藏的greeting()方法,与被隐藏的方法不同,对被笼罩的方法而言,除了笼罩它们的类之外,其余任何类都无奈访问它们。这就是为何变量s调用的是Sub类的name(),而非Super类的name()方法。
兴许对你来说 理解隐藏静态方法和笼罩实例方法的区别的最佳模式,就是本人创建几个类似于Sub/Super的类,再反复一次规则,实例方法被笼罩而静态方法被隐藏,被笼罩的方法只要笼罩它们的类能力访问它们,而访问被隐藏的方法的路径是提供该方法的全局名。如今你终于明确题目里成绩的答案了吧。什么时分“被笼罩的”方法并非真地被笼罩了呢?答案就是“永远不会”。另外,还有几个要点,请谨记:
--试图用子类的静态方法隐藏父类中异样标识的实例方法是不合法的,编译器将会报错
--试图用子类的实例方法笼罩父类中异样标识的静态方法也是不合法的,编译器会报错
--静态方法和最终方法(带要害字final的方法)不能被笼罩
--实例方法可以被笼罩
--形象方法必须在详细类中被笼罩
如今咱们来看承继时变量笼罩和隐藏的成绩,假设你以为你已经理解了上面的方法承继时的笼罩和隐藏成绩,继而以为变量也如此的话,那么请持续往下看:
Java共有6种变量类型:类变量、实例变量、方法参数、结构函数参数、同样解决参数和部分变量。类变量包括在类中定义的静态数据成员以及在接口中申明的静态或非静态的数据成员。实例变量是在类体中申明的非静态变量,术语“变量成员”指的是类变量和实例变量。方法参数是用来传入方法体的。结构函数参数是用来传入结构函数的。同样解决参数用来传入一个try语句中的catch块的。最后,部分变量是在一个代码块或一个for语句中申明的变量。
class Base { int x = 1; static int y=2; int z=3; int method() { return x; }}class Subclass extends Base { int x = 4; int y=5; static int z=6; int method() { return x; }}public class Test { public static void main(String[] args) { Subclass s=new Subclass(); System.out.println(s.x + " " + s.y +" "+ s.z); System.out.println(s.method()); Base b = (Subclass)s; System.out.println(b.x + " " + b.y +" "+ b.z); System.out.println(b.method()); }}
运转可能失去输出:
4 5 6
4
1 2 3
4
由此咱们可能得出:
实例变量和类变量能被隐藏,被子类的同名变量成员隐藏。部分变量和各种参数永远不会被隐藏(参见下例)。
class Hidden { public static void main(String args[]) { int args=0; //compile error String s="abc"; int s=10; //compile error } }
如何访问被隐藏的变量呢? 利用“this”要害字可能访问被部分变量隐藏的本类中的实例变量,要害字“super”可能访问父类中被隐藏的实例变量,类变量可能用类加“.”来访问。强迫转换为父类型。
变量和方法笼罩和隐藏的不同:一个类的实例无奈经过利用全局名或许强迫本人转换为父类型,以访问父类中被隐藏的方法,但是强迫转换子类为父类型之后,可能访问父类中被隐藏的变量。另外静态方法不能笼罩父类的实例方法,而静态变量却可能隐藏父类的一个同名实例变量,异样,实例方法不能笼罩父类的同名静态方法,而变量却可能隐藏父类的同名变量成员,不论父类的这个变量成员是类变量或许是实例变量。