2016-08-17 11 views
6

द्वारा संग्रह प्राप्त करें मान लें कि मेरे पास मेरी कक्षा Context है। जावा में संभव नहीं -जावा जेनेरिक प्रकार

public class Context { 
    Set<A> sA; 
    Set<B> sB; 
    Set<C> sC; 
} 

तो मैं एक सामान्य वर्ग Performer,, Context वर्ग से सामान्य प्रकार के आधार पर कार्रवाई करने निम्नलिखित तरीके से चाहता है कि है।

public class Performer<T> { // T can be type of A,B or C 

    public void saveToSet(T t) { 
     Context.Set<T>.add(t); 
    } 
} 

तो फिर, अगर मैं saveToSet(B b) कुछ ऐसा कहना, Context से सेट सही, इस मामले sB (Set<B>) में बुलाया जाएगा और नया उदाहरण है कि सेट करने के लिए जोड़ दिया जाएगा।

ठीक है, सवाल ... कैसे जावा में यह करने के लिए करते हैं? : डी

+2

यहां कोई सवाल है लागू करने के लिए प्राप्त प्रकार की जानकारी का उपयोग कर सकते हैं: इस तरह से प्रत्येक Set क्षेत्र के प्रकार के पैरामीटर को प्रतिबिंबित कर सकते हैं। – Sinkingpoint

+0

सवाल क्या है? –

उत्तर

7

अफसोस की बात है कि इस तरह का दृष्टिकोण जावा में टाइप एरर के कारण काम नहीं करेगा।

मूलतः सभी क्रम देखेंगे Context.Set<java.lang.Object>.add(t); और java.lang.Object के Set रों करने के लिए अपने क्षेत्रों के पतन है, और इसलिए यह स्पष्ट करने के लिए नहीं कर सकेंगे।

आप इस के आसपास भार के लिख कर saveToSet(A a) की तरह, saveToSet(B b) आदि

काम कर सकता था जिनमें से एक यह कई मायनों में, जावा जेनरिक सी ++ टेम्पलेट्स के गरीब चचेरे भाई हैं।

0
//Not very ice, but something like this can be useful 

if (x instanceof A) { 
    sA.add((A)x); 
    return; 
} 

if (x instanceof B) { 
    sB.add((B)x); 
    return; 
} 
0

यह प्रकार विलोपन के रूप में बुलाया जावा में एक अवधारणा के कारण काम नहीं करेगा। असल में, जेनेरिक प्रकार रनटाइम पर मिटा दिया जाता है, और रनटाइम यह नहीं जान पाएगा कि यह किस प्रकार की ऑब्जेक्ट थी या है। तो नहीं, आप ऐसा कुछ नहीं कर सकते हैं।

आप कर सकते हैं, हालांकि, अलग तरीकों बनाने के लिए, या आप एक विरासत में मिला कक्षाएं बनाने के लिए और है कि ओवरराइड विधि में विशिष्ट तर्क लागू कर सकते हैं। जावा के लिए

0

एक वैकल्पिक हल समृद्ध प्रकार का उपयोग कर रहा है। वे मूल रूप से प्रकार हैं जो Class<T> विशेषताओं के रूप में अपने सामान्य पैरामीटर रखते हैं। तो, मानक Set का उपयोग करने के बजाय, कक्षा को संग्रहीत करने वाले अपने कार्यान्वयन का उपयोग करें। कुछ ऐसा:

class TypeStoringSet<T> extends HashSet<T> { 
    private Class<T> clazz; 
    ... getter and setter here 

    public TypeStoringSet<T>(Class<T> clazz) { 
      super(); 
      this.clazz = clazz; 
    } 
} 
+1

इस समस्या में यह कैसे मदद करता है? –

0

शायद आप इस तरह के दृष्टिकोण का उपयोग कर सकते हैं।

class Context { 
    Map<String,Set<Object>> datasets = new HashMap<>(); 

    public <T> void add(T data){ 
     final String name = data.getClass().getName(); 
     if(!datasets.containsKey(name)) datasets.put(name, new HashSet<>()); 
     datasets.get(name).add(data); 
    } 

    public <T> Set<T> get(Class<T> type){ 
     return (Set<T>) datasets.get(type.getName()); 
    } 
} 

class Performer<T> { // T can be ANY type 

    public void saveToSet(T t) { 
     final Context context = new Context(); 
     context.add(t); 
    } 
} 

    final Set<A> aSet = context.get(A.class); 
    final Set<B> bSet = context.get(B.class); 
    final Set<C> cSet = context.get(C.class); 

अन्य संभव तरीके से कील को यह इंजेक्शन और Guice (ऋण: कम प्रदर्शन) के साथ विधि अवरोधन नाम पर है और इस कोड (वर्ग प्रकार से निपटने के लिए किया जाना करने के लिए आवश्यक अनुकूलन के बहुत सारे हैं, से MapMultibinding किया जा सकता है Guice datasets सुई)

0

वास्तव में आप अपने लक्ष्य और बाईपास प्रकार विलोपन प्रतिबिंब का उपयोग कर प्राप्त कर सकते हैं। लेकिन केवल तभी जब आपके Context में फ़ील्ड स्पष्ट रूप से परिभाषित सामान्य प्रकार पैरामीटर हैं।

तो अगर आप प्रदर्शन की सजा से डरते नहीं हैं तो प्रतिबिंब अपने दोस्त है।

// you can fill that lookup map upon Producer creation 
Map<Type, Field> lookup = new HashMap<>(); 
for (Field field : Context.class.getDeclaredFields()) { 
    // this code relies on fact that Set has only one 
    // type argument which is not parametrized 
    // also you need of course do some sanity checks 
    // (i.e field is a type of Set, etc) 

    Type setType = field.getGenericType(); 
    Type setGenericArgument = 
     ((ParameterizedType) superClass).getActualTypeArguments()[0]; 

    field.setAccisseble(true); 
    lookup.put(setGenericArgument, field); 
} 

उसके बाद आप अपने saveToSet विधि

public void saveToSet(T t) { 
    // also do exception processing and lookup 
    // map checks here 
    Field field = lookup.get(t.getClass()); 
    ((Set<T>) field.get(context)).add(t); 
} 
संबंधित मुद्दे