2016-10-29 17 views
8

Tôi cố gắng để làm cho kho lưu trữ của riêng mình cho cơ sở dữ liệu của tôi để tìm hiểu, vì vậy tôi đang cố gắng một cái gì đó như thế này:Trình tạo hàm gọi chung loại?

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

Nói cách khác tôi có nhiều lớp học kéo dài DatabaseObject, và tôi muốn để có thể xây dựng một con trỏ cho chúng động.

Tôi đã định nghĩa các phương thức cơ bản trong DatabaseObject như lấy tên bảng, mảng chuỗi tên cột, v.v. vì tôi không thể ghi đè phương thức tĩnh thông qua giao diện (đối với những thứ như tên bảng), tôi phải khởi tạo đối tượng trống để tôi có thể lấy tên bảng bằng bộ thu thập.

Tuy nhiên, tôi không chắc chắn làm thế nào để thực hiện:

  1. somehowGetClassOfT(). Bất cứ điều gì T là, tôi muốn chuyển lớp cho nó vào hàm Cursor.

  2. instantiateFromT(clazz). Cho một số lớp, hãy gọi hàm tạo để tôi có thể truy cập vào các trường bảng/chiếu/sắp xếp của đối tượng đó.

Hoặc là tất cả điều này có thể bằng cách sử dụng "phản chiếu" mà tôi đã nghe?

Trả lời

4

Generics không được thống nhất vào thời gian chạy. Kể từ khi thông tin là không có mặt, bạn có hai giải pháp:

  • nó có thể được bảo quản ở thời gian biên dịch bằng cách giới thiệu một lĩnh vực riêng với lớp
  • bạn có thể sử dụng phản ánh để giải quyết loại chung trong thời gian chạy từ một thể hiện .

Dưới đây là một ví dụ với một T lĩnh vực tư nhân và một nhà xây dựng, bằng cách bắt đầu từ mã của bạn:

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

Đây DogRepository của bạn:

public class DogRepository extends MyRepository<Dog> { 

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

} 

với một con chó mà thực hiện DatabaseObject:

public class Dog implements DatabaseObject{ 
    //todo 
} 

Để trả lời nhận xét của bạn.

Dòng DogRepository (Loại lớp), là cần thiết để vượt qua trong lớp làm đối số?

Không cần thiết (xin lỗi tôi đã đọc nhận xét của bạn)).
Và để đi xa hơn, như bạn có thể nhận thấy, các nhà thầu cho các kho chứa bê tông là mã tấm nồi hơi.
Nếu bạn sử dụng sự phản chiếu để giải quyết lớp đằng sau generic được sử dụng trong DogRepository, bạn không cần phải định nghĩa một hàm tạo tùy chỉnh nữa cho nó.

Ví dụ để lấy các loại được sử dụng trong các kho lưu trữ, mùa xuân không được công việc với thư viện riêng của mình sử dụng các cơ chế phản chiếu JDK với một cái gì đó như thế:

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

Spring có thư viện của nó bởi vì nó sử dụng nhiều suy tư.
Nhưng trong trường hợp của bạn, bạn cũng có thể thực hiện công việc mà không cần sử dụng lib nhưng với lớp tiện ích của riêng bạn. Đây là một mẫu để giải quyết kiểu generic từ một cá thể kho lưu trữ.

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

Với suy nghĩ để giải quyết các loại generic hiệu quả trong việc MyRepository constructor:

public abstract class MyRepository<T extends DatabaseObject> { 

    private Class<T> type; 

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

lớp bê tông kho không cần xây dựng tùy chỉnh nữa:

public class DogRepository extends MyRepository<Dog> { 

} 
+0

một cách thẳng. Tôi đã trả lời. – davidxxx

+0

Tôi vừa xem. Đã được SO. Tuyệt vời :) – davidxxx

+0

Dòng 'DogRepository (Loại loại) ', có cần phải vượt qua trong lớp như một đối số không? I E. không nên DogRepository có một tham chiếu nội bộ bằng cách nào đó để Dog.class để vượt qua một đối số vì vậy nó không phải được thông qua từ bên ngoài mỗi khi kho được gọi? – user7085962

Các vấn đề liên quan