重写vs隐藏Java – 困惑

我很困惑如何重写不同于隐藏在Java中。 任何人都可以提供有关这些不同的更多细节? 我读了Java教程,但示例代码仍然让我感到困惑。

更清楚的是,我明白Overriding。 我的问题是,我没有看到,除了一个在实例层面,另一个在课堂层面,隐藏是不同的。

看一下Java教程代码:

public class Animal { public static void testClassMethod() { System.out.println("Class" + " method in Animal."); } public void testInstanceMethod() { System.out.println("Instance " + " method in Animal."); } } 

那么我们有一个子类猫:

 public class Cat extends Animal { public static void testClassMethod() { System.out.println("The class method" + " in Cat."); } public void testInstanceMethod() { System.out.println("The instance method" + " in Cat."); } public static void main(String[] args) { Cat myCat = new Cat(); Animal myAnimal = myCat; Animal.testClassMethod(); myAnimal.testInstanceMethod(); } } 

然后他们说:

这个程序的输出如下:

动物中的类方法。

Cat。中的实例方法

对我来说,直接从Animal类调用一个类方法testClassMethod()的事实,在Animal类中执行该方法是非常明显的,没有什么特别的。 然后,他们从myCat的引用中调用testInstanceMethod(),所以再明显的是执行的方法就是Cat实例中的方法。

从我所看到的隐藏的行为就像压倒一切,那么为什么要区分呢? 如果我使用上面的类运行这个代码:

 Cat.testClassMethod(); 

我会得到: Cat中的类方法。 但是,如果我从Cat中删除testClassMethod(),那么我将得到: Animal中的类方法。

这表明我写了一个静态方法,在父类中有相同的签名,在一个子类中几乎没有覆盖。

希望我能清楚地知道我在哪里混淆,有人可以点亮。 非常感谢!

超越基本上支持后期绑定。 因此,调用哪个方法是在运行时决定的。这是针对非静态方法的。 隐藏是所有其他成员(静态方法,实例成员,静态成员)。 它是基于早期的约束。 更清楚的是,要调用或使用的方法或成员是在编译期间决定的。

在你的例子中,第一个调用Animal.testClassMethod()是对一个static方法的调用,因此,可以确定哪个方法将被调用。

在第二次调用myAnimal.testInstanceMethod() ,它调用一个非静态方法。 这就是你所说的运行时多态。 直到运行时间才决定调用哪个方法。

为了进一步澄清,请阅读。

静态方法是隐藏的,非静态方法被覆盖。 当呼叫不合格时,差异是显着的“something()”vs“this.something()”。

我真的不能把它放在单词上,所以这里举一个例子:

 public class Animal { public static void something() { System.out.println("animal.something"); } public void eat() { System.out.println("animal.eat"); } public Animal() { // This will always call Animal.something(), since it can't be overriden, because it is static. something(); // This will call the eat() defined in overriding classes. eat(); } } public class Dog extends Animal { public static void something() { // This method merely hides Animal.something(), making it uncallable, but does not override it, or alter calls to it in any way. System.out.println("dog.something"); } public void eat() { // This method overrides eat(), and will affect calls to eat() System.out.println("dog.eat"); } public Dog() { super(); } public static void main(String[] args) { new Dog(); } } 

OUTPUT:

 animal.something dog.eat 

这是覆盖和隐藏之间的区别,

  1. 如果父类和子类中的方法都是实例方法,则称为覆盖。
  2. 如果父类和子类中的方法都是静态方法,则称为隐藏。
  3. 一种方法不能在父母中是静态的,而在儿童中则是一个实例。 反之亦然。

在这里输入图像描述

覆盖只发生在实例方法中。 当引用variables的types是Animal并且对象是Cat时,则从Cat调用实例方法(这是重写)。 对于相同的acat对象,使用Animal的类方法。

 public static void main(String[] args) { Animal acat = new Cat(); acat.testInstanceMethod(); acat.testClassMethod(); } 

输出是:

 The instance method in Cat. Class method in Animal. 

如果我正确理解你的问题,那么答案是“你已经凌驾了”。

这说明,在子类中编写一个静态方法,与父类中的名称相同,几乎可以覆盖。“

如果你在一个与超类中的方法完全相同的子类中编写一个方法,它将覆盖超类的方法。 @Override注释不需要重写一个方法。 但它确实使你的代码更具可读性,并强制编译器检查你确实是在重写一个方法(并且不会拼错子类方法)。

 public class First { public void Overriding(int i) { // will be overrided in class Second } public static void Hiding(int i) { // will be hidden in class Second // because it's static } } public class Second extends First { public void Overriding(int i) { // overrided here } public static void Hiding(int i) { // hidden // because it's static } } 

记忆的规则很简单:扩展类的方法不能把static改成void,也不能把void改成static。 这将导致编译错误。

但是,如果无效名称更改为无效命名为覆盖。

如果静态名称更改为静态名称它是隐藏。 (当编译器在超类的对象中看到静态方法时,它不检查子类中的方法。

在java中如何隐藏静态方法? 猫类正在扩展动物类。 所以在Cat类中将有两个静态方法(我的意思是Child类的静态方法和Parent类的静态方法)但是JVM如何隐藏Parent静态方法? 它如何处理堆和堆栈?

基于我最近的Java研究

  • 方法覆盖 ,当子类具有相同的方法在子类中具有相同的签名。
  • 方法隐藏 ,当子类具有相同的方法名称,但参数不同时。 在这种情况下,你不重写父方法,而是隐藏它。

来自OCP Java 7的示例,第70-71页:

 public class Point { private int xPos, yPos; public Point(int x, int y) { xPos = x; yPos = y; } public boolean equals(Point other){ .... sexy code here ...... } public static void main(String []args) { Point p1 = new Point(10, 20); Point p2 = new Point(50, 100); Point p3 = new Point(10, 20); System.out.println("p1 equals p2 is " + p1.equals(p2)); System.out.println("p1 equals p3 is " + p1.equals(p3)); //point's class equals method get invoked } } 

但是如果我们写下如下主要内容:

  public static void main(String []args) { Object p1 = new Point(10, 20); Object p2 = new Point(50, 100); Object p3 = new Point(10, 20); System.out.println("p1 equals p2 is " + p1.equals(p2)); System.out.println("p1 equals p3 is " + p1.equals(p3)); //Object's class equals method get invoked } 

在第二个主要中,我们使用Object类作为静态types,所以当我们在Point对象中调用equals方法时,它将等待一个Point类作为参数到达,但是Object将会到达。 所以Object类等于方法正在运行,因为我们在那里有一个equals(Object o)。 在这种情况下,Point的类不等于覆盖,但隐藏了Object类的equals方法

在这个代码片段中,我使用“私有”访问修饰符而不是“静态”来显示隐藏方法和重写方法之间的区别。

 class Animal { // Use 'static' or 'private' access modifiers to see how method hiding work. private void testInstancePrivateMethod(String source) { System.out.println("\tAnimal: instance Private method calling from "+source); } public void testInstanceMethodUsingPrivateMethodInside() { System.out.println("\tAnimal: instance Public method with using of Private method."); testInstancePrivateMethod( Animal.class.getSimpleName() ); } // Use default, 'protected' or 'public' access modifiers to see how method overriding work. protected void testInstanceProtectedMethod(String source) { System.out.println("\tAnimal: instance Protected method calling from "+source); } public void testInstanceMethodUsingProtectedMethodInside() { System.out.println("\tAnimal: instance Public method with using of Protected method."); testInstanceProtectedMethod( Animal.class.getSimpleName() ); } } public class Cat extends Animal { private void testInstancePrivateMethod(String source) { System.out.println("Cat: instance Private method calling from " + source ); } public void testInstanceMethodUsingPrivateMethodInside() { System.out.println("Cat: instance Public method with using of Private method."); testInstancePrivateMethod( Cat.class.getSimpleName()); System.out.println("Cat: and calling parent after:"); super.testInstanceMethodUsingPrivateMethodInside(); } protected void testInstanceProtectedMethod(String source) { System.out.println("Cat: instance Protected method calling from "+ source ); } public void testInstanceMethodUsingProtectedMethodInside() { System.out.println("Cat: instance Public method with using of Protected method."); testInstanceProtectedMethod(Cat.class.getSimpleName()); System.out.println("Cat: and calling parent after:"); super.testInstanceMethodUsingProtectedMethodInside(); } public static void main(String[] args) { Cat myCat = new Cat(); System.out.println("----- Method hiding -------"); myCat.testInstanceMethodUsingPrivateMethodInside(); System.out.println("\n----- Method overriding -------"); myCat.testInstanceMethodUsingProtectedMethodInside(); } } 

输出:

 ----- Method hiding ------- Cat: instance Public method with using of Private method. Cat: instance Private method calling from Cat Cat: and calling parent after: Animal: instance Public method with using of Private method. Animal: instance Private method calling from Animal ----- Method overriding ------- Cat: instance Public method with using of Protected method. Cat: instance Protected method calling from Cat Cat: and calling parent after: Animal: instance Public method with using of Protected method. Cat: instance Protected method calling from Animal 
 public class Parent { public static void show(){ System.out.println("Parent"); } } public class Child extends Parent{ public static void show(){ System.out.println("Child"); } } public class Main { public static void main(String[] args) { Parent parent=new Child(); parent.show(); // it will call parent show method } } // We can call static method by reference ( as shown above) or by using class name (Parent.show()) 

链接的java教程页面解释了覆盖和隐藏的概念

具有相同签名(名称,加上其参数的数量和types)的子类中的实例方法以及作为超类中的实例方法的返回types将覆盖超类的方法。

如果一个子类在超类中定义了一个与静态方法具有相同签名的静态方法,那么子类中的方法隐藏超类中的方法。

隐藏静态方法和重写实例方法之间的区别具有重要意义:

  1. 被调用的重写实例方法的版本是子类中的版本。
  2. 被调用的隐藏静态方法的版本取决于它是从超类还是子类调用。

回到你的例子:

 Animal myAnimal = myCat; /* invokes static method on Animal, expected. */ Animal.testClassMethod(); /* invokes child class instance method (non-static - it's overriding) */ myAnimal.testInstanceMethod(); 

以上声明不显示隐藏。

现在改变下面的代码来获得不同的输出:

  Animal myAnimal = myCat; /* Even though myAnimal is Cat, Animal class method is invoked instead of Cat method*/ myAnimal.testClassMethod(); /* invokes child class instance method (non-static - it's overriding) */ myAnimal.testInstanceMethod(); 

除了上面列出的例子之外,这里还有一个小样本代码来澄清隐藏和重写之间的区别:

 public class Parent { // to be hidden (static) public static String toBeHidden() { return "Parent"; } // to be overridden (non-static) public String toBeOverridden() { return "Parent"; } public void printParent() { System.out.println("to be hidden: " + toBeHidden()); System.out.println("to be overridden: " + toBeOverridden()); } } public class Child extends Parent { public static String toBeHidden() { return "Child"; } public String toBeOverridden() { return "Child"; } public void printChild() { System.out.println("to be hidden: " + toBeHidden()); System.out.println("to be overridden: " + toBeOverridden()); } } public class Main { public static void main(String[] args) { Child child = new Child(); child.printParent(); child.printChild(); } } 

child.printParent()的调用输出:
被隐藏: 父母
被覆盖:孩子

child.printChild()的调用输出:
被隐藏: 孩子
被覆盖:孩子

从上面的输出(特别是大胆标记的输出)可以看出,方法隐藏的行为与重写的行为不同。

Java允许隐藏和重写仅用于方法。 相同的规则不适用于variables。 重写variables是不允许的,所以variables只能被隐藏(静态或非静态variables之间没有区别)。 下面的例子显示了getName()方法是如何被覆盖的,而variablesname是隐藏的:

 public class Main { public static void main(String[] args) { Parent p = new Child(); System.out.println(p.name); // prints Parent (since hiding) System.out.println(p.getName()); // prints Child (since overriding) } } class Parent { String name = "Parent"; String getName() { return name; } } class Child extends Parent { String name = "Child"; String getName() { return name; } }