2016-10-29 13 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 का विस्तार है, और मुझे निर्माण करने में सक्षम होना चाहता हूँ उनके लिए गतिशील रूप से एक कर्सर।

मैंने डेटाबेस ऑब्जेक्ट में मूल विधियों को परिभाषित किया है जैसे तालिका का नाम, कॉलम नामों की स्ट्रिंग सरणी आदि प्राप्त करना, लेकिन चूंकि मैं इंटरफ़ेस (तालिका नाम जैसी चीज़ों के लिए) के माध्यम से स्थिर तरीकों को ओवरराइड नहीं कर सकता, मुझे तुरंत चालू करना होगा खाली वस्तु इसलिए मैं एक गेटर के साथ टेबल नाम प्राप्त कर सकते हैं।

हालांकि, मुझे यकीन है कि कैसे लागू करने के लिए नहीं कर रहा हूँ:

  1. somehowGetClassOfT()। जो भी T है, मैं कर्सर फ़ंक्शन में कक्षा को पास करना चाहता हूं।

  2. instantiateFromT(clazz)। कुछ वर्ग को देखते हुए, कन्स्ट्रक्टर को कॉल करें ताकि मैं उस ऑब्जेक्ट की तालिका/प्रोजेक्शन/सॉर्ट फ़ील्ड तक पहुंच प्राप्त कर सकूं।

या यह सब "प्रतिबिंब" का उपयोग कर संभव है जो मैं सुन रहा हूं?

उत्तर

4

जेनिक्स रन-टाइम पर संशोधित नहीं होते हैं। के बाद से जानकारी मौजूद नहीं है, तो आप दो समाधान है:

  • यह वर्ग
  • आप एक उदाहरण से कार्यावधि में सामान्य प्रकार के हल करने के लिए प्रतिबिंब का उपयोग कर सकते के साथ एक निजी क्षेत्र शुरू करने से संकलन समय पर संग्रहीत किया जा सकता ।
यहाँ

एक निजी क्षेत्र टी और एक निर्माता, के साथ एक उदाहरण अपने कोड से शुरू करके:

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:

public class DogRepository extends MyRepository<Dog> { 

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

} 
एक कुत्ता जो DatabaseObject लागू करता है साथ

:

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

मैंने अभी देखा है। एसओ द्वारा पहले से ही मदद की है। ग्रेट :) – davidxxx

+0

लाइन 'डॉग रिपोजिटरी (कक्षा प्रकार)', क्या कक्षा में तर्क के रूप में पास करना आवश्यक है? अर्थात। क्या DogRepository के पास किसी भी तरह से एक तर्क नहीं पारित करने के लिए Dog.class को आंतरिक संदर्भ होना चाहिए ताकि भंडार को हर बार बाहर से बाहर नहीं किया जाना चाहिए? – user7085962

संबंधित मुद्दे