Java가 정적 메소드 대체를 허용하지 않는 이유는 무엇입니까?


534

정적 메소드를 대체 할 수없는 이유는 무엇입니까?

가능하면 예를 사용하십시오.


3
대부분의 OOP 언어는 이것을 허용하지 않습니다.
jmucchiello

7
@ jmucchiello : 내 대답을 참조하십시오. 나는 당신과 같은 생각을했지만 Ruby / Smalltalk 'class'메소드에 대해 배웠고 이것을 수행하는 다른 진정한 OOP 언어가 있습니다.
케빈 브록

5
@jmucchiello 대부분의 OOP 언어는 실제 OOP 언어가 아닙니다 (Smalltalk 생각)
mathk


1
Java가 컴파일 타임에 정적 메소드에 대한 호출을 해결하기 때문일 수 있습니다. 그래서 심지어는 작성한 경우 Parent p = new Child()다음 p.childOverriddenStaticMethod()컴파일러는 그것을 해결할 Parent.childOverriddenStaticMethod()참조 유형을 보면.
Manoj

답변:


494

재정의는 클래스의 인스턴스가 있어야합니다. 다형성의 요점은 클래스를 서브 클래스 할 수 있고 해당 서브 클래스를 구현하는 객체는 수퍼 클래스에 정의 된 (및 서브 클래스에서 재정의 된) 동일한 메소드에 대해 다른 동작을 갖습니다. 정적 메소드는 클래스의 인스턴스와 연관되지 않으므로 개념을 적용 할 수 없습니다.

이에 영향을주는 Java 설계를 추진할 때 고려해야 할 두 가지 사항이 있습니다. 하나는 성능에 대한 우려였습니다. 스몰 토크가 너무 느려서 (쓰레기 수거 및 다형성 호출이 그 일부 임) 많은 비판이 있었으며 Java 제작자는이를 피하기로 결정했습니다. 또 다른 하나는 Java의 대상이 C ++ 개발자라는 결정이었습니다. 정적 메소드가 작동하는 방식으로 작동하게 만드는 것은 C ++ 프로그래머에게 친숙한 이점이 있었으며 호출 할 메소드를 파악하기 위해 런타임까지 기다릴 필요가 없기 때문에 매우 빠릅니다.


18
...하지만 Java에서는 "올바른"것입니다. 예를 들어, 스칼라의 "정적 클래스"( objects)는 메소드 오버로드를 허용합니다.

32
Objective-C는 클래스 메소드를 대체 할 수도 있습니다 .
Richard

11
컴파일 타입 계층과 런타임 타입 계층이 있습니다. 정적 메소드 호출이 런타임 유형 계층 구조를 사용하지 않는 이유를 묻는 것이 가장 합리적입니다. Java에서 이것은 객체 ( obj.staticMethod()) 에서 정적 메소드를 호출 할 때 발생 하며 컴파일 타임 유형이 허용됩니다. 정적 호출이 클래스의 비 정적 메소드에있는 경우 "현재"오브젝트는 클래스의 파생 된 유형일 수 있지만 파생 된 유형에 정의 된 정적 메소드는 고려되지 않습니다 (실행 시간 유형에 있음) 계층).
Steve Powell

18
나는 그 개념을 적용 할 수 없다는 것이 사실 이 아니라는 것을 분명히했다 .
Steve Powell

13
이 답변은 정확하지만 OP의 기대치를 충족시키기 위해 어떻게해야하는지 또는 여기에서 나 자신과 다른 사람들이 어떻게해야하는지보다는 "어떻게"에 더 가깝습니다. "그 방법이 아닌"정적 메소드를 대체 할 수없는 구체적인 이유는 없습니다. 나는 그것이 개인적으로 결함이라고 생각합니다.
RichieHH

186

개인적으로 나는 이것이 Java 디자인의 결함이라고 생각합니다. 예, 예, 정적이 아닌 메소드는 인스턴스에 첨부되는 반면 정적 메소드는 클래스 등에 첨부된다는 것을 이해합니다. 여전히 다음 코드를 고려하십시오.

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

이 코드는 예상대로 작동하지 않습니다. 즉, SpecialEmployee는 일반 직원과 마찬가지로 2 %의 보너스를받습니다. 그러나 "정적"을 제거하면 SpecialEmployee는 3 %의 보너스를받습니다.

(실제로이 예제는 실제 코딩 방식이 아니라면 보너스 멀티 플라이어가 하드 코딩 된 것이 아닌 데이터베이스에 있기를 원할 것입니다. 그러나 그것은 예제를 많이 사용하고 싶지 않기 때문입니다. 요점과 관련이없는 코드).

getBonusMultiplier를 정적으로 만들고 싶을 수도 있습니다. 각 범주에 직원의 인스턴스가 없어도 모든 범주의 직원에 대해 보너스 승수를 표시 할 수 있습니다. 그러한 예제 인스턴스를 찾는 시점은 무엇입니까? 새 범주의 직원을 만들면서 아직 할당 된 직원이없는 경우 어떻게합니까? 이것은 논리적으로 정적 함수입니다.

그러나 작동하지 않습니다.

그리고 예, 그렇습니다. 위 코드를 다시 작성하여 작동하게하는 방법에는 여러 가지가 있습니다. 내 요점은 해결할 수없는 문제를 일으키는 것이 아니라, 합리적인 사람이 기대하는 것처럼 언어가 작동하지 않기 때문에 경고하지 않는 프로그래머를위한 함정을 만드는 것입니다.

아마도 OOP 언어 용 컴파일러를 작성하려고했을 때 정적 함수를 재정의 할 수 없도록 구현하는 이유를 빨리 알 수있을 것입니다.

또는 Java가 이런 식으로 동작하는 이유가있을 수 있습니다. 누구나이 행동으로 장점을 지적 할 수 있습니까? 이로 인해 더 쉬운 문제 범주가 있습니까? Java 언어 사양을 가리켜 서 "이것이 어떻게 작동하는지 문서화되어 있습니다"라고 말하지 마십시오. 나도 알아 그러나 왜 이런 식으로 행동해야 하는가? ( "제대로 작동하는 것이 너무 어려웠습니다"라는 것 외에도 ...)

최신 정보

@VicKirk : Java가 정적을 처리하는 방식에 맞지 않기 때문에 이것이 "나쁜 디자인"이라는 것을 의미한다면 제 대답은 "물론, 물론입니다."입니다. 원래 게시물에서 말했듯이 작동하지 않습니다. 그러나 이것이 작동하는 언어, 근본적으로 가상 함수처럼 정적 변수를 재정의 할 수있는 언어에 근본적으로 잘못된 것이 있다는 의미에서 나쁜 디자인을 의미하는 경우 어떻게 든 모호성을 유발하거나 불가능할 수 있습니다 효율적으로 또는 그와 같은 일부를 구현하면 "왜? 개념에 어떤 문제가 있습니까?"라고 대답합니다.

내가 제공하는 예는하고 싶은 매우 자연스러운 일이라고 생각합니다. 인스턴스 데이터에 의존하지 않는 함수가 있고 인스턴스와 독립적으로 호출하고 인스턴스 메소드 내에서 호출하려는 클래스가 있습니다. 왜 이것이 작동하지 않습니까? 나는이 상황에 수년에 걸쳐 상당한 횟수를 겪었습니다. 실제로 함수를 가상으로 만든 다음 더미 인스턴스로 가상 메소드에 대한 호출을 전달하는 정적 메소드가 인생의 유일한 목적인 정적 메소드를 작성하여 문제를 해결했습니다. 그것은 거기에 도착하는 매우 원형 교차로처럼 보인다.


11
@Bemrose :하지만 그건 내 요점입니다. 왜 그렇게하지 않아야합니까? 어쩌면 "정적"이 무엇을해야하는지에 대한 직관적 인 개념은 당신과 다를 수 있지만, 기본적으로 정적은 인스턴스 데이터를 사용하지 않기 때문에 정적으로 할 수있는 메소드라고 생각합니다. 인스턴스와 독립적으로 호출합니다. 정적은 클래스에 명확하게 연결되어 있습니다 .Integer.valueOf는 Integers에 연결되고 Double.valueOf는 Doubles에 연결될 것으로 예상합니다.
Jay

9
@ewernli & Bemrose : 네, 그렇습니다. 나는 그것을 토론하고 있지 않다. 내 예제의 코드가 작동하지 않으므로 물론 작성하려고하지 않습니다. 내 질문은 왜 그런 식입니다. (이것이 우리가 의사 소통을하지 않는 대화 중 하나로 바뀌는 것이 두려운 일입니다. "실례합니다, 세일즈맨 씨,이 중 하나를 빨간색으로받을 수 있습니까?" "아니오, 5 달러예요." 5 달러인데 빨간 것을 얻을 수 있나요? ""저기, 5 달러라고 말씀 드렸습니다. ""좋아요, 가격은 알고 있지만 색상에 대해 묻고있었습니다. ""이미 가격을 말 했어요! " 등)
Jay

6
궁극적 으로이 코드는 혼란 스럽다고 생각합니다. 인스턴스가 매개 변수로 전달되는지 고려하십시오. 그런 다음 런타임 인스턴스가 어떤 정적 메소드를 호출해야하는지 지시해야합니다. 기본적으로 기존 인스턴스와 평행 한 별도의 계층 구조를 만듭니다. 서브 클래스가 비정 적과 동일한 메소드 서명을 정의하면 어떻게 될까요? 나는 규칙이 일을 매우 복잡하게 할 것이라고 생각합니다. Java가 피하려고하는 것은 바로 이런 종류의 언어 합병증입니다.
Yishai

6
@Yishai : RE "런타임 인스턴스는 어떤 정적 메소드가 호출되는지를 지시합니다": 정확합니다. 왜 가상으로 할 수있는 정적으로 아무것도 할 수 없는지 모르겠습니다. "별도의 계층 구조": 같은 계층 구조의 일부로 만듭니다. 정적이 동일한 계층에 포함되지 않는 이유는 무엇입니까? "하위 클래스는 같은 서명을 비 정적으로 정의합니다.": 하위 클래스가 서명이 같지만 반환 유형이 다른 함수를 재정의하는 것이 불법 인 것처럼 불법적이라고 가정합니다. 부모는 던지거나 더 좁은 범위를 갖습니다.
Jay

28
제이는 요점이 있다고 생각합니다. 정적을 재정의 할 수 없다는 것을 알았을 때도 놀랐습니다. 부분적으로 내가 메소드가있는 A를 가지고 someStatic()있고 B 가 A를 확장하면 A 의 메소드에 B.someMethod() 바인딩 합니다. 이후 someStatic()에 B에 추가 하면 호출 코드는 호출 코드를 A.someStatic()다시 컴파일 할 때까지 계속 호출 합니다. 또한 컴파일되지 않은 링크에서 바인딩되기 때문에 런타임 유형이 아닌 선언 된 유형의 bInstance 를 bInstance.someStatic()사용 한다는 사실에 놀랐습니다 . 따라서 B.someStatic ()이 있으면 A.someStatic ()을 호출합니다. A bInstance; ... bInstance.someStatic()
Lawrence Dol

42

짧은 대답은 : 그것은 가능하지만 Java는 그렇지 않습니다.

다음은 Java 의 현재 상태 를 보여주는 코드입니다 .

파일 Base.java:

package sp.trial;
public class Base {
  static void printValue() {
    System.out.println("  Called static Base method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Base method.");
  }
  void nonLocalIndirectStatMethod() {
    System.out.println("  Non-static calls overridden(?) static:");
    System.out.print("  ");
    this.printValue();
  }
}

파일 Child.java:

package sp.trial;
public class Child extends Base {
  static void printValue() {
    System.out.println("  Called static Child method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Child method.");
  }
  void localIndirectStatMethod() {
    System.out.println("  Non-static calls own static:");
    System.out.print("  ");
    printValue();
  }
  public static void main(String[] args) {
    System.out.println("Object: static type Base; runtime type Child:");
    Base base = new Child();
    base.printValue();
    base.nonStatPrintValue();
    System.out.println("Object: static type Child; runtime type Child:");
    Child child = new Child();
    child.printValue();
    child.nonStatPrintValue();
    System.out.println("Class: Child static call:");
    Child.printValue();
    System.out.println("Class: Base static call:");
    Base.printValue();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
    child.localIndirectStatMethod();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
    child.nonLocalIndirectStatMethod();
  }
}

이것을 실행하면 (Java 1.6을 사용하여 Eclipse에서 Mac에서 수행) 다음을 얻습니다.

Object: static type Base; runtime type Child.
  Called static Base method.
  Called non-static Child method.
Object: static type Child; runtime type Child.
  Called static Child method.
  Called non-static Child method.
Class: Child static call.
  Called static Child method.
Class: Base static call.
  Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
  Non-static calls own static.
    Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
  Non-static calls overridden(?) static.
    Called static Base method.

여기에서 유일한 놀람이 될 수 있습니다 (그리고 어떤 질문에 대한됩니다) 표시의 경우는 수하는 첫 번째 사례 :

"런타임 유형은 객체 인스턴스 ( obj.staticMethod())를 사용하여 호출 할 때 호출되는 정적 메소드를 결정하는 데 사용되지 않습니다 ."

그리고 마지막 경우 :

"클래스의 객체 메소드 내에서 정적 메소드를 호출 할 때 선택한 정적 메소드 는 객체의 런타임 유형을 정의하는 클래스가 아니라 클래스 자체에서 액세스 할 수 있는 메소드입니다."

객체 인스턴스로 호출

정적 호출은 컴파일 타임에 해결되지만 비 정적 메소드 호출은 런타임에 해결됩니다. 정적 메소드는 (부모로부터) 상속 되지만 (자식에 의해) 재정의 되지는 않습니다 . 당신이 달리 예상했다면 이것은 놀랍습니다.

객체 메소드 내에서 호출

객체 메소드 호출은 런타임 유형을 사용하여 해결되지만 정적 ( class ) 메소드 호출은 컴파일 시간 (선언) 유형을 사용하여 해결됩니다.

규칙 변경

이러한 규칙을 변경하여라는 예제의 마지막 호출에서 Child.printValue()컴파일러가 선언 된 객체 클래스로 컴파일 타임에 호출을 해결하는 대신 런타임에 정적 호출에 유형을 제공해야합니다. 문맥). 정적 호출은 오늘날 객체 메소드 호출과 마찬가지로 (동적) 유형 계층 구조를 사용하여 호출을 해결할 수 있습니다.

이것은 쉽게 할 수 있으며 (Java를 변경 한 경우 : -O) 전혀 부당한 것은 아니지만 몇 가지 흥미로운 고려 사항이 있습니다.

주요 고려 사항은 어떤 정적 메서드 호출을 수행 해야하는지 결정 해야한다는 것입니다.

현재 Java에는 obj.staticMethod()호출이 호출로 대체되는 언어 ObjectClass.staticMethod()(일반적으로 경고가 표시됨) 에이 "질투"가 있습니다 . [ 참고 : ObjectClass 의 컴파일 타임 유형입니다 obj.] 런타임 유형 의을 사용하여 이러한 방식으로 재정의 할 수 있습니다 obj.

그렇게하면 메소드 본문을 읽기가 더 어려워 질 것이다. 부모 클래스의 정적 호출은 동적으로 "재 라우팅" 될 수있다 . 이를 피하려면 클래스 이름으로 정적 메소드를 호출해야합니다. 이렇게하면 컴파일 타임 유형 계층 구조 (지금과 같이)로 호출이보다 명확하게 해결됩니다.

정적 메소드를 호출하는 다른 방법은 더 까다 롭습니다. 의 런타임 유형을 사용 this.staticMethod()하는 것과 같은 의미 여야합니다 . 그러나 이로 인해 기존 프로그램에서 두통이 발생할 수 있습니다 .obj.staticMethod()thisthis.method()

그래서 무의미한 통화는 staticMethod()어떻습니까? 나는 그들이 오늘날과 똑같이하고 지역 수업 맥락을 사용하여 무엇을 해야할지 결정하는 것이 좋습니다. 그렇지 않으면 큰 혼란이 생길 ​​것입니다. 물론 그것은 그것이 의미하는 method()것을 의미 this.method()하는 경우 method가 아닌 정적 메서드, 그리고 ThisClass.method()경우는 method정적 방법이었다. 이것은 또 다른 혼란의 근원입니다.

다른 고려 사항

우리가이 동작을 변경 (정적 호출 가능성이 동적으로 로컬이 아닌했다), 우리는 아마의 의미를 다시 방문 할 것 final, private그리고 protected예선과 (와) 같은 static클래스의 방법. 우리는 모두 메소드 private staticpublic final메소드가 재정의되지 않았으므로 컴파일 타임에 안전하게 해결 될 수 있으며 로컬 참조로 읽을 수 있도록 "안전" 하다는 사실에 익숙해 져야합니다.


"우리가 그렇게한다면 메소드 본문을 읽기가 더 어려워 질 것입니다. 부모 클래스의 정적 호출은 잠재적으로 동적으로"재 라우팅 "될 수 있습니다." 사실이지만, 이것은 일반적인 비 정적 함수 호출에서 정확히 발생합니다. 이것은 일상적인 가상 기능에 대한 긍정적 인 기능으로 일상적으로 선전되며 문제는 아닙니다.
Jay

25

실제로 우리는 틀렸다.
Java에서는 기본적으로 정적 메소드를 대체 할 수 없지만 Java에서 클래스 및 메소드 클래스의 문서를 자세히 살펴보면 다음 해결 방법으로 정적 메소드 대체를 에뮬레이트하는 방법을 여전히 찾을 수 있습니다.

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

결과 출력 :

0.02
0.02
0.02
0.03

우리가 달성하려고했던 것 :)

세 번째 변수 Carl을 RegularEmployee로 선언하고 SpecialEmployee의 인스턴스에 할당하더라도 첫 번째 경우 RegularEmployee 메서드를 호출하고 두 번째 경우에는 SpecialEmployee 메서드를 호출합니다

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

출력 콘솔을 살펴보십시오.

0.02
0.03

;)


9
그렇습니다. 리플렉션은 우리가 할 수있는 유일한 일입니다. 그러나 문제는 정확히 이것이 아닙니다 – 여기에있는 것이 유용합니다
Mr_and_Mrs_D

1
이 답변은 모든 Java 주제에서 지금까지 본 가장 큰 해킹입니다. 아직도 그것을 읽는 것은 재미 있었다 :)
Andrejs

19

정적 메소드는 JVM에 의해 전역으로 처리되며 오브젝트 인스턴스에는 전혀 바인딩되지 않습니다.

스몰 토크와 같은 언어에서와 같이 클래스 객체에서 정적 메소드를 호출 할 수 있다면 개념적으로 가능하지만 Java에서는 그렇지 않습니다.

편집하다

정적 메소드 를 오버로드 할 수 있습니다 . 그러나 클래스는 일류 객체가 아니기 때문에 정적 메서드를 재정 의 할 수 없습니다 . 리플렉션을 사용하여 런타임에 객체의 클래스를 가져올 수 있지만 얻은 객체는 클래스 계층 구조와 평행하지 않습니다.

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

수업에 대해 생각해 볼 수는 있지만 거기서 멈 춥니 다. 당신은 사용하여 정적 메소드를 호출하지 않는 clazz1.staticMethod(),하지만 사용 MyClass.staticMethod(). 정적 메소드는 오브젝트에 바인드되지 않으므로 정적 메소드에 대한 개념 this이나 개념이 없습니다 super. 정적 메소드는 전역 함수입니다. 결과적으로 다형성에 대한 개념도 없으므로 메서드 재정의는 의미가 없습니다.

그러나 MyClassSmalltalk (또는 한 의견에서 제안한 것처럼 JRuby 일 수도 있지만 JRuby에 대해서는 아는 바 없음)와 같이 메소드를 호출하는 런타임에 객체 인 경우 가능할 수 있습니다 .

아 그래 ... 한가지 더 객체를 통해 정적 메소드를 호출 할 수 obj1.staticMethod()있지만 실제로 구문 설탕은 MyClass.staticMethod()피해야합니다. 일반적으로 최신 IDE에서는 경고가 발생합니다. 그들이 왜이 지름길을 허용했는지 모르겠습니다.


5
루비와 같은 많은 현대 언어조차도 클래스 메소드를 가지고 있으며이를 대체 할 수 있습니다.
찬드라 세 카르

3
클래스는 Java에서 객체로 존재합니다. "클래스"클래스를 참조하십시오. myObject.getClass ()라고 말하면 적절한 클래스 객체의 인스턴스를 반환합니다.
Jay

5
수업 자체가 아닌 수업에 대한 "설명"만받을 수 있습니다. 그러나 그 차이는 미묘합니다.
ewernli

여전히 클래스가 있지만 클래스 로더 근처의 VM에 숨겨져 있으며 사용자는 거의 액세스 할 수 없습니다.
mathk

clazz2 instanceof clazz1제대로 사용하려면 대신을 사용할 수 있습니다 class2.isAssignableFrom(clazz1). 귀하의 예에서 true를 반환한다고 생각합니다.
Simon Forsberg

14

메소드의 재정의는 동적 디스패치에 의해 가능 합니다. 즉, 선언 된 객체 유형이 동작을 결정하지 않고 런타임 유형을 결정합니다.

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"

모두에도 불구 lassie하고이 kermit유형의 객체로 선언 Animal, 자신의 행동 (방법 .speak())에 따라 다릅니다 동적 파견 때문에만이 바인드 메소드 호출 .speak()런타임에 구현 -하지 컴파일시.

이제 static키워드가 이해되기 시작합니다. "정적"이라는 단어는 "동적"의 반의어입니다. 따라서 정적 메서드를 재정의 할 수없는 이유는 정적 멤버에 동적 디스패치가 없기 때문입니다. 정적은 문자 적으로 "동적 아님"을 의미하기 때문입니다. static키워드 가 동적으로 전달되어 재정의 될 수있는 경우 키워드는 더 이상 의미가 없습니다.


11

예. 실제로 Java는 정적 메소드를 대체 할 수 있으며 이론적으로 Java에서 정적 메소드를 대체하면 컴파일 및 실행이 원활하지만 Java의 기본 특성 인 다형성이 손실됩니다. 컴파일하고 실행하는 것은 불가능합니다. 당신은 당신의 대답을 얻을 것입니다. 예를 들어 클래스 동물과 정적 메소드 eat ()를 가지고 있고 서브 클래스의 정적 메소드를 재정의하면 Dog라고합니다. 그런 다음 어디서나 Dog 객체를 Animal Reference에 할당하고 Java Dog의 eat ()에 따라 eat ()를 호출하면 정적 동물의 eat ()가 호출됩니다.

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog's eat but it didn't
    }
}


Output Animal Eating

Java의 다형성 원칙에 따르면 출력은이어야 Dog Eating합니다.
그러나 다형성을 지원하기 위해 Java는 후기 바인딩을 사용하기 때문에 결과가 달랐습니다. 즉, 메소드는 런타임시에만 호출되지만 정적 메소드의 경우에는 호출되지 않습니다. 정적 메소드 컴파일러는 런타임이 아닌 컴파일 타임에 메소드를 호출하므로 참조에 따라 메소드를 얻습니다. 객체에 따라 참조를 포함하지 않으므로 정적 오버 링을 지원하지만 이론적으로는 그렇지 않습니다. '티.


3
객체에서 정적 메서드를 호출하는 것은 좋지 않습니다.
Dmitry Zagorulkin

6

재정의는 인스턴스 멤버가 다형성 동작을 지원하도록 예약되어 있습니다. 정적 클래스 멤버는 특정 인스턴스에 속하지 않습니다. 대신 정적 멤버는 클래스에 속하며 결과적으로 서브 클래스는 정적 멤버가 아닌 보호 및 퍼블릭 인스턴스 멤버 만 상속하므로 재정의가 지원되지 않습니다. 대체 접근법을 평가하기 위해 인터페이스 및 연구 팩토리 및 / 또는 전략 설계 패턴을 정의 할 수 있습니다.


1
이미 이것을 다루고있는 다른 대답을 읽지 않았으며 이것이 개념 수준에서 재정의 정적을 할인 할만 큼 충분한 이유가 아님을 분명히했습니다. 우리는 그것이 작동하지 않는다는 것을 알고 있습니다. 정적 메소드의 오버라이드를 원한다는 것은 완벽하게 깨끗하며 실제로 다른 많은 언어에서도 가능합니다.
RichieHH

Richard, 4 년 전에이 질문에 대한 답변을 받았을 때 대부분의 답변이 게시되지 않았다고 가정 해 봅시다. 내가주의 깊게 읽지 않았다고 주장 할 필요는 없습니다. 또한 Java와 관련하여 재정의에 대해서만 논의하고 있다는 것을 읽지 않았습니다. 다른 언어로 가능한 것을 누가 신경 쓰나요? 관련이 없습니다. 다른 곳으로 트롤을 이동하십시오. 귀하의 의견은이 스레드에 가치있는 것을 추가하지 않습니다.
Athens Holloway 14

6

Java (및 많은 OOP 언어)에서 모든 것을 말할 수는 없으며 일부는 정적이 아닙니다. 모든 메소드에는 매개 변수 및 유형의 고정 서명이 있습니다. 가상 메서드에는 첫 번째 매개 변수가 내포되어 있습니다. 즉 객체 자체에 대한 참조와 객체 내에서 호출되면 컴파일러가 자동으로 추가합니다 this.

정적 메소드에는 차이가 없습니다. 여전히 고정 된 서명이 있습니다. 그러나 static 메소드를 선언하여 컴파일러가 서명의 시작 부분에 암시 적 객체 매개 변수를 포함해서는 안된다고 명시 적으로 언급했습니다. 따라서 이것을 호출하는 다른 코드 는 스택의 객체에 대한 참조를 시도 해서는 안됩니다 . 그렇게하면 스택에서 매개 변수가 잘못된 위치에 (하나씩 이동) 있기 때문에 메소드 실행이 작동하지 않습니다.

이 둘의 차이 때문에; 가상 메소드는 항상 컨텍스트 오브젝트에 대한 참조를 가지 this므로 해당 오브젝트 인스턴스에 속하는 힙 내의 모든 것을 참조 할 수 있습니다. 그러나 정적 메소드의 경우 전달 된 참조가 없으므로 컨텍스트를 알 수 없으므로 해당 메소드는 오브젝트 변수 및 메소드에 액세스 할 수 없습니다.

Java가 정의를 변경하여 정적 또는 가상의 모든 메소드에 대해 오브젝트 컨텍스트가 전달되도록하려면 본질적으로 가상 메소드 만 갖습니다.

누군가가 op에 의견을 물었을 때-이 기능을 원하는 이유와 목적은 무엇입니까?

나는 OP에 의해 언급 된 것처럼 Ruby를 잘 모른다. 나는 약간의 연구를했다. Ruby 클래스에서 실제로는 특별한 종류의 객체이며 새로운 메소드를 (동적으로도) 만들 수 있다는 것을 알았습니다. 클래스는 Ruby에서 전체 클래스 객체이며 Java가 아닙니다. 이것은 Java (또는 C #)로 작업 할 때 받아 들여야 할 것입니다. C #에서 일부 동적 형식을 추가하지만 동적 언어는 아닙니다. 실제로 루비에는 내가 찾을 수있는 한 "정적"메소드가 없습니다.이 경우 싱글 톤 클래스 객체의 메소드입니다. 그런 다음이 싱글 톤을 새 클래스로 재정의 할 수 있으며 이전 클래스 객체의 메소드는 새 클래스에 정의 된 메소드를 호출합니다 (올바른?). 따라서 원래 클래스의 컨텍스트에서 메소드를 호출 한 경우 여전히 원래 정적 만 실행합니다. 그러나 파생 클래스에서 메서드를 호출하면 부모 또는 하위 클래스에서 메서드를 호출합니다. 흥미롭고 그 가치를 볼 수 있습니다. 다른 사고 패턴이 필요합니다.

Java로 작업하고 있으므로 그런 방식으로 조정해야합니다. 그들은 왜 이것을 했습니까? 글쎄, 아마도 사용 가능한 기술과 이해를 바탕으로 당시의 성능을 향상시킬 것입니다. 컴퓨터 언어는 끊임없이 발전하고 있습니다. 충분히 되돌아 가면 OOP와 같은 것이 없습니다. 앞으로 다른 새로운 아이디어가있을 것입니다.

편집 : 다른 의견. 이제 차이점을 보았고 Java / C # 개발자 자신으로서 Ruby와 같은 언어를 사용하는 경우 Java 개발자의 답변이 혼란 스러울 수있는 이유를 이해할 수 있습니다. Java static메소드는 Ruby class메소드 와 동일하지 않습니다 . Java 개발자는 Ruby / Smalltalk와 같은 언어를 주로 사용하는 사람들과 마찬가지로이를 이해하기가 어려울 것입니다. Java가 정적 메소드에 대해 이야기하는 또 다른 방법으로 "클래스 메소드"를 사용한다는 사실로 인해 이것이 어떻게 혼란 스러울 수 있는지 알 수 있지만 Ruby와 동일한 용어가 다르게 사용됩니다. Java에는 Ruby 스타일 클래스 메소드가 없습니다 (죄송합니다). 루비에는 C에서 볼 수 있듯이 실제로 오래된 절차 스타일 함수 인 Java 스타일 정적 메소드가 없습니다.

그건 그렇고-질문 주셔서 감사합니다! 나는 오늘 클래스 메소드 (Ruby style)에 대해 새로운 것을 배웠습니다.


1
물론, Java가 "Class"객체를 숨겨진 매개 변수로 정적 메소드에 전달할 수없는 이유는 없습니다. 그것은 그것을하기 위해 설계된 것이 아닙니다.
jmucchiello 2016 년

6

글쎄 ... 재정의 된 메소드가 Java에서 어떻게 작동 해야하는지 관점에서 생각하면 대답은 아니오입니다. 그러나 정적 메서드를 재정의하려고하면 컴파일러 오류가 발생하지 않습니다. 즉, 재정의를 시도해도 Java는 그 일을 멈추지 않습니다. 그러나 비 정적 메소드와 동일한 효과를 얻지 못합니다. Java에서 재정의한다는 것은 단순히 특정 메소드가 객체의 컴파일 타임 유형이 아닌 객체의 런타임 유형을 기반으로 호출됨을 의미합니다 (정의 된 정적 메소드의 경우). 알았어 ... 왜 이상한 행동을 하는가? 그것들은 클래스 메소드이기 때문에 컴파일 시간 유형 정보를 사용하여 컴파일 시간 동안 항상 액세스됩니다.

예제 : 정적 메서드를 재정의하려고하면 어떻게되는지 봅시다 :-

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

출력 :-
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

출력의 두 번째 줄을 확인하십시오. staticMethod가 재정의 된 경우이 줄은 런타임 유형의 객체에서 'staticMethod ()'를 'SuperClass'가 아닌 'SubClass'로 호출 할 때 세 번째 줄과 동일해야합니다. 이는 정적 메소드가 항상 컴파일 시간 유형 정보 만 사용하여 해결됨을 확인합니다.


5

일반적으로 런타임에 호출 할 메소드를 결정하는 좋은 방법이 없으므로 정적 메소드의 '재정의'를 허용하는 것은 의미가 없습니다. EmployeeE를 사용하면 RegularEmployee.getBonusMultiplier ()를 호출하면 어떤 메소드를 실행해야합니까?

Java의 경우 정적 메소드가 오브젝트 인스턴스를 통해 호출되는 한 정적 메소드를 '재정의'할 수있는 언어 정의를 상상할 수 있습니다. 그러나이 모든 일은 정규 클래스 메소드를 다시 구현하여 실제로 이점을 추가하지 않고 언어에 중복성을 추가하는 것입니다.


2
직관적으로 가상 함수처럼 작동해야한다고 생각합니다. B가 A를 확장하고 A와 B 모두에 doStuff라는 가상 함수가있는 경우 컴파일러는 A의 인스턴스가 A.doStuff를 사용해야하고 B의 인스턴스가 B.doStuff를 사용해야 함을 알고 있습니다. 정적 함수와 동일한 기능을 수행 할 수없는 이유는 무엇입니까? 결국, 컴파일러는 각 객체가 어떤 클래스인지 알고 있습니다.
Jay

Erm ... Jay, 정적 메소드를 인스턴스에서 호출 할 필요는 없습니다 (일반적으로 그렇지는 않음).
meriton

2
@meriton,하지만 더 쉬워요? 클래스 이름을 사용하여 정적 메서드를 호출하면 클래스에 적합한 메서드를 사용합니다.
CPerkins 2019

그러나 당신을 위해 무엇을하고 있는가. A.doStuff ()를 호출하면 "B extends A"에서 재정의 된 버전 또는 "C extends A"에서 재정의 된 버전을 사용해야합니다. 그리고 C 또는 B가 있다면 어쨌든 해당 버전을 호출하고 있습니다.
PSpeed

@meriton : 정적 메소드는 일반적으로 인스턴스와 함께 호출되지 않는 것이 사실이지만, 현재 Java 디자인에서 그러한 호출이 유용하지 않기 때문입니다! 대안 디자인이 더 나은 아이디어라고 생각합니다. BTW는 매우 실제적으로 정적 함수는 아주 일상적으로 인스턴스와 함께 호출됩니다. 가상 함수 내에서 정적 함수를 호출 할 때. 그런 다음 this.function (), 즉 현재 인스턴스를 암시 적으로 얻습니다.
Jay

5

재정의함으로써 객체 유형에 따라 다형성을 만들 수 있습니다. 정적 메소드는 객체와 관련이 없습니다. 따라서 java는 정적 메소드 재정의를 지원할 수 없습니다.


5

Jay의 의견 ( https : //.com/a/2223803/1517187 )을 좋아 합니다.
나는 이것이 Java의 나쁜 디자인이라는 것에 동의합니다.
다른 많은 언어들은 이전 주석에서 볼 수 있듯이 정적 메서드 재정의를 지원합니다. 제이도 나와 같은 델파이에서 자바로 왔다고 생각합니다.
델파이 (Object Pascal)는 OOP를 구현 한 최초의 언어였습니다.
과거에 상용 GUI 제품을 작성하는 유일한 언어 였기 때문에 많은 사람들이 그 언어에 대한 경험이 있었음이 분명합니다. 그리고-델파이에서는 정적 메소드를 오버라이드 할 수 있습니다. 실제로 델파이의 정적 메소드는 "클래스 메소드"라고하며 델파이는 초기 바인딩이있는 메소드 인 "델파이 정적 메소드"라는 개념이 다릅니다. 후기 바인딩을 사용해야하는 메소드를 대체하려면 "가상"지시문을 선언하십시오. 매우 편리하고 직관적이어서 Java에서 이것을 기대할 것입니다.


3

정적 메서드를 재정의하려면 어떻게해야합니까? 인스턴스를 통해 정적 메소드를 호출 할 수 없습니다.

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

편집 : 불행히도 언어 디자인에 대한 감독을 통해 인스턴스를 통해 정적 메서드를 호출 할 수 있습니다 . 일반적으로 아무도 그렇게하지 않습니다. 내 잘못이야.


8
"인스턴스를 통해 정적 메소드를 호출 할 수 없습니다"실제로 Java의 단점 중 하나는 매우 나쁜 아이디어이지만 인스턴스를 통해 정적 메소드를 호출 할 수 있다는 것입니다.
Powerlord

1
참조 : 실제로 자바는 정적 멤버는 인스턴스를 통해 액세스 할 수 있도록하지 자바에서 정적 변수를
리처드 JP 르 구엔을

적절한 최신 IDE는 그렇게 할 때 경고를 생성하므로 Oracle은 이전 버전과의 호환성을 유지할 수 있지만 최소한 잡을 수 있습니다.
Gimby

1
인스턴스를 통해 정적 메소드를 호출 할 수 있다는 것은 개념적으로 잘못된 것이 없습니다. 이것은 엉망으로 만들기 위해 엉망입니다. Date 인스턴스와 같은 것이 호출 인터페이스를 통해 인스턴스 데이터를 함수에 전달하는 자체 정적 메서드를 호출하지 않아야하는 이유는 무엇입니까?
RichieHH

@RichieHH 그것은 그들이 괴롭히는 것이 아닙니다. 문제는 선언 된 유형의 변수가있는 곳 variable.staticMethod()대신에 호출이 허용되는 이유입니다 . 언어 디자인이 잘못되었다는 데 동의합니다. Class.staticMethod()variableClass
fishinear

3

Java에서 재정의한다는 것은 특정 메소드가 컴파일 타임 유형이 아닌 객체의 런타임 유형을 기반으로 호출됨을 의미합니다 (재정의 된 정적 메소드의 경우). 정적 메서드는 클래스 메서드이므로 인스턴스 메서드가 아니기 때문에 정적 메서드의 특성으로 인해 특정 클래스에 속하기 때문에 어떤 참조가 어떤 개체 또는 인스턴스를 가리키고 있는지와는 아무런 관련이 없습니다. 서브 클래스에서 다시 선언 할 수는 있지만 서브 클래스는 부모 클래스의 정적 메소드에 대해 아무것도 알지 못합니다. 왜냐하면 내가 말했듯이 그것이 선언 된 클래스에만 한정되기 때문입니다. 객체 참조를 사용하여 객체에 액세스하는 것은 Java 설계자가 제공하는 추가의 자유 일 뿐이므로 더 자세한 내용과 예제를 제한하는 경우에만 해당 관행을 중단한다고 생각해서는 안됩니다 http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html


3

재정의하면 동적 다형성이 달성됩니다. 정적 메서드를 재정의한다고 말하면 사용하려는 단어가 모순됩니다.

정적은 말합니다-컴파일 시간, 재정의는 동적 다형성에 사용됩니다. 둘 다 본질적으로 반대이므로 함께 사용할 수 없습니다.

동적 다형성 동작은 프로그래머가 객체를 사용하고 인스턴스 메소드에 액세스 할 때 발생합니다. JRE는 사용중인 객체의 종류에 따라 다른 클래스의 다른 인스턴스 메소드를 매핑합니다.

정적 메소드를 재정의한다고 말할 때 정적 메소드는 컴파일 할 때 링크 될 클래스 이름을 사용하여 액세스하므로 런타임에 정적 메소드와 메소드를 링크하는 개념이 없습니다. 따라서 정적 메서드 자체를 "재정의"하는 용어는 의미가 없습니다.

참고 : 객체로 클래스 메소드에 액세스하더라도 Java 컴파일러는 여전히 지능적이며 정적 링크를 수행합니다.


런타임에 정적 메소드가 실제로 포함하는 클래스의 인스턴스에서 호출되는 많은 인스턴스에서 이는 사실이 아니므로 호출 할 함수의 인스턴스를 판별하는 것이 완벽하게 가능합니다.
RichieHH

static은 컴파일 시간을 의미하지 않으며 static은 특정 객체가 아닌 클래스에 바인딩되어 있음을 의미합니다. 정적 Box.createBox보다 더 의미있는 것을 제외하고 클래스 팩토리를 만드는 것보다 의미가 BoxFactory.createBox없으며, 예외를 던지지 않고 오류 검사 구성을해야 할 때 피할 수없는 패턴입니다 (생성자는 실패 할 수 없으며 프로세스 / 던지기 만 죽일 수 있음) 정적 메소드는 실패시 null을 반환하거나 hastebin.com/codajahati.java 와 같은 것을 작성하기 위해 성공 / 오류 콜백을 허용 할 수도 있습니다.
Dmitry

2

이 질문에 대한 답은 간단합니다. static으로 표시된 메소드 또는 변수는 클래스에만 속하므로 정적 메소드는 수퍼 클래스에만 속하기 때문에 서브 클래스에서 상속 될 수 없습니다.


1
안녕하세요 G4uKu3_Gaurav. 기여하기로 결정 해 주셔서 감사합니다. 그러나 우리는 일반적으로 이것보다 더 길고 자세한 답변을 기대합니다.
DJClayworth 2016 년

@DJClayworth 당신은 자세한 답변 geeksforgeeks.org/…
g1ji

링크 주셔서 감사합니다. 실제로 나는 사이트에 새로 온 사람들에게 도움이되고, 질문에 대한 답변이 필요하지 않기 때문에 사이트에 익숙하지 않은 사람들에게 사이트가 어떻게 작동하는지 설명하기 위해 여기 있습니다.
DJClayworth 2016 년

1

쉬운 해결책 : 싱글 톤 인스턴스를 사용하십시오. 재정의와 상속을 허용합니다.

시스템에는 SingletonsRegistry 클래스가 있는데,이 클래스는 전달 된 클래스의 인스턴스를 반환합니다. 인스턴스가 없으면 작성됩니다.

Haxe 언어 수업 :

package rflib.common.utils;
import haxe.ds.ObjectMap;



class SingletonsRegistry
{
  public static var instances:Map<Class<Dynamic>, Dynamic>;

  static function __init__()
  {
    StaticsInitializer.addCallback(SingletonsRegistry, function()
    {
      instances = null;
    });

  } 

  public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
  {
    if (instances == null) {
      instances = untyped new ObjectMap<Dynamic, Dynamic>();      
    }

    if (!instances.exists(cls)) 
    {
      if (args == null) args = [];
      instances.set(cls, Type.createInstance(cls, args));
    }

    return instances.get(cls);
  }


  public static function validate(inst:Dynamic, cls:Class<Dynamic>)
  {
    if (instances == null) return;

    var inst2 = instances[cls];
    if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
  }

}

아주 멋진, 내가 :)이 Haxe 프로그래밍 언어에 대해 들어 이번이 처음이다
cyc115은

1
이것은 클래스 자체에서 정적 메소드로 Java에서 훨씬 더 잘 구현됩니다. Singleton.get(). 레지스트리는 보일러 플레이트 오버 헤드이며 클래스에서 GC를 배제합니다.
Lawrence Dol

당신이 옳습니다, 그것은 고전적인 해결책입니다. 왜 내가 레지스트리를 선택했는지 정확히 기억하지 못합니다. 어쩌면이 결과를 이끌어 낸 사고의 틀이 있었을 것입니다.
Raivo Fishmeister

1

정적 메소드, 변수, 블록 또는 중첩 클래스 는 객체가 아닌 전체 클래스에 속합니다 .

Java의 메소드는 객체 / 클래스의 동작을 노출시키는 데 사용됩니다. 여기서 메소드가 정적 이므로 (즉, 정적 메소드는 클래스의 동작 만 나타냅니다.) 전체 클래스의 동작을 변경 / 재정의 하면 객체 지향 프로그래밍의 기본 기둥 중 하나 인 높은 응집력 을 위반하게됩니다. . (생성자는 Java에서 특별한 종류의 메소드임을 기억하십시오.)

높은 응집력 -하나의 클래스에는 하나의 역할 만 있어야합니다. 예를 들어 : 자동차 클래스는 자전거, 트럭, 비행기 등이 아닌 자동차 객체 만 생성해야합니다. 그러나 자동차 클래스에는 자체 기능 만있는 일부 기능 (동작)이있을 수 있습니다.

따라서 자바 프로그래밍 언어를 디자인하는 동안. 언어 설계자들은 개발자들이 본질적으로 메소드를 정적으로 만 만들면 클래스의 일부 동작을 스스로 유지할 수 있다고 생각했습니다.


아래 조각 코드는 정적 메서드를 재정의하려고 시도하지만 컴파일 오류가 발생하지 않습니다 .

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

여기에서 메소드를 재정의하는 것이 아니라 다시 선언 하기 때문입니다. Java를 사용하면 메소드를 다시 선언 할 수 있습니다 (정적 / 비 정적).

Car 클래스의 getVehileNumber () 메소드에서 static 키워드를 제거하면 컴파일 오류가 발생 합니다. Vehicle 클래스에만 속하는 정적 메소드의 기능 을 변경 하려고하기 때문입니다.

또한 getVehileNumber ()가 final 로 선언 되면 코드가 컴파일되지 않습니다. final 키워드는 프로그래머가 메소드를 다시 선언하지 못하도록 제한하기 때문입니다.

public static final int getVehileNumber() {
return VIN;     }

전체적으로 정적 메서드를 사용할 위치는 소프트웨어 디자이너에게 달려 있습니다. 개인적으로 클래스의 인스턴스를 만들지 않고 정적 메서드를 사용하여 일부 작업을 수행하는 것을 선호합니다. 둘째, 외부 세계에서 클래스의 행동을 숨길 수 있습니다.


1

다음은 간단한 설명입니다. 정적 메소드는 클래스와 연관되고 인스턴스 메소드는 특정 오브젝트와 연관됩니다. 재정의를 통해 특정 개체와 관련된 재정의 된 메서드의 다른 구현을 호출 할 수 있습니다. 따라서 객체와 관련이 없지만 클래스 자체와 관련된 정적 메서드를 재정의하는 것은 직관적이지 않습니다. 따라서 정적 메소드는 호출하는 객체에 따라 재정의 할 수 없으며 항상 생성 된 클래스와 연결됩니다.


public abstract IBox createBox();내부 IBox 인터페이스 를 사용하는 것이 어떻게 직관적 입니까? Box는 IBox를 구현하여 createBox를 재정의하고 객체를 생성하여 유효한 IBox를 만들거나 그렇지 않으면 null을 반환합니다. 생성자는 "널 (null)"을 반환 할 수 없으므로 (1) 모든 곳에서 예외를 사용하거나 (지금 우리가하는 일) (2) 앞서 말한 것을 수행하지만 초보자 나 전문가에게는 의미가없는 팩토리 클래스를 만들어야합니다. 자바의 (지금 우리도 할). 정적 구현되지 않은 메소드가이를 해결합니다.
Dmitry

-1

이제 위의 답변을 보면 모든 사람들이 정적 메소드를 재정의 할 수 없다는 것을 알고 있지만 서브 클래스에서 정적 메소드에 액세스 하는 개념에 대해 오해해서는 안됩니다 .

이 정적 메소드가 서브 클래스에 정의 된 새로운 정적 메소드에 의해 숨겨지지 않은 경우 서브 클래스 참조를 사용하여 수퍼 클래스의 정적 메소드에 액세스 할 수 있습니다.

예를 들어 아래 코드를 참조하십시오.

public class StaticMethodsHiding {
    public static void main(String[] args) {
        SubClass.hello();
    }
}


class SuperClass {
    static void hello(){
        System.out.println("SuperClass saying Hello");
    }
}


class SubClass extends SuperClass {
    // static void hello() {
    // System.out.println("SubClass Hello");
    // }
}

산출:-

SuperClass saying Hello

서브 클래스에서 정적 메소드 숨기기에 대한 세부 사항은 Java oracle 문서를 참조 하고 서브 클래스에서 수행 할 수있는 작업을 검색 하십시오.

감사


-3

다음 코드는 가능하다는 것을 보여줍니다.

class OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriden Meth");   
}   

}   

public class OverrideStaticMeth extends OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriding Meth");   
}   

public static void main(String[] args) {   
OverridenStaticMeth osm = new OverrideStaticMeth();   
osm.printValue();   

System.out.println("now, from main");
printValue();

}   

} 

1
아닙니다. 의 정적 선언 형 osmOverridenStaticMeth아닙니다 OverrideStaticMeth.
Lawrence Dol

2
또한 <big grin>을 프로그래밍하는 동안 Meth를 너무 많이 사용하지 않도록 노력하고 있습니다.
Lawrence Dol
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.