25

실험적으로 Java 정적 메소드가 정적 컨텍스트에서도 범위에있는 동일한 명명 된 메소드를 대체한다는 것을 발견했습니다. 매개 변수 오버로딩을 허용하지 않고도. 마찬가지로Java static imports

import java.util.Arrays;  
import static java.util.Arrays.toString; 

public class A { 
    public static void bar(Object... args) { 
     Arrays.toString(args); 
     toString(args);  //toString() in java.lang.Object cannot be applied to (java.lang.Object[]) 
    } 
} 

나는 이것에 관해서 아무것도 발견 할 수 없다. 이거 버그 야? 그렇다면 언어를 구현할 이유가 있습니까?

UPD : Java 6에서는이 예제를 컴파일하지 않습니다. 질문은 - 왜?

+0

그것의 super의 Object의'toString()' –

+2

IMHO를 언급 한 것처럼 보이지만 전체 정적 임포트 기능은 네임 스페이스를 오염시키고 코드 가독성을 떨어 뜨리는 나쁜 개념입니다. 게으르지 마십시오. 정적 함수의 클래스/인터페이스를 입력하는 것이 그리 어렵지 않습니다. IDE를위한 IDE가 있습니다. 정적 가져 오기를 사용하지 마십시오. – buc

+0

@ Jigar Joshi, 이음새가 너무 심해요. 그러나 나는 아무것도 찾을 수 없습니다. 그리고 더, 우리는 정적 인 컨텍스트로부터'Object.toString'를 호출 할 수 없기 때문에이 동작에 어떤 로직도 보이지 않습니다. –

답변

21

설명은 간단하다 오른쪽 이름의 그런 다음에 만 과부하 해결 및 게임에서의 공동 작업과 같은 다른 작업을 수행하십시오.

이제 toString() 메서드를 포함하는 가장 작은 포함 범위가 Object에서 상속되는 클래스 A입니다. 그러므로 우리는 거기서 멈추고 더 이상 검색하지 않습니다. 안타깝게도 컴파일러는 주어진 스코프에있는 메소드 중 가장 적합한 메소드를 찾으려고 시도하고 그 중 하나를 호출 할 수 없으며 오류를 제공함을 알립니다. 범위에 자연적 방법은 정적 수입보다 우선하기 때문에 결코 정적 객체의 메소드와 동일한 이름을 가진 방법을 가져 의미

는합니다 (JLS는 구체적으로 방법의 그림자를 설명하지만, 이것에 대한 문제는 그것을 기억하는 것이 훨씬 간단하다고 생각합니다.)

편집 : @alf 친절하게 전체 사진을 원하는 사람들을 위해 describes the method invocation JLS의 오른쪽 부분을 제출. 다소 복잡하지만 문제는 간단하지 않으므로 예상 할 수 없습니다.

+4

JLS 링크가 필요합니다. - http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.1 – alf

+0

@alf 감사합니다. 지금은 훨씬 더 나은 대답입니다. . JLS에서 설명을 찾을 수있는 위치를 알고 있다면 직접 추가했습니다. – Voo

4

오버라이드가 아닙니다. 문제가 해결되면 this.toString()Arrays.toString 대신 A 메서드에 계속 액세스합니다.

그림자 N이라는 필드를 가져 패키지 (P)의 컴파일 부 (C)에서 단일 - 정전 수입 신고 D :

language specification

정적 수입 만 static 방법 및 종류의 해상도에 영향을 미치는 것을 설명 c의 전체에서 c의 정적 요청시 가져 오기 선언으로 가져온 n이라는 정적 필드의 선언.

서명이있는 n이라는 메서드를 가져 오는 패키지 p의 컴파일 단위 c에서 단일 정적 가져 오기 선언 d는 의 정적 메서드의 선언을 쉐도 잉합니다. 정적 가져 오기 - 온 디맨드 선언 c.

N라는 타입의 선언의 그림자를 가져 패키지 (P)의 컴파일 부 (C)에서 단일 - 정전 수입 신고 D :

  • 정적 가져가 N이라는 가져온 임의 정지형 -에서 - 비 요구 선언.
  • 최상위 유형 (§7.6) n의 이름은 p의 다른 컴파일 단위 (§7.3)에서 선언됩니다.
  • 임의의 유형 n은 c의 유형 수입 주문 선언 (§7.5.2)에 의해 수입됩니다. 전체에서 c.

정적 가져 오기는 비 정적 메서드 나 내부 유형을 섀도 잉하지 않습니다.

따라서 toString은 비 정적 메서드를 음영 처리하지 않습니다. 이름이 toStringA의 비 정적 방법을 참조 할 수 있기 때문에, Arraysstatic의 방법을 참조 할 수 않기 때문에 toStringString toString() 인 범위에서 사용할 toString라는 유일한 방법으로 결합한다. 그 방법은 어떤 인자도 취할 수 없으므로 컴파일 에러가 발생합니다.

Section 15.12.1은 방법 해상도를 설명하며 static 메서드 내에서 사용할 수없는 메서드 이름의 섀도 잉을 허용하지만 member 메서드 내에서는 사용할 수 없도록 완전히 다시 작성해야합니다.

내 생각에 언어 디자이너는 메서드 확인 규칙을 간단하게 유지하기를 원했기 때문에 동일한 이름은 static 메서드에 나타나는지 여부와 같은 동일한 것을 의미하며 사용할 수있는 유일한 변경 사항입니다.

방법을 해결하는 컴파일러가 메소드가 가장 작은 둘러싸 범위를 찾기가 맨 처음에하는 일을 호출 할 : 그것은 행동이 매우 직관적이라는 사실을 변경하지 않지만

+0

메소드'bar'가 정적 인 것을 제외하면, 편집 된 – chrisbunney

+0

@StasKurilin에'toString()'을 호출 할 인스턴스가 없습니다. –

+2

@StasKurilin [파. 6.3.1] (http://java.sun.com/docs/books/jls/third_edition/html/names.html#34133)에 자세히 설명되어 있습니다. 그것은 인스턴스 메소드'Object.toString()'의 선언이 그 범위에있는 다른 모든 메소드 *를 음영 처리한다고 말합니다. 여기에는'Arrays.toString (Object [])'에 대한 정적 가져 오기가 포함됩니다. 즉, 정적 가져 오기는 효과가 없음을 의미합니다. * 컴파일러는 메서드 호출을 해결한다고 생각하지 않습니다. – millimoose

0

정상적인 가져 오기와 다른 버그 또는 다른 것으로 생각하지 않습니다. 예를 들어 일반 가져 오기의 경우 가져온 이름과 같은 개인 클래스가 있으면 가져온 이름이 반영되지 않습니다.

1

당신은 유사한 은 다음 어떤 컴파일러 오류

import static java.util.Arrays.sort; 
public class StaticImport { 
    public void bar(int... args) { 
     sort(args); // will call Array.sort 
    } 
} 

이 컴파일 이유를하지 것이다 코드를 찾고 다음 시도하고 당신은 toString() (또는 다른 방법에 정의되어 있지 않은 경우 class Object)는 Object가 클래스의 부모이기 때문에 여전히 Object 클래스로 범위가 지정됩니다. 따라서 컴파일러가 Object 클래스의 메소드와 일치하는 시그너처를 찾으면 컴파일러 오류가 발생합니다. 내 예제에서 Object 클래스는 sort(int[]) 메서드를 가지고 있지 않으므로 컴파일러는 정적 가져 오기과 정확하게 일치시킵니다.