2010-02-09 5 views
1

내 응용 프로그램에 대한 일반 데이터 액세스 계층을 쓰려고합니다. 그 실체에 대한일반 및 Java : "확장"은 어떻게 작동합니까?

public abstract class Entity1 { 
    // some implementation 
} 
public class Entity2 extends Entity1 { 
    // some implementation 
} 
public class Entity3 extends Entity1 { 
    // some implementation 
} 

의 DAO는 제외 (대부분 동일합니다 : 나는 (그들이 최대 절전 모드에서 계층 구조로 구현되지 않음) 배수가 대부분 동일하고 자바의 클래스 계층 구조로 표현되는 엔티티를 최대 절전 모드가 메소드의 타입 시그니처, 그리고 Hibernate에 요청 된 클래스). 나는이 같은 일반적인 DAO를 쓸 수 있도록하고 싶습니다 : 정말 좋은

public interface EntityDao<T extends Entity1> { 
    List<T>getEntities(); 
    void saveOrUpdateEntity(T entity); 
} 

public class EntityDaoImpl implements EntityDao<Entity1> { 
    private final HibernateTemplate hibernateTemplate; 

    private final Class<DBEnumerationDto> clazz; 

    public DBEnumerationDaoHibernateImpl(SessionFactory sessionFactory, Class<DBEnumerationDto> clazz) { 
     this.hibernateTemplate = new HibernateTemplate(sessionFactory); 
     this.clazz = clazz; 
    } 

    @Override 
    public List<Entity1> getEntities() { 
     return this.hibernateTemplate.loadAll(this.clazz); 
    } 
    @Override 
    public void saveOrUpdateEntity(Entity1 entity) { 
     this.hibernateTemplate.saveOrUpdate(entity); 
    } 
} 

지금까지. 이를 사용하는 경우 그러나 문제는 발생 :이 질문은 Java Generics: casting to ? (or a way to use an arbitrary Foo<?>) 관련 추측 The method saveOrUpdateEntity(capture#5-of ? extends Entity1) in the type EntityDao<capture#5-of ? extends Entity1> is not applicable for the arguments (Entity1)

하지만 난 정말 어떤 방법으로 파악하지 못할 :

Entity1 test = new Entity1(); 
Entity1Dao<? extends Entity1> dao = ...; // get the dao forthe current operation 
dao.saveOrUpdate(test); 

이것은 컴파일러 오류를 제공합니다.

코드를 어떻게 수정해야합니까? 아니면 내 접근 방식이 잘못 되었나요?

+0

추상 클래스 대신 구체적인 클래스를 저장하려고 했습니까? –

답변

0

실제로 어떤 유형인지 알아야하므로 generic 클래스의 실제 인스턴스화에 extends 키워드를 사용하지 않아야합니다. 당신은 의미, 그 종류 또는 와일드 카드를 사용해야 할 것 중 하나

Entity1Dao<Entity1> 
// or 
Entity1Dao<?> 

최대 절전 모드 템플릿이 작동 할 수 있기 때문에 당신이 최대 절전 모드를 사용하고 당신은 아마 모든 엔터티 수퍼 클래스를 필요가 없습니다 일반적인 DAO를 구현하려는 경우 등록 된 엔티티 인 모든 클래스. 엔티티 수퍼 클래스 접근법을 한 번 시도했지만 많은 유익을주지 않으면 서 거대한 일반 번거 로움을 겪었습니다 (특히 Hibernate 주석을 사용할 때 상속과 관련하여 잘 작동하지 않음).

2

실패한 예제의 두 번째 줄에 물음표 (와일드 카드)가 무엇을 의미하는지 잠시 생각해보십시오.

알려지지 않은 제네릭 매개 변수가있는 Entity1Dao을 얻었습니다 (매개 변수가 Entity1의 하위 클래스라는 사실 만 알 수 있습니다). 때문에 와일드 카드의

Entity1Dao<? extends Entity1> dao = getEntityDao(); 

private Entity1Dao<Entity2> getEntityDao() 
{ 
    return new Entity1Dao<Entity2>(); // Or whatever (the construction itself is irrelevant) 
} 

Entity1Dao<Entity2>이 완벽하게 합법적 인 할당이 실제로 구현 될 수 있도록 다음과 같이 그래서 완벽하게 합법적 것이다. 이제 다음 줄로 가서 dao.saveOrUpdate()으로 전화를 걸어 Entity1 유형의 개체를 전달합니다.

이것은 작동하지 않습니다. 위에 표시된 것처럼 dao는 Entity2에 매개 변수가 지정되어 있으므로 구체적인 방법이 saveOrUpdate(Entity2 entity)! 따라서 컴파일러가 왜 타입 경고를 주는지.


요약, 귀하의 문제는 와일드 카드 매개 변수가 실제 타입의 서브 클래스를 처리 할 따라서 없습니다 수있는 "확장"키워드입니다. 와일드 카드를 변경하여 super (즉, <? super Entity1>)를 사용하는 경우 컴파일러는 실제 제네릭 유형에 관계없이 saveOrUpdate 메소드가 Entity1 유형의 인수를 허용한다는 것을 확신 할 수 있으므로 컴파일됩니다.

은 종종 당신이 모두 슈퍼로 같은 매개 변수를 필요로 밝혀과 는 전혀 와일드 카드를 사용할 수 없음을 의미 어떤 정확한 유형에 비해을 확장합니다. 이 경우,이 같은 전체 클래스의 구체적인 유형에 제네릭 방법, 뭔가 할 수도 있습니다 :

public <T extends Entity1> void saveEntityExample(T test) 
{ 
    Entity1Dao<T> dao = getEntityDao(); 
    dao.saveOrUpdate(test); 
} 

private <T extends Entity1> Entity1Dao<T> getEntityDao() 
{ 
    // Get the DAO however 
} 

당신은 또한 this answer에 연결 조쉬 블로흐의 이야기를 체크 아웃 할 수 있습니다를, 특히 "PECS"의 개념을 고안하는 것입니다. "확장"이 항상 대답 인 클래스와는 달리, 제네릭에 있어서는 "확장"또는 "슈퍼"를 의미하는지 기억해야하며 니모닉은 일반적인 규칙을 기억하는 유용한 방법입니다.

관련 문제