Nice programing

인스턴스를 통해 정적 메소드를 호출하지 않는 이유는 Java 컴파일러에 대한 오류입니까?

nicepro 2020. 10. 19. 12:45
반응형

인스턴스를 통해 정적 메소드를 호출하지 않는 이유는 Java 컴파일러에 대한 오류입니까?


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

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

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

편집하다:

명확하게 말하면 질문은 스레드와 관련이 없습니다. 나는 이것을 논의 할 때 쓰레드 예제가 종종 주어질 수 있다는 것을 알고 있습니다. 그러나 실제로 문제는 그러한 사용법이 항상 넌센스이며 그러한 호출을 (유능하게) 작성하고 의미 할 수 없다는 것입니다. 이러한 유형의 메서드 호출의 모든 예는 barmy입니다. 또 다른 것 :

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

각 String 인스턴스가 "String valueOf (int i)"메서드와 함께 제공되는 것처럼 보이게합니다.


기본적으로 Java 디자이너가 언어를 설계 할 때 실수를했다고 생각하며 관련된 호환성 문제로 인해 수정하기에는 너무 늦었습니다. 예, 매우 잘못된 코드로 이어질 수 있습니다. 예, 피해야합니다. 예, IDE가 오류, IMO로 처리하도록 구성되어 있는지 확인해야합니다. 언어를 직접 디자인 한 적이 있다면 피해야 할 일의 예로서이를 염두에 두십시오. :)

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은 완전히 무시됩니다.


왜 오류 여야합니까? 인스턴스는 모든 정적 메서드에 액세스 할 수 있습니다. 정적 방법은 인스턴스의 상태를 변경할 수 없습니다 (에 노력하고 있다 컴파일 오류).

The problem with the well-known example that you give is very specific to threads, not static method calls. It looks as though you're getting the activeCount() for the thread referred to by thread, but you're really getting the count for the calling thread. This is a logical error that you as a programmer are making. Issuing a warning is the appropriate thing for the compiler to do in this case. It's up to you to heed the warning and fix your code.

EDIT: I realize that the syntax of the language is what's allowing you to write misleading code, but remember that the compiler and its warnings are part of the language too. The language allows you to do something that the compiler considers dubious, but it gives you the warning to make sure you're aware that it could cause problems.


They cannot make it an error anymore, because of all the code that is already out there.

I am with you on that it should be an error. Maybe there should be an option/profile for the compiler to upgrade some warnings to errors.

Update: When they introduced the assert keyword in 1.4, which has similar potential compatibility issues with old code, they made it available only if you explicitly set the source mode to "1.4". I suppose one could make a it an error in a new source mode "java 7". But I doubt they would do it, considering that all the hassle it would cause. As others have pointed out, it is not strictly necessary to prevent you from writing confusing code. And language changes to Java should be limited to the strictly necessary at this point.


Short answer - the language allows it, so its not an error.


Likely for the same logical that makes this not an error:

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

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

The really important thing, from the compiler's perspective, is that it be able to resolve symbols. In the case of a static method, it needs to know what class to look in for it -- since it's not associated with any particular object. Java's designers obviously decided that since they could determine the class of an object, they could also resolve the class of any static method for that object from any instance of the object. They choose to allow this -- swayed, perhaps, by @TofuBeer's observation -- to give the programmer some convenience. Other language designers have made different choices. I probably would have fallen into the latter camp, but it's not that big of a deal to me. I probably would allow the usage that @TofuBeer mentions, but having allowed it my position on not allowing access from an instance variable is less tenable.


It isn't an error because it's part of the spec, but you're obviously asking about the rationale, which we can all guess at.

My guess is that the source of this is actually to allow a method in a class to invoke a static method in the same class without the hassle. Since calling x() is legal (even without the self class name), calling this.x() should be legal as well, and therefore calling via any object was made legal as well.

This also helps encourage users to turn private functions into static if they don't change the state.

Besides, compilers generally try to avoid declaring errors when there is no way that this could lead to a direct error. Since a static method does not change the state or care about the invoking object, it does not cause an actual error (just confusion) to allow this. A warning suffices.


The purpose of the instance variable reference is only to supply the type which encloses the static. If you look at the byte code invoking a static via instance.staticMethod or EnclosingClass.staticMethod produces the same invoke static method bytecode. No reference to the instance appears.

The answer as too why it's in there, well it just is. As long as you use the class. and not via an instance you will help avoid confusion in the future.


Probably you can change it in your IDE (in Eclipse Preferences -> Java -> Compiler -> Errors/Warnings)


There's not option for it. In java (like many other lang.) you can have access to all static members of a class through its class name or instance object of that class. That would be up to you and your case and software solution which one you should use that gives you more readability.


I just consider this:

instanceVar.staticMethod();

to be shorthand for this:

instanceVar.getClass().staticMethod();

If you always had to do this:

SomeClass.staticMethod();

then you wouldn't be able to leverage inheritance for static methods.

That is, by calling the static method via the instance you don't need to know what concrete class the instance is at compile time, only that it implements staticMethod() somewhere along the inheritance chain.

EDIT: This answer is wrong. See comments for details.

참고URL : https://stackoverflow.com/questions/610458/why-isnt-calling-a-static-method-by-way-of-an-instance-an-error-for-the-java-co

반응형