2017-02-14 5 views
5

제목이 오해의 소지가 있지만 비 원어민 인 경우 더 좋은 것을 알아 내지 못했습니다. hybrid 실제로 "RingdingRingding" 때문에 기대했던 1 OUPUT을 위해 몇 가지 방법참조 할 클래스 유형과 호출 할 메소드를 결정하는 실제 클래스 유형?

Fox foxi = new Fox(); 
Dog hybrid = new Fox(); 
System.out.println(hybrid.play(foxi)); // Output number 1 
System.out.println(foxi.play(hybrid)); // Output number 2 

전화

public class Dog { 
    public String bark() { 
     return "Wuff"; 
    } 
    public String play(Dog d) { 
     return "Wuff" + d.bark(); 
    } 
} 


public class Fox extends Dog { 
    public String bark() { 
     return "Ringding" ; 
    } 
    public String play(Fox f) { 
     return "Ringding" + f.bark(); 
    } 
} 

그리고 나뿐만 아니라 일부 인스턴스를 생성 :

내가 두 개의 클래스, DogFox을 말해봐 참조가 유형이 Dog 인 경우에도 Dog의 인스턴스에 대한 참조는 여전히 참조됩니다 Fox 객체들, 여전히 난이 출력 얻었다 : foxi 때문에

WuffRingding

저도 같은 문제가있어 두 번째는, Foxhybrid의 인스턴스가 실제로 Fox의 인스턴스이다 (? 무슨 일이 있어도 참고, 오른쪽)의 OUPUT는 "RingdingRingding" 없어야하지만 다시, 내가 가지고 :

을 WuffRingding

이유를 설명 할 수 있습니까?

+1

중요한 것은'Fox.play (Fox)'가'Dog.play (Dog)'를 덮어 쓰지 않는다는 것입니다. 하이브리드 타입이'Dog'이기 때문에,'play (Dog)'오버로드가 호출됩니다. –

+0

@AndyTurner 안녕하세요, 앤디 당신의 대답에 감사드립니다. 타입 캐스팅에 관해서도, 액추럴 타입은 중요합니까? Fox (Fox)의 인스턴스에 (Dog)를 캐스팅하고 껍질 메서드를 호출한다고 가정 해 봅시다. Fox 클래스의 메서드가 될 것입니다. 그렇습니까? 참조와 캐스팅 사이에 다소 혼란 스럽습니다. –

+1

호출 할 메서드는 런타임이 아닌 컴파일 타임에 결정됩니다. 따라서 메소드에 'Dog'에 대한 참조를 전달하면 런타임에 'Fox'를 참조하는 경우에도 'Dog'를 사용하는 오버로드가 호출됩니다. –

답변

2

두 가지 중요한 메소드 호출.

컴파일 시간과 런타임의 두 배입니다.
규칙은이 두 번에 동일하지 않습니다.

  • 컴파일 타임에 컴파일러는 메소드의 정확한 서명이 제대로 컴파일되도록 정적으로 정의해야합니다.
    이 바인딩은 컴파일러가 메서드가 호출되는 구체적인 인스턴스와 상관이 없으며 메서드에 전달 된 매개 변수와 동일하므로 정적입니다.
    컴파일러는 실행 흐름 중에 유효 유형이 변경 될 수 있으므로 실행 유형에 의존하지 않습니다.
    그래서 컴파일러는 선언 된 형식에 대해 사용 가능한 메서드를 검색합니다.이 형식은 전달 된 매개 변수의 선언 된 형식에 따라보다 구체적인 메서드입니다.

  • 런타임에 클래스 또는 다른 메서드의 인스턴스 메서드는 메서드가 호출되는 유효한 인스턴스에 따라 사용됩니다.
    그러나 호출 된 메서드는 컴파일 타임에 지정된 서명을 준수해야합니다. 첫 번째 경우에 대해

1)

Fox foxi = new Fox(); 
Dog hybrid = new Fox(); 
System.out.println(hybrid.play(foxi)); // Output number 1 
  • 첫 (컴파일 시간) : 개 예컨대

컴파일러 가장 구체적인 방법을 찾아야 play()은 Fox 선언 형식의 변수를 매개 변수로 사용합니다.개 클래스에서

는 호환 서명 하나의 방법 play()이 존재합니다
public String play(Dog d) { 

그래서이 서명은 바인딩에 사용됩니다 : String play(Dog d).

bark() 메서드에 대해서는 bark() 메서드 서명이 하나뿐이므로 분명합니다.

런타임시 콘크리트 인스턴스의 String play(Dog d) 방법은 호출됩니다
그래서 우리는 컴파일 시간

  • 두 번째 시간 (런타임)에 바인딩되는 방법에 모호함이 없습니다. hybrid 변수는 Fox의 인스턴스를 나타내지 만 Fox는 String play(Dog d)을 재정의하지 않습니다. 폭스는 또 다른 서명 놀이() 메소드를 정의하지만, :
    public String play(Fox f) { 
    

    그래서 JVM은 강아지의 public String play(Dog d) { 메소드를 호출합니다.
    그리고 d.bark()이 실행될 때 d의 유효 형식의 메서드를 호출하고 dFox 인스턴스를 참조 할 때 메서드를 호출합니다.

    그래서 "WuffRingding"이 출력됩니다. 두번째 경우에 대해


    2)

    Fox foxi = new Fox(); 
    Dog hybrid = new Fox(); 
    System.out.println(foxi.play(hybrid)); // Output number 2 
    
    • 첫() 컴파일 시간 :

    Fox 예를 들면, 컴파일러는 가장 구체적인 방법을 찾아야 play()을 매개 변수로 사용하여 Dog 유형으로 선언 된 변수. Fox 클래스에서

    , 호환 가능한 매개 변수를 두 play() 방법이 존재합니다

    public String play(Dog d) { // inherited from the parent class 
    
    public String play(Fox f) { // declared in Fox 
    

    컴파일러는 방법보다 특정한 것을 확인
    메소드의 호출 컨텍스트에 대한보다 구체적인 방법을 선택해야한다 Dog 선언 된 유형 매개 변수에 대한 다른 값은 public String play(Dog d)입니다. 그래서 컴파일러는 메서드 호출을 public String play(Dog d)에 바인드합니다.

    • 두 번째 시간 (런타임) : 런타임시

    콘크리트 인스턴스의 String play(Dog d) 메서드가 호출됩니다.
    첫 번째 경우에 변수 foxi은 Fox 인스턴스를 나타내지 만 Fox는 String play(Dog d)을 무시하지 않습니다.
    그래서 JVM은 public String play(Dog d) Dog 메소드를 호출합니다.
    그리고 f.bark()이 실행될 때 f의 유효 유형의 메소드를 호출하고 fFox 인스턴스를 참조 할 때 메소드를 호출합니다.

    그래서 "WuffRingding"이 다시 출력됩니다. 이 방법은 효과적으로 오버라이드 (override)하지 않는 경우

    @Override 
    public String play(Fox f) { 
        return "Ringding" + f.bark(); 
    } 
    

    : 예를 들어
    :


    는 부모 클래스의 메소드를 오버라이드 (override)하기위한 방법에 @Override 을 추가해야합니다 놀라움의이 종류를 방지하려면 play(Fox f) 메서드를 사용하면 컴파일러에서이 메서드에 대해 불만을 제기합니다.

+0

답변에와 주셔서 감사합니다. 아직도 어떤 것을 시도 : 개 a = (개) 여우; a.bark(); "개"유형의 참조가 "a"인 경우에도 출력이 여전히 "울림"인 이유를 설명 할 수 있습니까? –

+1

당신은 환영합니다 :) 다시 대답을 읽었습니다. "bark() 메서드에 관해서는 하나의 bark() 메서드 서명 만 있기 때문에 훨씬 명확합니다. 그래서 우리는에 바인딩 된 메서드에 모호함이 없습니다. 컴파일 시간 ". 컴파일시에 고유 한'bark()'메쏘드가 컴파일 된 클래스에 묶여 있음을 의미합니다. 그리고 런타임에 JVM은 메소드가 호출되는 유효 인스턴스의 바운드 메소드 ('bark()')를 사용합니다. – davidxxx

+0

나는 지금 그것을 얻는다, 많은 감사! –

1

여기에 play 메서드가 오버로드되지 않고 오버로드되었습니다.

Dog d = new Fox()을 수행 할 때 Dog의 기준은 때까지 Dog 클래스의 방법 Fox 클래스에 의해 오버라이드 (override)하지 않는 클래스 Dog의 방법을 호출합니다. 메소드가 오버라이드 (override)되면 (자), 그러한 메소드의 호출은 실행시에 해결됩니다 만, 오버로드 된 메소드의 호출은 컴파일시에 해결됩니다.

추가 정리를 위해 정적 다형성과 런타임 다형성을 읽습니다.

1

분명히, 당신의 혼란의 원인이되는 것은 그 동안 실제로 단지 과부하을, 당신은 서브 클래스 Fox무시 슈퍼 클래스의 플레이 방법 플레이 방법을 생각한다는 것입니다.

Fox 클래스의 play-method에서 Dog의 매개 변수 유형을 변경하면 질문에서 분석 한 이유로 출력이 "RingdingRingding"이됩니다.이 경우 재생이 -method가 superclass-method를 올바르게 대체합니다.

더 자세히 오버로드 된 플레이 방법의 경우에 살펴 보자 :

hybrid.play(foxi) 

컴파일러는 Dog입니다 hybrid의 선언 된 정적 유형에 보인다. foxiFox으로 선언됩니다.따라서 컴파일러는 정적 형식 Fox 중 하나의 매개 변수를 필요로하는 클래스 Dog의 재생 방법을 찾습니다. 정적 유형 Dog 중 하나의 매개 변수를 예상하는 재생 방법 만 있기 때문에 성공하지 못합니다. 그러나 DogFox의 수퍼 클래스이므로 컴파일러는이 호출을 마지막에 호출합니다.

foxi.play(hybrid) 

컴파일러는 Fox입니다 foxi의 선언 된 정적 유형에 보인다. hybridDog으로 선언됩니다. 따라서 컴파일러는 Fox 클래스의 정적 메서드 Dog 중 하나의 매개 변수를 필요로하는 play-method를 찾습니다. 컴파일러가 선택할 수있는 클래스 Fox에는 두 가지 play-methods가 있습니다. play(Fox f) 및 상속 된 오버로드 된 메서드 play(Dog d)입니다. play(Fox f)Fox 유형의 매개 변수 하나가 필요하며 hybridDog으로 선언되므로이 방법은 유효한 선택이 아닙니다. 이는 컴파일러가 이전 문과 마찬가지로 Dog 클래스에 선언 된 play(Dog d) 메서드를 다시 선택한다는 의미입니다.

컴파일러는 당신이 play(Dog d)play(Fox f)을 무시할 수없는 이유는 다음과 같다 :이 허용되었다 상상해 사람이 할 것 :

Dog doggo = new Dog(); 
hybrid.play(doggo); 

는 이제, 오버라이드 (override) play(Fox f) 메소드가 호출 될 것이다 play(Fox f)의 구현은 fDog 일뿐만 아니라보다 전문화 된 Fox 일 것으로 예상하기 때문에 실행시에 Dog 유형의 입력 매개 변수가 작동하지 않습니다.

슈퍼 클래스 메소드를 오버라이드해야하는 오버로드/오버라이드 혼동 주석 메소드를 방지하려면 @Override으로 지정하십시오. @Override 주석 메소드가 실제로 수퍼 클래스 메소드를 대체하지 않으면 컴파일러는 코드 컴파일을 거부합니다.

1

어떤 방법을 호출할지 결정하는 규칙은 pretty complicated이지만 여기서는이 경우에 대해 요약하려고합니다. hybrid.play(foxi)에 대한 우선

:

  1. hybrid 검색하는 클래스 또는 인터페이스를 결정는 Dog을 입력있다, 그래서 Dog 인터페이스는 방법에 대해 검색됩니다. 즉, Dog에 정의한 메소드 만 호출 될 수 있습니다. 이들은 :

    bark() 
    play(Dog) 
    
  2. 유형 Fox의 매개 변수와 방법 서명

    당신은 play 방법을 호출 할을 결정합니다. FoxDog의 하위 유형이므로 play(Dog) 메서드가 일치합니다.

따라서이 메서드는 호출 된 메서드입니다.foxi.play(hybrid)에 대한

다음, 상기 Fox 인터페이스 방법에 대해 검색됩니다

  1. foxiFox 입력이 검색하는 클래스 또는 인터페이스를 결정하므로. 가능한 방법은 다음과 같습니다

    bark() 
    play(Dog) 
    play(Fox) 
    

    공지 사항 play(Fox)play(Dog)를 대체하지 않습니다 그들은 같은 방법으로 서명이없는, 그래서 play(Fox) 단지 과부하입니다.

  2. 입력 Dog의 매개 변수의 play 메소드를 호출하는 방법 서명

    를 결정합니다. 따라서 play(Dog) 메서드는 호출 된 메서드이므로 일치하는 유일한 메서드입니다.

    hybrid에 런타임 유형이 Fox 인 것은 문제가되지 않습니다.이 메서드 호출은 컴파일 할 때 발생합니다.

    따라서 play(Fox)이 아닌 play(Dog)이 호출됩니다.