2016-10-29 15 views
8

Staram się aby moje własne repozytorium dla mojej bazy danych, aby dowiedzieć się, więc próbuję coś takiego:Wywołanie konstruktora typu generycznego?

@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; 
} 

Innymi słowy Mam wiele klas, które rozszerzają DatabaseObject i chcę, aby być w stanie budować kursor dla nich dynamicznie.

Zdefiniowałem podstawowe metody w DatabaseObject, takie jak uzyskanie nazwy tabeli, Tablica ciągów nazw kolumn itp., Ale ponieważ nie mogę przesłonić statycznych metod przez interfejs (w przypadku rzeczy takich jak nazwa tabeli), muszę utworzyć instancję pusty obiekt, więc mogę uzyskać nazwę tabeli z geterem.

Jednak nie jestem pewien, jak wdrożyć:

  1. somehowGetClassOfT(). Niezależnie od tego, czy jest to T, chcę przekazać tę klasę do funkcji kursora.

  2. instantiateFromT(clazz). Biorąc pod uwagę klasę, wywołaj konstruktora, aby uzyskać dostęp do pól tabeli/projekcji/sortowania tego obiektu.

Czy to wszystko jest możliwe dzięki "odbiciu", o którym słyszałem?

Odpowiedz

4

Produkty generyczne nie są reifikowane w czasie wykonywania. Ponieważ informacja ta nie jest obecny, masz dwa rozwiązania:

  • mogą być przechowywane w czasie kompilacji, wprowadzając prywatną pole z klasą
  • można wykorzystać odbicie rozwiązać typy rodzajowe w czasie wykonywania z instancji .

Oto przykład z prywatnym polu T i konstruktora, zaczynając od kodu:

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 
     }   
    } 
} 

tutaj swoje DogRepository:

public class DogRepository extends MyRepository<Dog> { 

    public DogRepository() {   
     super(Dog.class); 
    } 

} 

z psem, który implementuje DatabaseObject:

public class Dog implements DatabaseObject{ 
    //todo 
} 

Aby odpowiedzieć na swój komentarz.

Linia DogRepository (typ klasy), czy konieczne jest podanie w klasie jako argumentu?

Nie jest niepotrzebny (przepraszam źle przeczytałem twój komentarz)).
I dalej, jak można zauważyć, konstruktorami repozytoriów betonu są kody płyt kotła.
Jeśli używasz refleksji do rozwiązania klasy generycznej używanej w DogRepository, nie musisz już definiować niestandardowego konstruktora.

Na przykład, aby odzyskać w rodzaju stosowanych w repozytorium, Wiosna robi pracę z własnej biblioteki za pomocą mechanizmów refleksji JDK z czymś takim:

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

Wiosna ma swoją bibliotekę, ponieważ wykorzystuje wiele refleksji.
Ale w twoim przypadku możesz także wykonać zadanie bez używania biblioteki, ale z własną klasą narzędzi. Tutaj próbka do rozwiązania typ ogólny z instancji repozytorium.

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

z refleksji rozwiązać skuteczną typu rodzajowego w MyRepository konstruktora:

public abstract class MyRepository<T extends DatabaseObject> { 

    private Class<T> type; 

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

repozytorium betonu klasy nie potrzebują własnego konstruktora dłużej:

public class DogRepository extends MyRepository<Dog> { 

} 
+0

w prosty sposób. Odpowiedziałam. – davidxxx

+0

Właśnie widziałem. Już pomógł SO. Świetnie :) – davidxxx

+0

Linia 'DogRepository (klasa )', czy konieczne jest przekazanie klasy jako argumentu? To znaczy. czy DogRepository nie ma wewnętrznego odwołania do Dog.class, aby przekazać argument, więc nie musi być przekazywany z zewnątrz za każdym razem, gdy wywoływane jest repozytorium? – user7085962

Powiązane problemy