developer tip

자바 오버라이드 vs 숨기기-혼동

optionbox 2020. 10. 19. 07:59
반응형

자바 오버라이드 vs 숨기기-혼동


Overriding이 Java에서 Hiding과 어떻게 다른지 혼란 스럽습니다. 누구든지 이것이 어떻게 다른지에 대한 자세한 내용을 제공 할 수 있습니까? Java Tutorial을 읽었 지만 샘플 코드가 여전히 혼란 스러웠습니다.

좀 더 명확하게, 재정의를 잘 이해합니다. 내 문제는 하나가 인스턴스 수준에 있고 다른 하나가 클래스 수준에 있다는 사실을 제외하고는 숨기기가 다르지 않다는 것입니다.

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.");
    }
}

그런 다음 하위 클래스 cat이 있습니다.

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();
    }
}

그런 다음 그들은 말합니다.

이 프로그램의 출력은 다음과 같습니다.

Animal의 클래스 방법.

Cat의 인스턴스 메서드.

나에게 Animal 클래스에서 직접 testClassMethod () 클래스 메서드를 호출하면 Animal 클래스의 메서드가 실행된다는 사실은 매우 분명하며 특별한 것은 없습니다. 그런 다음 myCat에 대한 참조에서 testInstanceMethod ()를 호출하므로 실행 된 메서드가 Cat 인스턴스에있는 메서드라는 것이 분명합니다.

호출 숨김이 재정의와 똑같이 작동하는 것을 알기 때문에 왜 그렇게 구별하십시오. 위의 클래스를 사용하여이 코드를 실행하면 :

Cat.testClassMethod();

나는 얻을 것이다 : Cat. 그러나 Cat에서 testClassMethod ()를 제거하면 다음과 같은 결과가 나타납니다 . Animal의 클래스 메서드.

이것은 부모와 동일한 서명을 가진 정적 메서드를 하위 클래스에서 거의 재정의하는 것을 보여줍니다.

내가 혼란스럽고 누군가가 빛을 발할 수있는 곳을 분명히하고 있기를 바랍니다. 미리 감사드립니다!


재정의는 기본적으로 후기 바인딩을 지원합니다. 따라서 호출 할 메서드는 런타임에 결정되며 비 정적 메서드 용입니다. 숨기기는 다른 모든 멤버 (정적 메서드, 인스턴스 멤버, 정적 멤버)를위한 것입니다. 초기 바인딩을 기반으로합니다. 보다 명확하게, 호출하거나 사용할 메서드 또는 멤버는 컴파일 시간에 결정됩니다.

귀하의 예에서 첫 번째 호출 Animal.testClassMethod()static메서드에 대한 호출 이므로 어떤 메서드가 호출 될지 확실합니다.

두 번째 호출 인 myAnimal.testInstanceMethod()에서는 비 정적 메서드를 호출합니다. 이것이 바로 런타임 다형성이라고 부르는 것입니다. 어떤 메소드를 호출할지 런타임까지 결정되지 않습니다.

자세한 내용은 이를 읽어보십시오 .


정적 메서드는 숨겨지고 비 정적 메서드는 재정의됩니다. 호출이 "something ()"대 "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();
    }

}

산출:

animal.something
dog.eat

이것이 오버라이드와 숨김의 차이점입니다.

  1. 부모 클래스와 자식 클래스의 메서드가 모두 인스턴스 메서드이면 재정의를 호출했습니다.
  2. 부모 클래스와 자식 클래스의 메서드가 모두 정적 메서드 인 경우 숨김이라고합니다.
  3. 한 메서드는 부모에서 정적이고 자식의 인스턴스로있을 수 없습니다. 그리고 그 반대의 경우도 마찬가지입니다.

여기에 이미지 설명 입력


내가 귀하의 질문을 제대로 이해했다면 대답은 "이미 무시하고 있습니다"입니다.

"부모와 동일한 이름을 가진 정적 메서드를 하위 클래스에서 작성하는 것이 거의 오버라이드를 수행한다는 것을 보여줍니다."

슈퍼 클래스의 메서드와 정확히 동일한 이름을 가진 메서드를 서브 클래스에 작성하면 슈퍼 클래스의 메서드가 재정의됩니다. 메서드를 재정의하는 데 @Override 주석이 필요하지 않습니다. 그러나 코드를 더 읽기 쉽게 만들고 컴파일러가 실제로 메서드를 재정의하고 있는지 (예를 들어 하위 클래스 메서드를 잘못 입력하지 않았는지) 확인하도록합니다.


재정의는 인스턴스 메서드에서만 발생합니다. 참조 변수의 유형이 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.

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으로 변경할 수 없습니다. 컴파일 오류가 발생합니다.

하지만 무효 이름 으로 변경 무효 이름 은 재정입니다.

그리고 경우에 정적 이름 으로 변경 정적 이름 그것의 숨기기. (컴파일러가 수퍼 클래스의 객체에서 정적 메소드를 발견하면 서브 클래스의 메소드를 확인하지 않습니다.)


이 코드 조각에서는 '정적'대신 '개인'액세스 한정자를 사용하여 메서드 숨기기와 메서드 재정의 간의 차이점을 보여줍니다.

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

최근 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 클래스를 정적 ​​유형으로 사용하므로 Point 객체에서 equal 메서드를 호출하면 Point 클래스가 매개 변수로 도착하기를 기다리고 있지만 Object는옵니다. 그래서 Object 클래스는 실행되는 메소드와 같습니다. 왜냐하면 거기에 equals (Object o)가 있기 때문입니다. 이 경우 Point의 클래스 equals는 재정의하지 않지만 Object 클래스 equals method를 숨 깁니다 .


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())

링크 된 자바 튜토리얼 페이지는 재정의 및 숨기기 개념을 설명합니다.

동일한 시그니처 (이름, 매개 변수의 수 및 유형) 및 반환 유형을 가진 서브 클래스의 인스턴스 메서드는 슈퍼 클래스의 인스턴스 메서드와 같은 방식으로 슈퍼 클래스의 메서드를 재정의합니다.

서브 클래스가 수퍼 클래스의 정적 메소드와 동일한 시그니처를 사용하여 정적 메소드를 정의하는 경우 서브 클래스의 메소드는 수퍼 클래스의 메소드를 숨 깁니다.

정적 메서드를 숨기는 것과 인스턴스 메서드를 재정의하는 것의 차이점은 다음과 같은 중요한 의미를 갖습니다.

  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()출력은 :
숨겨진한다 : 아이를
오버라이드 (override) 할 수 : 아이

위의 출력 (특히 굵게 표시된 출력)에서 볼 수 있듯이 메서드 숨김은 재정의와 다르게 동작합니다.

Java는 메서드에 대해서만 숨기기 및 재정의를 허용합니다. 동일한 규칙이 변수에 적용되지 않습니다. 변수 재정의는 허용되지 않으므로 변수를 숨길 수만 있습니다 (정적 변수와 비 정적 변수 간의 차이 없음). 아래 예는 메서드 getName()가 재정의되고 변수 name가 숨겨 지는 방법을 보여줍니다 .

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;
    }
}

At runtime the child version of an overridden method is always executed for an instance regardless of whether the method call is defi ned in a parent or child class method. In this manner, the parent method is never used unless an explicit call to the parent method is referenced, using the syntax ParentClassName.method(). Alternatively, at runtime the parent version of a hidden method is always executed if the call to the method is defined in the parent class.


In method overriding, method resolution is done by the JVM on the basis of runtime object. Whereas in method hiding, method resolution is done by the compiler on the basis of reference. Thus,

If the code would have been written as,

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

The Output would be as below:
Class method in Animal.


하위 클래스에 동일한 정적 메서드가있을 때 컴파일러가 슈퍼 클래스 메서드 구현을 숨기므로 숨김이라고합니다.

컴파일러는 재정의 된 메서드에 대한 제한된 가시성을 갖지 않으며 런타임 중에 만 사용되는 메서드를 결정합니다.


자바에서 정적 메소드 숨김이 어떻게 발생합니까? Cat 클래스는 Animal 클래스를 확장하고 있습니다. 그래서 Cat 클래스에는 정적 메소드가 모두 있습니다 (즉, Child 클래스의 정적 메소드와 Parent 클래스의 정적 메소드를 의미합니다).하지만 JVM은 Parent 정적 메소드를 어떻게 숨길까요? 힙과 스택에서 어떻게 처리되고 있습니까?

참고 URL : https://stackoverflow.com/questions/10594052/overriding-vs-hiding-java-confused

반응형