2008-10-03 9 views
3

기본 클래스 B와 파생 클래스 D가 있다고 가정합니다. 인스턴스가 어떤 유형이든 새로운 객체를 반환하는 기본 클래스 내에 foo() 메서드를 갖고 싶습니다. 예를 들어 B.foo()를 호출하면 B 형 객체를 반환하고 D.foo()를 호출하면 D 형 객체를 반환합니다. 한편 구현은 기본 클래스 B에서만 수행됩니다.Java : Newbie-ish 상속 질문

이것이 가능합니까? 클래스 이름은 어디

public ClassName getFoo() throws InstantiationException, IllegalAccessException 
{ 
    return getClass().newInstance(); 
} 

을 :이 당신이 당신의 슈퍼 클래스에 반영, 즉를 사용하여이 작업을 수행 할 수있을 것 같아요

public B instance() throws Exception { 
     return getClass().newInstance(); 
    } 
+0

구현을 기본 클래스로 유지하려는 특별한 이유가 있습니까? – Rik

+0

"초보자"질문을 말할 때, 근본적인 문제를 진술하는 더 가치있는 답을 얻을 수 있습니다. 나는 당신이 당신의 질문에 사용했던 것처럼 B와 D보다 당신의 문제에 대한 더 나은 해결책이 있어야한다고 믿습니다. –

답변

3

하지 마십시오. "foo"메소드를 추상화합니다.

abstract class B { 
    public abstract B foo(); 
} 

또는 기본 클래스 생성자를 통해 추상적 인 공장납니다

abstract class B { 
    private final BFactory factory; 
    protected B(BFactory factory) { 
     this.factory = factory; 
    } 
    public B foo() { 
     return factory.create(); 
    } 
} 
interface BFactory { 
    B create(); 
} 

이 공변 반환 형식과 맛 제네릭을 추가합니다.

3

만큼 기본 클래스의 이름.

어디서나 사용하고 싶다면 캐스트해야 할 것입니다 ... 정말 훌륭한 솔루션이라고 확신하지 못합니다!

편집 : newInstance() 유형 메소드는 일반적으로 정적이며 물론 서브 클래스의 유형이 정적 메소드와 관련이 있는지 알지 못합니다.

정적 () 방법으로 (동적으로) 하위 클래스의 인스턴스를 만드는 방법이 없다고 생각합니다.

+0

이 작동하지만 일반 "예외"클래스를 throw하는 메서드는 선언하지 마십시오. – jsight

+0

나는 반대의 접근법을 취한다 - 클라이언트가 다음과 같은 경우에만 여러 예외를 선언한다. b) 다르게 복구한다. 그렇지 않으면 단지 시각적으로 혼란스러워. 데모 및 JUnit 테스트 ... –

1

: 각 클래스는 기본 생성자가 같은

1

글쎄, 난 떨어져있을 수도 있지만 "이"항상 현재의 객체를 참조하기 때문에, 당신은 그 라인을 따라

public B foo() { 
    return this.getClass().newInstance(); 
} 

이나 뭐 같은 것을 할 수 있다고 가정까요? D의 인스턴스를 만든 다음 d.foo()를 호출하면 D의 인스턴스가 B로 반환됩니다.이 인스턴스를 일반 Object로 반환 할 수는 있지만 가능한 한 구체적이어야합니다.

0

@Rik

글쎄, 진짜 문제는 내가 추상적 인 기본 클래스가 있다는 것입니다. 그리고 Thing은 새로운 Thing 인스턴스를 리턴하는 getNextThing() 메소드를 가지고 있습니다.

그런 다음 BigThing, LittleThing, SomethingThing과 같은 여러 하위 클래스가 있는데 각 클래스에 대해 getNextThing() 메서드를 다시 작성하지 않으려합니다. 그들은 모두 똑같은 일을하기 때문에 낭비가되는 것 같습니다.

내 접근 방식에 맞지 않습니까?

+0

아니, 귀하의 질문에 반영 대답을 사용하여, 당신이 원하는대로이 구현할 수 있어야합니다, 나에게 잘 보입니다. – MattC

+0

당신은 그 때 반성해야 할 것 같아요. – Rik

+0

"모두 똑같은 일을하기 때문에 낭비가되는 것 같습니다." 거의 낭비가되지 않습니다. 당신은 이유 때문에 서브 클래스를가집니다. 종종 각 하위 클래스에는 다른 생성자 또는 초기화 또는 다른 것이 있습니다. 그것들은 거의 동일하지 않습니다. –

0

나는 왜 당신이 실제로하려는 것을하려고하는지 잘 모르겠습니다. 컨텍스트를 제공하면 더 많은 도움을받을 수 있습니다.

public class B <X extends B>{ 

public X foo() throws InstantiationException, IllegalAccessException{ 
    return (X)this.getClass().newInstance(); 
} 
}   
public class C extends B<C>{   

} 

이 조언을드립니다. CS 수업을 가르치는 방식은 교수가 상속에 매혹되지만 구성을 파악하지 못했다는 것입니다. 나는 당신이 찾고있는 것이 작곡이라고 생각합니다. 그래서 Thing 자체에서 getNextThing을 호출하는 대신, Thing을 구현하는 것에 대해 생각해야 할 수도 있습니다. Iterable

즉, 보이지 않는 것처럼 귀하의 상속 모델에 맞게.이것의 또 다른 이점은 당신이 멋진 구문 장치를 (루프 내 용을 향상시키기 위해) 얻을 수 있다는 것입니다.

1

당신이 이것을 원한다면 아마 디자인 결함이 있다고 생각한다는 사실 외에도 다음과 같은 접근 방식을 시도해 볼 수 있습니다.

정적 메서드는 동적 특성이 없기 때문에 상속을 사용하여 수행 할 수없는 B.foo(), D.foo() 정적 (클래스) 메서드를 사용하고 있습니다. 조회 시스템의 일부. 따라서 유형 정보가 충분하지 않습니다.

당신이 멤버 함수 foo를 사용하는 경우() 당신은 다음과 같은 구조 할 수 : 다른 답변, 당신은 모두 getClass()를 사용할 수 있습니다 말하는 것처럼

public class B { 
    public B foo() 
    throws IllegalAccessException, InstantiationException { 
     return this.getClass().newInstance(); 
    } 
} 

public class D extends B{  
} 

public class Test { 
    public static final void main(String[] args) 
    { 
     try { 
      System.out.println((new B()).foo()); 
      System.out.println((new D()).foo()); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } catch (InstantiationException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

죄송합니다. foo()가 정적 메서드라는 것을 의미하지는 않았습니다. 그렇지 않습니다. – Jake

+0

또한 왜 이것이 디자인 결함의 산물이라고 생각하십니까? – Jake

1

을 위해서, newInstance를()가 아니 -가있는 경우. 각 하위 클래스의 인수 생성자 (InstantiationException 및 IllegalAccessException catch해야합니다).

인수가 필요한 생성자가있는 경우 필요에 따라 하위 클래스에서 재정의 할 수있는 getNewInstance()와 같은 메소드를 정의하거나 리플렉션을 사용할 수 있습니다.

당신이 정말로, 서브 클래스의 기본 생성자가없는 해당해야하는 경우

Thing foo() { 
    Thing th = getNewInstance(); 
    // do some stuff with th 
    return th; 
} 

Thing getNewInstance() { 
    return getClass().newInstance(); 
} 

그런 다음 getNewInstance()는 오버라이드 (override) 할 수 있습니다.

Thing getNewInstance() { 
    return new BigThing(10, ThingSize.METRES); 
}