2017-05-09 1 views
2

우리는 오류를 볼 수있는 그런 방법 :자바 바이트 코드와 오류

java.lang.NoSuchMethodError: com.nhn.user.UserAdmin.addUser(Ljava/lang/String;)V.

이없이 반환 형식과 방법 addUser가 발견되지 않는 것을 말한다. 이는 라이브러리가 업데이트되었지만 응용 프로그램의 바이트 코드가 여전히 오래된 이유 때문일 수 있습니다.

그러나 Java 오버로드를 연구 할 때 Java는 반환 유형의 변경만으로 오버로드를 지원하지 않는다는 것을 알 수 있습니다.

올바르지 않으므로 바이트 코드가 호출 된 메소드의 리턴 유형을 알려주는 이유와 메소드가 리턴되는 유형으로 라이브러리가 갱신 될 때 오류가 발생하는 이유는 무엇입니까?

+0

반환 유형이 변경되면 오류가 발생하지 않아야합니까? 라이브러리의 메소드 결과를 할당하지만 이후에 라이브러리가 변경되어 void 또는 호환되지 않는 객체를 반환하는 경우 어떻게해야합니까? –

답변

0

메서드가 인터페이스에서 선언 된 후 오버로드되었을 수 있습니다. 따라서 구현 된 버전의 메소드를 변경하면 오류가 발생합니다. 반환 유형이 일치하지 않지만 이름이 같으면 여전히 오류가 발생합니다. 컴파일러는 메서드를 호출 할 때 사용할 반환 유형을 알 수 없으므로 반환 형식 만 변경하면 안됩니다.

+0

나는 그 오류의 이유는 무엇인지 이해했다. 나의 질문은 리턴 타입에서만 변경된 메소드를 오버로드 할 수 없을 때 JVM이 리턴 된 메소드의 세부 사항을 기록한 이유는 무엇인가? 메소드의 반환 유형 정보를 저장하는 용도는 무엇입니까? – Jobs

1

Java 바이트 코드는 강력하게 유형이 지정되고 검증됩니다. 이는 호출자의 코드가 호출 된 메소드가 반환 할 코드와 호환 가능해야 함을 의미합니다. 따라서 호출자의 메서드 참조에 예상되는 반환 형식이 포함되지 않은 경우에도 코드에 여전히 암시 적 가정이 포함되어있었습니다 (예 : 결과와 함께 long 연산을 시도하면 메서드가 Object 또는 void이 아닌 long을 반환 할 것으로 예상됩니다.

예상되는 반환 형식을 나타내는 메서드 참조를 사용하면 확인 작업이 간단 해지고 전체 프로세스를보다 효율적으로 처리 할 수 ​​있습니다. 실제 연결을 수행하지 않고 예상되는 메서드 서명을 사용하여 메서드 코드의 정확성을 확인할 수 있습니다. 메소드 호출 명령어가 최종적으로 링크되면 실행 가능 코드를 확인할 필요가 없으며 서명 만 일치해야합니다.

그래서 자바 소스 코드가 최소한 이전 버전에서는 다른 리턴 유형을 정의 할 수 없더라도 자바 바이트 코드가 그렇게 설계되었습니다. Java 5부터는 규칙이 더 이상 엄격하지 않습니다.

다음 인터페이스 고려해

interface StringFunction<R> { 
    R apply(String input); 
} 

인해 타입을 소거하는, 상기 바이트 코드 레벨에있어서 Object apply(String input)있을 것이다.

지금 다음 구현 클래스 고려 :

class Length implements StringFunction<Integer> { 
    public Integer apply(String input) { 
     return input.length(); 
    } 
} 

뿐만 아니라보다 구체적인 반환 형식이 허용 선언되고, 그것은 실제로 일반 타입 시스템에 따라 같은 자바 언어로 필요한입니다, 그것은 상속 추상 방법 Integer apply(String)에서 StringFunction<Integer>. 바이트 코드 레벨

, 그것은 실제 구현 방법 Integer apply(String)뿐만 아니라 정식 바이트 코드 레벨에서 interface 계약을 만족하고, 실제 구현 방법에 위임 다리 방법 Object apply(String input)있을 것이다.제네릭 효과적으로 반환 형식의 축소를 할 수 있기 때문에

이 아닌 일반 메소드를 거부 할 이유가 없었다, 따라서, 자바는 소위 허용 공변 반환 형식뿐만 아니라 자바 5 가입일 :

class Base { 
    Object getValue() { 
     return null; 
    } 
} 
class Sub extends Base { 
    @Override String getValue() { 
     return "now a string"; 
    } 
} 

그래서 오버로드가 아닌 동일한 매개 변수 유형이지만 다른 리턴 유형의 여러 메소드를 갖는 클래스를 생성 할 수 있습니다.

이러한 경우는 대안으로 처리 될 수 있습니다. 메소드가 매개 변수 유형으로 만 구별되고 리턴 유형은 동일하거나 더 구체적이어야하며 공변 리턴 유형과 호환 가능해야한다는 것을 정의함으로써 메소드 테이블을 빌드 할 때 JVM이 모든 리턴 유형을 열심히 해결해야한다는 것을 암시합니다 클래스의 유형이 실제로 더 구체적인 지 여부를 확인합니다. 그리고 호출자와 호출 수신자간에 적절한 계약을 맺기 위해서는 반환 형식을 인코딩해야합니다.

+0

두 번째로 공분산을 다룬 답을 읽습니다. 나는 그걸 읽으면서 그 아이가 내가 틀 렸음을 알기에 무슨 뜻인지 잘 알고 있었다. – Eugene

+0

@Eugene : 나는 [this one]을 좋아한다. (http://stackoverflow.com/questions/2723397/what-is-pecs- 생산자 - 확장 - 소비자 - 슈퍼/19739576 # 19739576) 분산을 설명하기위한 ... – Holger