해결하기 매우 어려운 이름 숨김 문제가 있습니다. 다음은 문제를 설명하는 단순화 된 버전입니다.
수업이 있습니다. org.A
package org;
public class A{
public class X{...}
...
protected int net;
}
그런 다음 수업이 있습니다 net.foo.X
package net.foo;
public class X{
public static void doSomething();
}
이제 여기에서 상속 A
하고 호출하려는 문제 클래스가 있습니다.net.foo.X.doSomething()
package com.bar;
class B extends A {
public void doSomething(){
net.foo.X.doSomething(); // doesn't work; package net is hidden by inherited field
X.doSomething(); // doesn't work; type net.foo.X is hidden by inherited X
}
}
보시다시피 이것은 불가능합니다. X
상속 된 유형에 의해 숨겨져 있기 때문에 간단한 이름을 사용할 수 없습니다 . 나는 완전한 이름을 사용할 수 net.foo.X
있기 때문에, net
상속 된 필드에 의해 숨겨져 있습니다.
B
내 코드베이스 에는 클래스 만 있습니다. 클래스 net.foo.X
와 org.A
라이브러리 클래스이므로 변경할 수 없습니다!
내 유일한 솔루션은 다음과 같습니다. 차례로 호출하는 다른 클래스를 호출 할 수 있습니다 X.doSomething()
. 하지만이 클래스는 이름 충돌로 인해 존재할 수 있습니다. 내가 직접 호출 할 수있는 해결책이없는 X.doSomething()
에서는 B.doSomething()
?
예를 들어 global::
C # 또는 ::
C ++ 에서 전역 네임 스페이스를 지정할 수있는 언어에서는 net
이 전역 접두사를 단순히 접두사 로 지정할 수 있지만 Java는이를 허용하지 않습니다.
답변
를 null
형식으로 캐스트 한 다음 해당 메서드를 호출 할 수 있습니다 (대상 개체가 정적 메서드 호출에 관여하지 않기 때문에 작동 함).
((net.foo.X) null).doSomething();
이것은의 이점이 있습니다
- 부작용이 없음 (인스턴스화 문제
net.foo.X
) - 아무 것도 이름을 바꿀 필요가 없습니다 (
B
원하는 이름으로 메서드를 지정할 수 있으므로import static
정확한 경우에는 작동하지 않습니다). - 델리게이트 클래스의 도입이 필요하지 않습니다 (좋은 생각이긴하지만…).
- 리플렉션 API 작업의 오버 헤드 나 복잡성이 필요하지 않습니다.
단점은이 코드가 정말 끔찍하다는 것입니다! 저에게는 경고가 발생하며 일반적으로 좋은 일입니다. 그러나 완전히 비현실적인 문제를 해결하기 때문에
@SuppressWarnings("static-access")
적절한 (최소한!) 둘러싸는 지점에서 컴파일러가 종료됩니다.
답변
아마도 이것을 관리하는 가장 간단한 (반드시 가장 쉬운 것은 아님) 방법은 델리게이트 클래스를 사용하는 것입니다 :
import net.foo.X;
class C {
static void doSomething() {
X.doSomething();
}
}
그리고 …
class B extends A {
void doX(){
C.doSomething();
}
}
이것은 다소 장황하지만 매우 유연합니다. 원하는 방식으로 작동하도록 할 수 있습니다. 또한 static
메서드와 인스턴스화 된 객체 모두에서 거의 동일한 방식으로 작동 합니다.
델리게이트 객체에 대한 자세한 내용은 http://en.wikipedia.org/wiki/Delegation_pattern을 참조 하십시오.
답변
정적 가져 오기를 사용할 수 있습니다.
import static net.foo.X.doSomething;
class B extends A {
void doX(){
doSomething();
}
}
조심 그 B
와 A
이름이 방법을 포함하지 않는doSomething
답변
작업을 수행하는 적절한 방법은 정적 가져 오기이지만 절대 최악의 시나리오에서 정규화 된 이름을 알고 있으면 리플렉션을 사용하여 클래스의 인스턴스를 구성 할 수 있습니다.
Java : 기본 생성자가없는 클래스의 newInstance
그런 다음 인스턴스에서 메서드를 호출합니다.
또는 리플렉션을 사용하여 메서드 자체를
호출합니다. 리플렉션을 사용하여 정적 메서드 호출
Class<?> clazz = Class.forName("net.foo.X");
Method method = clazz.getMethod("doSomething");
Object o = method.invoke(null);
물론 이것들은 분명히 최후의 수단입니다.
답변
정답은 아니지만 X의 인스턴스를 만들고 이에 대한 정적 메서드를 호출 할 수 있습니다. 그것은 당신의 방법을 호출하는 방법 (내가 인정하는 더러운) 일 것입니다.
(new net.foo.X()).doSomething();
답변
캐스트를 수행하거나 이상한 경고를 억제하거나 중복 인스턴스를 만들 필요가 없습니다. 하위 클래스를 통해 부모 클래스 정적 메서드를 호출 할 수 있다는 사실을 사용하는 트릭입니다. ( 여기 내 hackish 솔루션과 유사합니다 .)
이런 클래스를 만드세요
public final class XX extends X {
private XX(){
}
}
(이 최종 클래스의 개인 생성자는 실수로이 클래스의 인스턴스를 만들 수 없도록합니다.)
그런 다음 자유롭게 전화 X.doSomething()
를 걸 수 있습니다.
public class B extends A {
public void doSomething() {
XX.doSomething();
}
답변
모든 파일이 동일한 폴더에있는 경우 gobalnamespace를 얻으려고하면 어떨까요? ( http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html )
package com.bar;
class B extends A {
public void doSomething(){
com.bar.getGlobal().net.foo.X.doSomething(); // drill down from the top...
}
}