인스턴스를 통해 정적 메소드를 호출하지 않는 이유는 Java 컴파일러의 오류가 발생하지 않습니까?

StackOverflow https://stackoverflow.com/questions/610458

  •  03-07-2019
  •  | 
  •  

문제

나는 당신 모두가 의미하는 행동을 알고 있다고 확신합니다 - 코드와 같은 코드는 다음과 같습니다.

Thread thread = new Thread();
int activeCount = thread.activeCount();

컴파일러 경고를 유발합니다. 오류가 아닌 이유는 무엇입니까?

편집하다:

분명히 : 질문은 스레드와 관련이 없습니다. 나는 실 예제가 종종 그들과 함께 일을 엉망으로 만들 수 있기 때문에 이것을 논의 할 때 종종 주어진다는 것을 알고 있습니다. 그러나 실제로 문제는 그러한 사용법이 있다는 것입니다 언제나 말도 안되고 당신은 (유능하게) 그러한 전화를 쓸 수 없습니다. 이러한 유형의 메소드 호출의 모든 예는 Barmy입니다. 또 다른 것이 있습니다 :

String hello = "hello";
String number123AsString = hello.valueOf(123);

각 문자열 인스턴스에는 "String valueof (int i)"메소드가있는 것처럼 보입니다.

도움이 되었습니까?

해결책

기본적으로 나는 Java 디자이너가 언어를 설계했을 때 실수를 저지른 것으로 생각하며, 관련된 호환성 문제로 인해 수정하기에는 너무 늦었습니다. 예, 매우 오도하는 코드로 이어질 수 있습니다. 예, 피해야합니다. 예, IDE가 IMO로 취급하도록 IDE가 구성되어 있는지 확인해야합니다. 당신이 직접 언어를 디자인 한 적이 있다면, 피해야 할 종류의 예로서 명심하십시오 :)

Djclayworth의 요점에 응답하기 위해 C#에 허용되는 내용은 다음과 같습니다.

public class Foo
{
    public static void Bar()
    {
    }
}

public class Abc
{
    public void Test()
    {
        // Static methods in the same class and base classes
        // (and outer classes) are available, with no
        // qualification
        Def();

        // Static methods in other classes are available via
        // the class name
        Foo.Bar();

        Abc abc = new Abc();

        // This would *not* be legal. It being legal has no benefit,
        // and just allows misleading code
        // abc.Def();
    }

    public static void Def()
    {
    }
}

왜 오해의 소지가 있다고 생각합니까? 코드를 보면 someVariable.SomeMethod() 나는 그것을 기대한다 값을 사용하십시오 someVariable. 만약에 SomeMethod() 정적 방법이며, 기대는 유효하지 않습니다. 코드가 나를 속이고 있습니다. 아마도 어떻게 될 수 있습니까? 좋은 물건?

기괴하게도, Java는 잠재적으로 초기화되지 않은 변수를 사용하여 정적 메소드를 호출 할 수 없습니다. 일관성이없고 도움이되지 않는 혼란입니다. 왜 그것을 허용합니까?

편집 :이 편집은 Clayton의 답변에 대한 응답으로 정적 메소드에 대한 상속을 허용한다고 주장합니다. 그렇지 않습니다. 정적 방법은 다형성이 아닙니다. 다음은 다음과 같은 짧지 만 완전한 프로그램입니다.

class Base
{
    static void foo()
    {
        System.out.println("Base.foo()");
    }
}

class Derived extends Base
{
    static void foo()
    {
        System.out.println("Derived.foo()");
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Base b = new Derived();
        b.foo(); // Prints "Base.foo()"
        b = null;
        b.foo(); // Still prints "Base.foo()"
    }
}

보시다시피, 실행 시간 값 b 완전히 무시됩니다.

다른 팁

왜 오류가되어야합니까? 인스턴스는 모든 정적 메소드에 액세스 할 수 있습니다. 정적 메소드는 인스턴스의 상태를 변경할 수 없습니다 ( ~이다 컴파일 오류).

당신이주는 잘 알려진 예의 문제는 매우 구체적입니다. 스레드, 정적 메소드 호출이 아닙니다. 마치 당신이 얻는 것처럼 보입니다 activeCount() 참조 된 스레드의 경우 thread, 그러나 당신은 실제로 호출 스레드에 대한 수를 얻고 있습니다. 이것은 프로그래머로서 당신이 만드는 논리적 오류입니다. 이 경우 경고를 발행하는 것이 컴파일러가 수행하기에 적절한 일입니다. 경고에주의를 기울이고 코드를 수정하는 것은 당신에게 달려 있습니다.

편집 : 언어의 구문이 허용 오해의 소지가있는 코드를 작성하지만 컴파일러와 경고는 언어의 일부라는 것을 기억하십시오. 언어를 사용하면 컴파일러가 모호한 것으로 간주하는 일을 할 수 있지만 문제가 발생할 수 있음을 알 수 있도록 경고를 제공합니다.

이미 존재하는 모든 코드 때문에 더 이상 오류를 만들 수 없습니다.

나는 그것이 오류가되어야한다는 것에 대해 당신과 함께 있습니다. 컴파일러가 일부 경고를 오류로 업그레이드 할 옵션/프로필이 있어야 할 수도 있습니다.

업데이트: 그들이 소개했을 때 주장하다 기존 코드와 유사한 잠재적 호환성 문제가있는 1.4의 키워드는 소스 모드를 "1.4"로 명시 적으로 설정 한 경우에만 사용할 수 있습니다.. 새로운 소스 모드 "Java 7"에서 IT를 오류로 만들 수 있다고 생각합니다. 그러나 나는 그들이 일으킬 모든 번거 로움을 고려할 때 그들이 그렇게 할 것이라고 의심합니다. 다른 사람들이 지적했듯이, 혼란스러운 코드를 작성하는 것을 막을 필요는 없습니다. 그리고 Java에 대한 언어 변경은이 시점에서 엄격하게 필요한 것으로 제한되어야합니다.

짧은 대답 - 언어는 그것을 허용하므로 오류가 아닙니다.

오류가 아닌 것과 동일한 논리의 경우 :

public class X
{
    public static void foo()
    {
    }

    public void bar()
    {
        foo(); // no need to do X.foo();
    }
}

컴파일러의 관점에서 정말로 중요한 것은 기호를 해결할 수 있다는 것입니다. 정적 방법의 경우 특정 객체와 관련이 없기 때문에 어떤 클래스를 찾아야하는지 알아야합니다. Java의 디자이너는 분명히 객체의 클래스를 결정할 수 있기 때문에 객체의 모든 인스턴스에서 해당 객체의 정적 메소드 클래스를 해결할 수 있다고 결정했습니다. 그들은 @tofubeer의 관찰에 의해 흔들린 것을 허용하여 프로그래머에게 편의를 제공하기로 선택했습니다. 다른 언어 디자이너들은 다른 선택을했습니다. 나는 아마 후자 캠프에 빠졌을 것입니다. 그러나 그것은 나에게 큰 거래는 아닙니다. 아마도 @tofubeer가 언급 한 사용법을 허용 할 것이지만 인스턴스 변수에서 액세스 할 수없는 것이 덜 적절하다는 내 입장을 허용 한 것은 아마도 내 입장을 허용했습니다.

사양의 일부이기 때문에 오류는 아니지만 분명히 우리 모두가 추측 할 수있는 이론적 근거에 대해 묻습니다.

내 생각에 이것의 출처는 실제로 클래스의 메소드가 번거 로움없이 동일한 클래스에서 정적 메소드를 호출 할 수 있도록하는 것입니다. X () 호출은 합법적이기 때문에 (자체 클래스 이름이 없어도)이 this.x () 호출도 합법적이어야하므로 모든 물건을 통한 전화도 합법화되었습니다.

또한 사용자가 상태를 변경하지 않으면 개인 기능을 정적으로 전환하도록 장려합니다.

게다가, 컴파일러는 일반적으로 직접 오류로 이어질 수있는 방법이 없을 때 오류를 선언하지 않으려 고 노력합니다. 정적 방법은 상태를 변경하거나 호출 객체에 대한 관리가 변경되지 않기 때문에 실제 오류 (혼란)를 허용하지 않습니다. 경고로 충분합니다.

인스턴스 변수 참조의 목적은 정적을 동봉하는 유형을 제공하는 것입니다. 인스턴스를 통해 정적을 호출하는 바이트 코드를 보면 staticMethod 또는 enclosingClass.staticMethod는 동일한 Intatic 메소드 바이트 바이트 코드를 생성합니다. 인스턴스에 대한 참조가 나타나지 않습니다.

왜 거기에있는 이유도 있습니다. 수업을 사용하는 한. 그리고 인스턴스를 통해 당신은 미래의 혼란을 피하는 데 도움이 될 것입니다.

아마도 당신은 당신의 IDE에서 그것을 변경할 수 있습니다 (Eclipse preverences-> java-> compiler-> 오류/경고).

옵션이 없습니다. Java에서 (다른 많은 Lang과 마찬가지로) 해당 클래스의 클래스 이름 또는 인스턴스 객체를 통해 클래스의 모든 정적 멤버에게 액세스 할 수 있습니다. 그것은 당신과 당신이 사용해야하는 소프트웨어 솔루션에 달려있어 더욱 가독성을 제공합니다.

나는 이것을 고려한다 :

instanceVar.staticMethod();

이것에 대한 속기 :

instanceVar.getClass().staticMethod();

항상 이것을해야한다면 :

SomeClass.staticMethod();

그러면 정적 방법에 대한 상속을 활용할 수 없습니다.

즉, 인스턴스를 통해 정적 메소드를 호출함으로써 인스턴스가 컴파일 타임에 어떤 콘크리트 클래스인지 알 필요가 없으며, 상속 체인을 따라 staticMethod ()를 구현하는 것만으로 만 있습니다.

편집 :이 답변은 잘못되었습니다. 자세한 내용은 의견을 참조하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top