2016-10-29 4 views
8

배우고 내 데이터베이스에 대한 내 자신의 저장소를 만들려고 노력하고, 그래서 이런 식으로 뭔가 시도하고있다 : 즉제네릭 형식의 생성자를 호출합니까?

@Override 
public <T extends DatabaseObject> List<T> getList() { 
    Cursor cursor = getCursor(somehowGetClassOfT(), null, null); //how to do this? 
    //excess code removed, rest of function not relevant to question 
    return list; 
} 

protected <T extends DatabaseObject> Cursor getCursor(Class<T> clazz, String selection, String[] selectionArgs) { 
    DatabaseObject databaseObject = instantiateFromT(clazz); //how to do this? 
    String tableName = databaseObject.getTableName(); 
    String[] projection = databaseObject.getProjection(); 
    String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER; 
    Cursor cursor = database.query(
      tableName,        
      projection,    
      selection,        
      selectionArgs,        
      null,          
      null,          
      sortOrder         
    ); 
    return cursor; 
} 

내가 DatabaseObject을 확장하는 많은 클래스가 있고, 내가 만들 수 있도록하려면를 동적으로 커서를 표시합니다.

테이블 이름, 문자열 이름의 문자열 배열 등을 가져 오는 것과 같이 DatabaseObject에서 기본 메서드를 정의했지만 테이블 이름과 같은 인터페이스를 통해 정적 메서드를 재정의 할 수 없으므로 예제를 인스턴스화해야합니다. 빈 개체 그래서 나는 getter와 테이블 이름을 얻을 수 있습니다.

그러나, 나는 구현하는 방법을하지 확신 :

  1. somehowGetClassOfT(). T이 무엇이든, 그 클래스를 Cursor 함수에 전달하려고합니다.

  2. instantiateFromT(clazz). 어떤 클래스를 감안할 때 생성자를 호출하면 해당 객체의 테이블/프로젝션/정렬 필드에 액세스 할 수 있습니다.

또는 내가 들었던 "반사"를 사용하면이 모든 것이 가능합니까?

답변

4

실행시 제네릭이 구체화되지 않습니다. 정보가 존재하지 않기 때문에, 당신은 두 가지 해결책이 있습니다

그것은 당신이 인스턴스에서 런타임에 제네릭 형식을 해결하기 위해 반사를 사용할 수
  • 클래스와 민간 분야를 도입하여 컴파일 시간에 저장할 수 있습니다
    • . 여기

    사용자 코드에서 시작하여 개인 필드 T와 생성자와 예 :

    여기
    public abstract class MyRepository<T extends DatabaseObject> { 
    
        private Class<T> type; 
    
        public MyRepository(Class<T> type) { 
         this.type = type; 
        } 
    
        public <T> List<T> getList() { 
         Cursor cursor = getCursor(null, null); // how to do this? 
         // excess code removed, rest of function not relevant to question 
         return null; 
        } 
    
        protected <T extends DatabaseObject> Cursor getCursor(String selection, String[] selectionArgs) { 
         DatabaseObject databaseObject = instantiateFromType(); // how to do this? 
         String tableName = databaseObject.getTableName(); 
         String[] projection = databaseObject.getProjection(); 
         String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER; 
         Cursor cursor = database.query(
         tableName, 
         projection, 
         selection, 
         selectionArgs, 
         null, 
         null, 
         sortOrder); 
         return cursor; 
        } 
    
        private DatabaseObject instantiateFromType() { 
         try { 
          T interfaceType = (T) type.newInstance(); 
          return interfaceType; 
         } 
         catch (Exception e) { 
          // TODO to handle 
         }   
        } 
    } 
    

    당신의 DogRepository : DatabaseObject를 구현하는 개

    public class DogRepository extends MyRepository<Dog> { 
    
        public DogRepository() {   
         super(Dog.class); 
        } 
    
    } 
    

    :

    public class Dog implements DatabaseObject{ 
        //todo 
    } 
    

    귀하의 의견에 답변하십시오.

    라인 DogRepository (클래스 유형)은 클래스를 인수로 을 전달해야합니까?

    아니요 (미안하지만 의견이 잘못되었습니다.)).
    콘크리트 저장소에 대한 생성자는 보일러 플레이트 코드입니다.
    리플렉션을 사용하여 DogRepository에서 사용되는 제네릭 뒤에있는 클래스를 해결하는 경우 더 이상 사용자 지정 생성자를 정의 할 필요가 없습니다.

    저장소에 사용되는 유형을 검색 할 예를 들어, 봄은 그런 일에 JDK 반사 메커니즘을 사용하여 자신의 라이브러리를 사용하여 작업을 수행 훨씬 반사를 사용하기 때문에

    Map<TypeVariable, Type> source = GenericTypeResolver.getTypeVariableMap(DogRepository.class); 
    

    봄은 도서관이있다.
    그러나 귀하의 경우에는 lib를 사용하지 않고도 자신의 유틸리티 클래스를 사용하여 작업을 수행 할 수 있습니다. 저장소 인스턴스에서 제네릭 형식을 해결하기위한 예제입니다. 반사와

    DogRepository dogRepository = new DogRepository(); 
    Class<?> typeClass = (Class<?>) ((ParameterizedType) dogRepository.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
    System.out.println("typeClass=" + typeClass); 
    

    MyRepository 생성자에서 유효 제네릭 형식을 해결하기 위해 :

    public abstract class MyRepository<T extends DatabaseObject> { 
    
        private Class<T> type; 
    
        public MyRepository() { 
         type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
        } 
        ... 
    } 
    

    저장소 구체적인 클래스는 사용자 정의 생성자가 필요하지 않습니다 더 이상 :

    public class DogRepository extends MyRepository<Dog> { 
    
    } 
    
  • +0

    직선 방식이다. 나는 대답했다. – davidxxx

    +0

    방금 ​​보았습니다. 이미 SO의 도움을 받았습니다. Great : – davidxxx

    +0

    'DogRepository (Class type)'행은 인수로 클래스를 전달해야합니까? 나는. DogRepository는 Dog.class에 내부 참조를 가지고있어서 저장소를 호출 할 때마다 외부에서 전달 될 필요가 없도록 인수를 전달해서는 안됩니까? – user7085962

    관련 문제