2009-05-18 17 views
18

यह देखने के प्रयास में कि क्या मैं अपने कुछ गणित कोड को साफ़ कर सकता हूं, ज्यादातर मैट्रिक्स सामान, मैं कुछ जावा जेनरिक का उपयोग करने की कोशिश कर रहा हूं। मेरे पास निम्न विधि है:जावा जेनरिक और संख्या

private <T> T[][] zeroMatrix(int row, int col) { 
    T[][] retVal = (T[][])new Object[row][col]; 
    for(int i = row; i < row; i++) { 
     for(int j = col; j < col; j++) { 
      retVal[i][j] = 0; 
     } 
    } 
    return retVal; 
} 

लाइन retVal [i] [j] = 0 वह मुझे सिरदर्द का कारण बनता है। लाइन के लक्ष्य 0. की टी प्रतिनिधित्व मैं इसके साथ चीजों के सभी प्रकार के कर करने का प्रयास किया साथ सरणी को प्रारंभ करने के लिए है: (टी कक्षा में परिभाषित किया गया है टी फैली रूप में संख्या)

retVal[i][j] = (T)0; 
retVal[i][j] = new T(0); 

केवल काम जो काम करता है

retVal[i][j] = (T)new Object(0); 

जो मैं नहीं चाहता हूं।

क्या यह संभव है? क्या किसी भी प्रकार की संख्या (संभावित रूप से BigDecimal सहित) के एनएक्सएम मैट्रिक्स का प्रतिनिधित्व करने का कोई आसान तरीका है, या मैं अटक गया हूं?

+1

मेरे पास इस चर्चा में जोड़ने के लिए बहुत कुछ नहीं है, लेकिन ऐसे प्रश्न प्रदान करने के लिए धन्यवाद जो इस तरह के महान उत्तरों को उकसाता है। मैं जेनिक्स के जावा के कार्यान्वयन से खुश नहीं हूं, लेकिन अब मैं उन्हें बेहतर समझता हूं। –

उत्तर

1

ये बूढ़े (संदर्भ) सरणी जेनेरिक के साथ अच्छी तरह से खेल नहींते हैं। इस मामले में सरणी भी अक्षम होने की संभावना है। आप सरणी की सरणी बना रहे हैं, इसलिए अनावश्यक संकेत और सीमाएं जांच रही हैं। कक्षा Matrix<T> बनाने के लिए बेहतर है। आप Matrix को T के उदाहरण के संदर्भ में भी जोड़ना चाहते हैं जो शून्य का प्रतिनिधित्व करता है।

+1

यह वास्तव में मेरे मैट्रिक्स से कोड है <टी संख्या> वर्ग बढ़ाता है। –

+0

मैं "सरणी" प्रकार के रूप में संख्या [] या सूची का उपयोग करने का सुझाव देता हूं। java.util एक नकली जेनेरिक सरणी के साथ लिखा जा रहा है बस खुद को एक गड़बड़ में मिलता है। आपको एक विधि की आवश्यकता होगी ('निजी संख्या [] [] शून्यमैट्रिक्स (int पंक्ति, int col, संख्या शून्य)' या 'निजी सूची शून्यमैट्रिक्स (int पंक्ति, int col, टी शून्य)')। –

1

जेनिक्स और सरणी बहुत अच्छी तरह से मेल नहीं खाते हैं। जेनेरिक सरणी बनाना अनुमति नहीं है क्योंकि यह टाइपएफ़ नहीं होगा। यह इस तथ्य से उपजी है कि अगर उप सुपर का एक उप प्रकार है, तो उप [] सुपर [] का एक उप प्रकार है, जो सामान्य प्रकार का मामला नहीं है; किसी भी दो अलग प्रकार के टाइप 1 और टाइप 2 के लिए, सूची न तो एक उप प्रकार या सूची का एक सुपरटेप है। (प्रभावी जावा इसे अध्याय 5, आइटम 25 में शामिल करता है)।

-1

जेनिक्स को लागू करने के लिए जावा का उपयोग करने का मतलब है कि आपको सामान्य प्रकार के नए होने में परेशानी होगी।

कैसे अशक्त उपयोग के बारे में प्रतिनिधित्व करने के लिए 0

retVal[i][j] = null; 

इसके बाद आप किसी भी प्रकार आप बाद में सरणी करना चाहते हैं निर्दिष्ट कर सकते हैं।

+0

मुझे इस समाधान को पसंद नहीं है क्योंकि जावा में शून्य शून्य नहीं है – dfa

2

जावा में प्रकार रनटाइम पर मिटा दिया जाता है, इसलिए आपको रनटाइम पर प्रकार प्राप्त करने के लिए एक और तर्क में पारित करने की आवश्यकता होती है।

यह या तो सरणी शुरू करने या कक्षा का उपयोग करने के लिए मूल्य हो सकता है।

यदि आप कक्षा में उत्तीर्ण करना चुनते हैं, तो प्रत्येक प्रकार के लिए शून्य मान संग्रहीत करने के लिए कक्षा का मानचित्र रखें।

इसके बाद आप सरणी को भरने के लिए java.util.Arrays.fill उपयोग कर सकते हैं:

private static HashMap<Class<?>, Object> ZEROS = new HashMap<Class<?>,Object>(); 

static { 
    ZEROS.put(Integer.class, Integer.valueOf(0)); 
    ... 
} 

private static <T extends Number> T[][] zeroMatrix (Class<T> type, int rows, int cols) { 
    @SuppressWarnings("unchecked") 
    T[][] matrix = (T[][]) java.lang.reflect.Array.newInstance(type, rows, cols); 
    Object zero = ZEROS.get(type); 

    for (T[] row : matrix) 
     java.util.Arrays.fill(row,zero); 

    return matrix; 
} 

Integer[][] matrix = zeroMatrix (Integer.class, 10, 10); 

हालांकि, अगर प्रदर्शन दूर से चिंता का विषय है आप नहीं न्यूमेरिक कोड के लिए बॉक्स्ड मानों का उपयोग होना चाहता हूँ।

आप वास्तव में शून्य के लिए शून्य की कोशिश नहीं करना चाहते हैं - यह आपके कोड में अन्य सभी पथों की जटिलता को ट्रिगर करेगा। यद्यपि आप एक संख्यात्मक समर्थन वर्ग से दूर हो सकते हैं जो विभिन्न बॉक्स किए गए संख्या प्रकारों के अतिरिक्त और गुणा प्रदान करेगा, आपके द्वारा सहेजी गई जटिलता की मात्रा दो या तीन आदिम मैट्रिक्स और कुछ बड़ी संख्या के साथ तुलना करने की तुलना में बहुत कम होगी, विशेष रूप से यदि आप स्रोत कोड उत्पन्न करने के लिए एक टेम्पलेट सिस्टम (जैसे चींटी की प्रतिस्थापन कार्य या एक्सएसएलटी) का उपयोग करते हैं।

+0

@ संकलन समय पर सामान्य प्रकार टाइपिंग जांच के लिए उपलब्ध है - इसलिए यह संकलन समय पर मिटा नहीं गया है, लेकिन संकलन समय के बाद। संकलक इसे जेवीएम में भेजे गए कोड से मिटा देता है, इसलिए रनटाइम पर इसे मिटा दिया जाता है। –

1

मुझे लगता है कि आप हारने वाली लड़ाई से लड़ रहे हैं। यहां तक ​​कि यदि आप इसे हल करते हैं, तो आप अतिरिक्त, घटाव आदि को हल करने की योजना कैसे बना रहे हैं? संख्या वर्ग एक बहुत ही उपयोगी सुपरक्लास नहीं है, और केवल उपयोगी विधि DoubleValue() है।

शून्य को गुणा में शून्य या गुणा में शून्य के रूप में परिभाषित किया जा सकता है, लेकिन अतिरिक्त या गुणा की सामान्य परिभाषा के बिना, शून्य की सामान्य परिभाषा असंभव है।

यदि आप इसे चाहते हैं तो आप सबकुछ के लिए बिगडिसिल के साथ चिपके रहना बेहतर हो सकते हैं, लेकिन निश्चित रूप से प्रदर्शन प्रदर्शन जुर्माना होगा।

अन्य स्पष्ट विकल्प सरणी प्रारंभिकरण के साथ सरणी को छोड़ना होगा, और फिर शून्य के रूप में शून्य के इलाज के लिए अपना अन्य कोड बदलना होगा।

3

यह शून्य के बजाय शून्य होना चाहिए।

आप वास्तव में वहाँ वस्तु टी के लिए डाल करने के लिए बराबर 0 चाहते हैं तो आप इस तरह टी कुछ का एक कारखाना प्रदान करना होगा:

interface Factory<T> { 
    T getZero();  
} 

और आप बनाना चाहिए इस तरह विधि:

class IntegerFactory implements Factory<Integer> { 
    Integer getZero() { 
     return new Integer(0); 
    } 
} 

न ही:

private <T> T[][] zeroMatrix(int row, int col, Factory<T> factory) { 
    T[][] retVal = (T[][])new Object[row][col]; 
    for(int i = row; i < row; i++) { 
     for(int j = col; j < col; j++) { 
      retVal[i][j] = factory.getZero(); 
     } 
    } 

    return retVal; 
} 

तुम भी कारखाने के लिए उचित कार्यान्वयन होना चाहिए वास्तव में उचित टाइप किए गए सरणी को वापस करने के लिए आप कारखाने के कार्यान्वयन में getMatrix(int row, int column) डाल देंगे।

+0

यह रनटाइम पर स्पष्ट रूप से टूटता है। आप ऑब्जेक्ट [] [] को एकीकृत करने के लिए [] [] को नहीं डाल सकते हैं। –

+0

टेम्पलेट सीमाएं जोड़ने का प्रयास करें, उदा। <टी कुछ इंटरफेसटैटहाउसगेटजेरोमेड> –

+0

getZero() को कैशिंग या केवल इंटीजर.वल्यूओएफ() – dfa

1

आपको यह विचार करने की आवश्यकता है कि जेनरिक केवल टाइप सुरक्षा जांच के लिए संकलन-समय पर उपयोग किए जाते हैं। यह जानकारी रनटाइम पर खो जाती है ताकि आप retVal [i] [j] = 0 पर ऑटो-मुक्केबाजी का उपयोग न कर सकें; चूंकि जावा नंबर या ऑब्जेक्ट टाइप करने के लिए ऑटो-बॉक्स नहीं कर सकता है।

यदि आप उस मान को पार करते हैं जिसे आप सेट करना चाहते हैं, तो यह काम करेगा। यहां एक त्वरित नमूना है:

private <T> T[][] fillMatrix(int row, int col, T value) { 
    T[][] retVal = (T[][])new Object[row][col]; 
    for(int i = 0; i < row; i++) { 
     for(int j = 0; j < col; j++) { 
      retVal[i][j] = value; 
     } 
    } 
    return retVal; 
} 

Btw, के लिए (आई इंट = पंक्ति, मैं < पंक्ति, i ++) और के लिए (इंट जे = col; j < col; J ++) कभी नहीं पाश वहाँ के साथ एक और समस्या है तो होगा अपने कोड।

संपादित करें: आप परिणाम [] [] के अलावा किसी अन्य चीज़ को परिणाम देने में सक्षम नहीं होंगे क्योंकि यह वास्तविक सरणी प्रकार है।

+0

से नीचे मेरा उत्तर जांचें शायद << के लिए (टी [] टी 1: retVal) (टी टी 2: टी 1) टी 2 = मूल्य; >> काम कर सकता है। – ATorras

+2

यह उठाता है: java.lang.ClassCastException: [[Ljava.lang.Object; [[Ljava.lang.Integer; – dfa

+0

+1 ओच! आप सही हैं – ATorras

12
<T extends Number> T[][] zeroMatrix(Class<? extends Number> of, int row, int col) { 
    T[][] matrix = (T[][]) java.lang.reflect.Array.newInstance(of, row, col); 
    T zero = (T) of.getConstructor(String.class).newInstance("0"); 
    // not handling exception  

    for (int i = 0; i < row; i++) { 
     for (int j = 0; j < col; 
      matrix[i][j] = zero; 
     } 
    } 

    return matrix; 
} 

उपयोग:

BigInteger[][] bigIntegerMatrix = zeroMatrix(BigInteger.class, 3, 3); 
    Integer[][] integerMatrix = zeroMatrix(Integer.class, 3, 3); 
    Float[][] floatMatrix = zeroMatrix(Float.class, 3, 3); 
    String[][] error = zeroMatrix(String.class, 3, 3); // <--- compile time error 
    System.out.println(Arrays.deepToString(bigIntegerMatrix)); 
    System.out.println(Arrays.deepToString(integerMatrix)); 
    System.out.println(Arrays.deepToString(floatMatrix)); 

संपादित

एक सामान्य मैट्रिक्स:

public static <T> T[][] fillMatrix(Object fill, int row, int col) { 
    T[][] matrix = (T[][]) Array.newInstance(fill.getClass(), row, col); 

    for (int i = 0; i < row; i++) { 
     for (int j = 0; j < col; j++) { 
      matrix[i][j] = (T) fill; 
     } 
    } 

    return matrix; 
}  

Integer[][] zeroMatrix = fillMatrix(0, 3, 3); // a zero-filled 3x3 matrix 
String[][] stringMatrix = fillMatrix("B", 2, 2); // a B-filled 2x2 matrix 
+0

जो सही के बारे में लगता है, मैं निश्चित रूप से कुछ कहने के लिए जेनेरिकों को पर्याप्त नहीं जानता लेकिन अगर यह सही काम करता है तो यह सही होना चाहिए। :) –

+0

उम्म .... एक मिनट प्रतीक्षा करें। मुझे शुद्धता में कोई समस्या नहीं है, लेकिन मुझे दक्षता में समस्या है। आपको शुरुआत में नया इंस्टेंस ("0") रखना चाहिए, उदा। टी शून्य = .... नया इंस्टेंस ("0"), और लूप में मैट्रिक्स असाइन करें [i] [j] = शून्य। –

+0

(केवल समस्याग्रस्त अगर टी एक उत्परिवर्ती वर्ग है और मुझे नहीं लगता कि वे हैं) –

8

Arrays और जेनेरिक्स एक साथ अच्छी तरह से नहीं खेलते हैं:

"Arrays covariant हैं, जिसका अर्थ है कि सुपरटेप संदर्भों की एक सरणी उप प्रकार संदर्भों की एक सरणी का एक सुपरटेप है।यही कारण है कि Object[]String[] के महाप्रकार है और एक स्ट्रिंग सरणी प्रकार Object[] के संदर्भ चर के माध्यम से पहुँचा जा सकता है, कि "

Java Generics FAQ देखें:।

1

यदि आप वास्तव में जेनेरिक का उपयोग करना चाहते हैं, तो आप ऐसा कुछ कर सकते हैं जैसे

private <T extends Number> T[][] zeroMatrix(int row, int col, Class<T> clazz) throws InstantiationException, IllegalAccessException, 
     IllegalArgumentException, InvocationTargetException 
{ 
    T[][] retVal = (T[][]) Array.newInstance(clazz, new int[] { row, col }); 
    for (int i = 0; i < row; i++) 
    { 
     for (int j = 0; j < col; j++) 
     { 
      Constructor<T> c = clazz.getDeclaredConstructors()[0]; 
      retVal[i][j] = c.newInstance("0"); 
     } 
    } 

    return retVal; 
} 

उदाहरण:

zeroMatrix(12, 12, Integer.class); 
1

मैं एक related question which also asked about performance issues जो अपने प्रश्न संदर्भित उठाया। सर्वसम्मति स्पष्ट थी कि जेनेरिकों के लिए पुन: काम करने के लिए काफी प्रदर्शन हुआ था और इसलिए यदि आप मायने रखते हैं तो आपको प्राइमेटिव्स के साथ रहना चाहिए (मेरे लिए यह करता है)।

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