2013-10-04 5 views
0

JVM은 동적 바인딩에 대해 이해했기 때문에 런타임에 객체의 실제 유형을 살펴보고 해당 클래스에서 구현을 검색하고 상속 수준까지 올라간다.동적 바인딩에 대한 오해의 소감

우리가 예를 들어 :

Vehicle v = new Car(); 클래스 CarVehicle이 연장된다고 가정하면, 우리는 기준 가변형 차량이며 개체 유형 차량임을 알 수있다.

우리가 말한다면 : v.start()을 :

JVM이 Vehicle 클래스에서 먼저 Car 클래스에 다음 start 메소드 구현에 보일 것이다.

이의 예는이 코드에 있습니다

public class scratch{ 
    public static void main(String [] args){ 
     Vehicle v = new Car(); 
     v.start(); 
    } 
} 

class Vehicle{ 
    public void start(){ 
     System.out.println("Vehicle class"); 
    } 
} 

class Car extends Vehicle{ 
    public void start(){ 
     System.out.println("Car class"); 
    } 
} 

예상대로이 코드의 출력은 다음과 같습니다 "자동차 클래스"이것은 내 질문에

입니다 : 내가 시작 방법을 취할 경우 Vehicle 클래스에서 완전히 지우면 프로그램이 더 이상 실행되지 않습니다. 내가 동적 바인딩에 대해 이해하는 것으로부터 JVM은 여전히 ​​객체의 실제 유형 (이 경우 Car)을 살펴보고 start 메소드의 자동차 구현을 실행해야합니다. 그러나, 그렇게하지 않습니다.

왜?

+0

메서드가 존재하지 않기 때문에. 'NoSuchMethodError '(http://docs.oracle.com/javase/7/docs/api/java/lang/NoSuchMethodError.html) –

+1

IMHO 당신이'start' 함수를 제거하고'Vehicle v = new Car()'컴파일러 오류가 발생합니다. 컴파일러는 LHS 객체를 검사하여 호출 된 함수가 존재하는지 여부를 확인합니다. –

+0

@VusP 그는 .class 또는 .java를 수정했는지에 따라 다릅니다. 하지만 그래, 컴파일 오류가 더 가능성이 높습니다. –

답변

1

Vehicle에서 제거하는 문제는 다형성과 관련이 있습니다. Vehicle에서 여기에 start()을 정의하면 모든 Vehicle, 심지어 하위 클래스에도 해당 메소드가 있음을 알 수 있습니다. 당신이 Vehicle()에서 start()를 제거하면

, 다음은 우리가 start()을 수행하는 Car 알고에도 불구하고, 어떤 Vehiclestart() 방법을 가지고 있음을 보장 할 수 없습니다. Vehicle을 확장하지만 start()을 정의하지 않는 HorselessCarriage 클래스가 있다면 어떻게 될까요? 그런 다음 start() 메소드가 없습니다. 따라서 Vehiclestart() 방법이 없으면 Vehicle 변수에서 start()을 호출 할 수 없습니다.

Vehiclestart()를 호출 할 수있는의 요점은 어떤Vehicle 구현이 호출 할 start() 방법을 가지고 있도록하는 것입니다.

UPDATE

JVM은 오브젝트의 실행시의 형태를 취하고 메소드 호출의 서명과 일치하는 방법이 보인다. 발견되지 않으면 상속 트리를 수퍼 클래스로 이동하여 거기에서 메소드를 찾습니다.

세부 정보가 JLS, Section 15.12.4.4과 같다 :

하자 X 메소드 호출 대상 참조의 컴파일 시간 유형일.이어서 : 클래스 S 메소드 의 호출에 필요한 동일한 기술자 (파라미터의 개수, 같은 파라미터 유형과 같은 복귀 형)으로 m 라는 비추 방법 선언을 포함

하면 컴파일 타임 (§15.12.3)에서 결정된 경우 :

호출 모드가 super 또는 interface 인 경우이 메서드는 이 호출되고 프로 시저가 종료됩니다.

호출 모드는 가상이며, S에서 선언 은 (§8.4.8.1) X.m가 다음 S에서 선언 방법 호출 할 수있는 방법에 우선, 상기 절차가 종료되면.

호출 모드가 가상이고 S의 선언이 이 X.m을 오버라이드하지 않고 X.m이 추상으로 선언 된 경우 AbstractMethodError가 발생합니다.

그렇지 않으면 S에 수퍼 클래스가있는 경우이 동일한 검색 절차는 이며 S 대신 직접 수퍼 클래스를 사용하여 재귀 적으로 수행됩니다. 호출 할 메소드는 이 조회 프로 시저의 재귀 호출의 결과입니다.

여기에서 S은 개체의 런타임 유형으로 나타납니다.

+0

이것은 의미가 있으며이 질문을하기 전에도 의심 스럽습니다. 그렇다면 역동적 인 바인딩이 정확히 어떻게 작동합니까? 호출 할 메소드를 결정할 때 JVM은 어디에서 시작합니까? –

+0

@ user121834 내 대답을 업데이트했습니다. – rgettman

+0

@rgettman 확인해 주셔서 감사합니다. 이것은 내가 어떻게 그것이 일하는 줄 알았지 만, 아직 올려다 보지 않았다! – aglassman

0

Vehicle 클래스에서 start() 메서드를 사용하면 Car가 해당 메서드를 재정의합니다. Vehicle에서 start() 메서드를 제거하면 더 이상 해당 메서드를 재정의하지 않습니다. 따라서 v.start()를 호출하면 호출 할 메서드가 없습니다. 이것이 @Override를 사용해야하는 이유이며, 코드에서 어떤 일이 일어나고 있는지 분명합니다. Vehicle에 start() 메소드가없는 경우 Car에서 start()를 호출하려면 먼저 Vehicle 클래스를 Car 클래스로 캐스팅해야합니다. 간단히 말해서

+0

나는 rgettman의 코멘트에서했던 것과 같은 방식으로 대답 할 것입니다. 이것은 의미가 있으며 나는 이것을 예상했다. 그러나 런타임에 어떤 메소드 구현을 결정할 때 어떤 클래스가 JVM을 시작 하는가? –

+0

런타임에는 실제 객체의 클래스로 시작한다고 생각합니다. 그래서이 경우 자동차를 보면서 시작합니다. – aglassman

1

, JVMstart 방법의 기준에 대한 검색을 시작하기 위해 하나의 엔드 포인트가 필요합니다, 당신이 호출 할 방법을 가지고있는 개체 유형을 중요하지, JVM는 기존 전화하려고 확인하기 위해 거울을 필요 방법.

+0

정확하게 이해하지 못합니다. 이 인스턴스에서 JVM이 선택하는 엔드 포인트는 무엇입니까? 거울로 무엇을 의미합니까? –

+0

동적 연결에는 [가상 테이블] (http://en.wikipedia.org/wiki/Virtual_method_table)의 메소드에 대한 적절한 참조를 시작하고 찾을 수있는 지점이 있어야하므로 메소드에 액세스하려고하면 이 변수에 존재하지 않는 것은 JVM이 컴파일면을 통과하지 못했기 때문입니다. 왜냐하면이 변수에는이 메소드가 없기 때문입니다. – xhamr

0

그러나 일단이 메서드를 제거하면 Vehicle에는 더 이상 "시작"기능이 없으며 Vehicle 클래스에서 알 수없는 메서드이며 Vehicle 참조를 통해 액세스합니다. 원하는대로 Java를 수행하려면

abstract class Vehicle 
{ 
    public abstract void start(); 
} 

Vehicle의 모든 하위 항목에 이제 시작 방법이 보장되므로 코드가 다시 작동해야합니다. 그러나 귀하의 예에서와 같이 시작 메소드가 제거되면 일부 이전 진술에서 시작 메소드가없는 Motorcycle과 같은 다른 Vehicle 자손을 생성하지 않았고 귀하의 V 참조에 할당하지 않았다는 보장이 없습니다.

0

나는이 문제를 보는 간단한 방법은 방법을 소개하는 것이라고 생각한다. 여기에 방법을 정의하는 방법은 다음과 같습니다

public void callStart(Vehicle vehicle) { 
    vehicle.start(); 
} 

이 방법을 사용하면 콘크리트 Car 또는 콘크리트 Vehicle 전달 할 수 있습니다.

Java가이 코드를 컴파일 할 수 있다고 가정합니다.start() 메서드가없는 Vehicle의 경우 Java를 사용하면 런타임에 오류를 발견해야합니다. 하지만 Java는 오류를 컴파일 한 시점을 알려줌으로써 시간을 절약 해줍니다.

이것은 자바와 같은 일부 동적 언어와 다릅니다. 이것이 JavaScript라면 구체 Vehicle을 전달할 수 있으며 런타임에 오류를 발견해야합니다. 또 다른 차이점은 JavaScript에서는 콘크리트 Car을 전달할 수 있으며 오류없이 작동한다는 것입니다. 이것은 duck typing라고하며 Java에없는 기능입니다.

관련 문제