2012-11-27 4 views
9

이것은 새 질문과 같지만 자바로 작업 한 마지막 시간에는 해당 언어에 제네릭이 없었습니다.일반 부모를 통해 액세스 한 하위 클래스의 Java 정적 멤버

public abstract class AbstractBase { .... } 
public class ConcreateSubA extends AbstractBase { .... } 
public class ConcreateSubB extends AbstractBase { .... } 
... 
public class ConcreateSubZZ9PluralZAlpha extends AbstractBase { .... } 
... 

좀 레거시 코드를 정리하기 위해 노력하고있어, 반복적 인 중복의 톤이 모든 속으로 고려 될 수있는 하나 개의 장소가 거기를 : 나는 클래스 계층 구조를 (이름은 가능한 한 일반화로로 변경) 제네릭을 통해 단일 루틴. (이 루틴을 호출 할 때, 그것은 구체적인 클래스 하나에서 작동해야하기 때문에 내가 제네릭을 생각하고 있어요.)

루틴 모습을

public <Thing extends AbstractBase> void someFunc() 
{ 
    another_function_call (Thing.concreteSpecialToken); 
    // could also be 
    // another_function_call (Thing.concreteSpecialToken()); 
    // if methods are more feasible than fields 

    // Cannot use 
    // another_function_call (Thing().concreteSpecialToken()); 
    // because creating instances of these types is a Major Operation[tm] 
} 

처럼 나는 엄청나게 라인 대해 떠나요 하지만 중요한 부분은 다음과 같습니다. someFunc()은 parametric 유형입니다 (실제로 인수가 있지만 그 중 아무 것도 추론하지 않습니다). 결국 특수 토큰을 가져와야하고 이것이 내가 퍼지게되는 곳입니다.

토큰은 각 구체적인 클래스에 대해 거대한 엉덩이 고유 문자열입니다. 클래스 기반이며 인스턴스 기반이 아닙니다. 실제 토큰 값은 각 서브 클래스에서 private static final 필드로 선언됩니다.

그래서 (결국) 하위 클래스의 개인 정적 필드를 얻으려면 기본 클래스의 공용 메서드/필드를 사용해야합니다. 분명히 의미가 없기 때문에 분명히베이스에 abstract static 메서드를 선언 할 수 없습니다. 데이터가 인스턴스 기반 인 경우 기본 클래스에 다형성 getter를 사용하면 간단하지만 하위 클래스는 정적입니다.

Java generics의 기능이 누락 된 것처럼 느껴지지만 whatever이 추상 기본 클래스로 선언 할 수없는 경우가 아니면 Thing.whatever()을 사용할 수 없습니다. Java의 한계 또는 전문성 부족으로 인해이 격차를 해소하려고합니다. 제가 생각한 한 가지 시도는 유망한 것처럼 보였습니다. 클래스 계층 구조 아래로 코드 복제본을 여러 번 가져 와서 똑같은 코드를 반복적으로 사용하여 추상적 인 메서드를 정의했습니다 ... 제네릭이 예방하는 데 도움이되는 요소입니다.

+2

+1 'ZZ9PluralZAlpha'의 경우 : –

답변

7

Java 한계 또는 전문 기술 부족으로 인해 갭을 메우기 위해 노력하고 있습니다.

상당히 제한적인 IMO이지만 Java의 제한 사항입니다. 기본적으로 정적 멤버를 다형성 인 것처럼 사용하려고합니다. 작동하지 않을 것입니다 - 제네릭은 여러분을 도와주지 않습니다.

옵션 :

  • 유형의 삭제는 이 가지고있는 경우에 당신이 명시 적으로
  • 에 통과하지 않는 한 ThingClass 얻을 수 없음을 의미 염두에 사용 반사 ...하지만 곰 어쨌든 Thing의 인스턴스는 그냥 추상화 인스턴스 각 구현에서 정적 필드의 값을 반환합니다.
  • 별도의 유형 hierar 만들기 당신이이 같은 private static final 필드에 토큰을 유지하려면 인스턴스 멤버에게
3

올바르게 이해한다면 type 매개 변수의 구체적인 클래스가 필요합니다. public <T extends AbstractBase> void someFunc(Class<T> clazz)

물론 이것은 여분의 매개 변수는 메서드에 전달 될 필요가 의미와 자바의 형태 삭제 주어진 정적 필드에 액세스하는 반사를 사용할 필요가 있지만 : 그것을하는 일반적인 방법은 다음과 같이 당신의 방법을 선언하는 것입니다 그것은 유일한 방법입니다.

이야기의 도덕은 generics와 statics가 잘 어울리지 않는다는 것입니다.

2

약간 투박하지만 경우 someFunc는 반사 사용할 수있는 Class<Thing> 매개 변수를했다 :

public <Thing extends AbstractBase> void someFunc(Class<Thing> clz) { 
    // exception handling omitted 
    Object whatever = clz.getDeclaredMethod("whatever").invoke(null); 

을하지만 어쩌면

public abstract class AbstractBase { 
    public static class Info { 
    public String getInfo() { 
     return "AbstractBase"; 
    } 
    } 
} 

public class ConcreteSubA extends AbstractBase { 
    public static final Info INFO = new Info() { 
    public String getInfo() { return "ConcreteSubA"; } 
    } 
} 

과 같은 무언가를 중첩 클래스를 사용하여 다형성을 더 잘 활용할 수 someFunc의 매개 변수는 AbstractBase.Info입니다.

public <Thing extends AbstractBase> someFunc(AbstractBase.Info inf) { 
    String info = inf.getInfo(); 
} 

// call it as 
ConcreteSubB csb = someFunc(ConcreteSubB.INFO); 

아이디어는 계층 구조의 각 클래스 Info가 그 이전의 정적 인 데이터를 유지하는 싱글 인스턴스를 갖는다는 것이다.

+0

그건 문제입니다. someFunc가 호출 될 때 아직 전달할 물건이 없습니다. 하지만 반성을 다시 한 번 살펴 보겠습니다. 감사합니다. –

+0

@TiStrga 대체 접근법을 조금 확장하여 통계가 아닌 다른 클래스의 싱글 톤 인스턴스에 데이터를 저장했습니다. –

1

를 사용 CHY, 당신은 반사를 통해 얻을 수 있습니다 : 전화 사이트에서

public <Thing extends AbstractBase> void someFunc(Class<Thing> clz) 
{ 
    try { 
     Field field = clz.getField("concreteSpecialToken"); 
     field.setAccessible(true); 
     Object concreteSpecialToken = field.get(null); 
     another_function_call (concreteSpecialToken); 
    } catch (IllegalAccessException e) { 
     handle(e); 
    } catch (NoSuchFieldException e) { 
     handle(e); 
    } 
} 

, 당신은 someFunc(ConcreateSubZZ9PluralZAlpha.class)을 할 필요가 . 하지만 당신이 할 수 있는지 궁금해하는데 왜 someFunc(ConcreateSubZZ9PluralZAlpha.concreteSpecialToken)처럼 토큰 객체를 매개 변수로 전달하는 것이 좋을까요? 또는 메소드 someFunc()을 토큰 클래스 자체로 옮길 수도 있습니다.

관련 문제