2012-12-26 11 views
6

मैं Float, DoubleInteger की तरह आवरण प्रकार के लिए केवल एक ही आपरेशन प्रति सामान्य विधि का उपयोग कर, बुनियादी अंकगणितीय आपरेशनों इसके अलावा, घटाव, गुणा और भाग की तरह प्रदर्शन करने के लिए चाहते हैं प्रदर्शन करने के लिए एक सामान्य वर्ग का उपयोग करना ... (BigDecimal को छोड़कर और BigInteger)।बुनियादी अंकगणितीय आपरेशनों

मैंने एक सामान्य वर्ग का उपयोग करके निम्नलिखित (अतिरिक्त के लिए) कुछ करने की कोशिश की है।

public final class GenericClass<E extends Number> { 

    public E add(E x, E y) { 
     return x + y; // Compile-time error 
    } 
} 

यह एक संकलन समय त्रुटि जारी करता है, ई के लिए

ऑपरेटर + लागू नहीं किया जा सकता है, ई

इस तरह के आपरेशनों को प्राप्त करने के इस तरह के एक सामान्य संस्करण का उपयोग करने का कोई तरीका है ?

+1

इस समस्या डोमेन overengineering की तरह लगता है का उपयोग कर अंकगणितीय आपरेशनों पर काम करने की इच्छुक है। – Woot4Moo

उत्तर

8

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

1

आम तौर पर आपको इसकी आवश्यकता नहीं है क्योंकि यह "सुपर" प्रकार का उपयोग करने के लिए सरल और अधिक कुशल है जैसे डबल या बिगडिसीमल जो कि किसी भी प्रकार के किसी भी मूल्य का प्रतिनिधित्व कर सकता है।

नोट: double इसके संदर्भ में Integer के आधे से भी कम स्थान का उपयोग करता है।

1

Number एक वर्ग प्रकार है, इसलिए आदिम प्रकार ऑपरेटर लागू नहीं होते हैं। इसके अतिरिक्त, जावा don't support आदिम प्रकारों में जेनेरिक, इसलिए आप केवल प्राचीन प्रकारों को अनुमति देने के लिए ई को बांधने में सक्षम नहीं होंगे।

इस तरह का एक तरीका प्रत्येक प्राचीन प्रकार को संभालने के लिए होगा कि संख्या जोड़ें विधि में अलग-अलग समर्थन करती है, लेकिन मुझे लगता है कि जो आप पूरा करने की कोशिश कर रहे हैं उसे पराजित करता है।

6

नहीं, आप ऐसा नहीं कर सकते क्योंकि + ऑपरेटर संख्या वर्ग का हिस्सा नहीं है।

तुम भी कर सकते थे

static void test() { 

    MyInteger my = new MyInteger(); 
    Integer i = 1, j = 2, k; 
    k = my.add(i, j); 
    System.out.println(k); 
} 

static public abstract class GenericClass<E extends Number> { 
    public abstract E add(E x, E y); 
} 

static public class MyInteger extends GenericClass<Integer> { 
    @Override 
    public Integer add(Integer x, Integer y) { 
     return x + y; 
    }  
} 

: आप क्या कर सकते एक सार आधार वर्ग बनाने के लिए है और इसे से फैली हुई है (मैं आदेश परीक्षण की सुविधा के लिए इन कक्षाओं में स्थिर किया, लेकिन आप इस संशोधक निकाल सकते हैं।) एक अमूर्त फ़ंक्शन जोड़ें जो पैरामीटर ले जाएगा और वापस लौटाएगा और टाइप नंबर का रिटर्न वैल्यू और इसे और उप-वर्गों को ओवरराइड करेगा लेकिन रिटर्न वैल्यू के लिए आवश्यक कास्टिंग इसकी उपयोगिता को हरा देगा।

+0

प्रश्न में परिदृश्य के बारे में, इस तरह से एक सामान्य वर्ग का उपयोग करने का कोई मतलब नहीं है। इसके अतिरिक्त, जावा में इस तरह से एक स्थिर वर्ग की घोषणा की अनुमति नहीं है (हालांकि यह सी # के मामले में है)। एक स्थैतिक वर्ग में ऐसा होना चाहिए कि कोई भी स्थैतिक ** ** वर्ग (बाहरीतम कक्षाएं स्थिर नहीं हो) हो। यानी एक स्थैतिक वर्ग कम से कम एक बाहरीतम स्थैतिक वर्ग द्वारा निहित होना चाहिए। – Lion

+0

स्थैतिक वर्गों के लिए, मैंने यह नहीं कहा कि मैं उन्हें किसी अन्य वर्ग में नहीं लगा रहा था। मैंने इन स्थिरों को बस इसलिए बनाया क्योंकि मैं उन्हें एक स्थिर कार्य से instanciating था, लेकिन आप सही हैं, यह हर जगह इस शब्द को हटाने के लिए आसान होगा। आपके अन्य बयान के अनुसार, "प्रश्न में परिदृश्य के बारे में, इस तरह से एक सामान्य वर्ग का उपयोग करने का कोई मतलब नहीं है", मुझे यह समझने में पूरी तरह से यकीन नहीं है कि आप क्या कह रहे हैं लेकिन मुझे बस इतना कहना है कि जावा में बस असंभव है जैसा कि वर्णन किया गया है मूल परिदृश्य को हल करने के लिए। – SylvainL

2

मैं सोच सकता हूं कि इस प्रकार को अज्ञात प्रकार के रूप में प्राप्त करना और उदाहरण का उपयोग करना है।

कुछ की तरह:

public class GenericClass<? extends Number>{ 
    public Integer add(? x, ? y){ 
     if(x instance of Integer && y instance of Integer){ 
      //Do your math with Integer class methods help 
      //Return here 
     } 
     return (Interger)null; 
    } 

} 

लेकिन यकीन नहीं:/

1

अफोंसो ने सुझाव दिया के रूप में, एक और संभावना एक समारोह बना सकते हैं और नीचे सभी आवश्यक संभावनाओं लिखने के लिए होगा। यहाँ कुछ बदलाव होते रहते हैं:

 // Examples with static functions: 
     Integer i = addNumbers (1, 2); // OK 
     Double d = addNumbers (3.0, 4.0); // OK 
     String s = addObjects ("a", "b"); // OK 
// 
     // Example with a raw type for a class with both method 
     // (or member function) and static functions: 
GenericClass gc = new GenericClass(); // Raw type 
// 
     // Note the error if we don't add a cast: 
// i = gc.add(1, 2); // Error: Cannot convert from Number to Integer 
// 
     // Now OK with a cast but with a Type safety warning: 
     i = (Integer) gc.add (1, 2); // Type safety warning. 
     i = GenericClass.add2 (1, 2); // OK 
     i = GenericClass.add3 (1, 2); // OK 
//  
     // Example with an instanciated type for the same class: 
     GenericClass<Integer> gc1 = new GenericClass<Integer>(); 
// 
     // Note that we don't need a cast anymore: 
     i = gc1.add(1, 2); // Now OK even without casting. 
// 
     i = GenericClass2.add2 (1, 2); // OK 
     s = GenericClass2.add2 ("a", "b"); // OK 
     i = GenericClass2.<Integer>add2 (1, 2); // OK. 
     d = GenericClass2.<Double>add2 (1.0, 2.0); // OK 
     s = GenericClass2.<String>add2 ("a", "b"); // OK 
// 
    public static<T extends Number> T addNumbers(T x, T y) { 

     if (x instanceof Integer && y instanceof Integer){ 
      return (T) (Integer) ((Integer)x + (Integer)y); 
     } else if (x instanceof Double && y instanceof Double){ 
      return (T) (Double) ((Double)x + (Double)y); 
     } else 
      return (T)null; 
    } 
//  
    public static<T> T addObjects(T x, T y) { 

     if (x instanceof Integer && y instanceof Integer) { 
     // 
     // We must add an (Integer) cast because the type of the operation 
     // "((Integer)x + (Integer)y))" is "int" and not "Integer" and we 
     // cannot directly convert from "int" to "T". Same thing for Double 
     // but not for the type String: 
     // 
      return (T) (Integer) ((Integer)x + (Integer)y); 
     } else if (x instanceof Double && y instanceof Double) { 
      return (T) (Double) ((Double)x + (Double)y); 
     } else if (x instanceof String && y instanceof String) { 
      return (T) ((String)x + (String)y);    
     } else 
      return (T)null; 
    } 
// 
    static class GenericClass<T extends Number> { 

     public T add(T x, T y) { 
      if (x instanceof Integer && y instanceof Integer) { 
       return (T) (Integer) ((Integer)x + (Integer)y); 
      } else if (x instanceof Double && y instanceof Double) { 
       return (T) (Double) ((Double)x + (Double)y); 
      } else 
       return (T)null; 
     } 
// 
     // The type <T> here is NOT the same as the one for the class. 
     // We should rename it in order to make this clearer. See add3() 
     // for an example of this. 
     public static<T> T add2(T x, T y) { 
      if (x instanceof Integer && y instanceof Integer) { 
       return (T) (Integer) ((Integer)x + (Integer)y); 
      } else if (x instanceof Double && y instanceof Double) { 
       return (T) (Double) ((Double)x + (Double)y); 
      } else if (x instanceof String && y instanceof String) { 
       return (T) ((String)x + (String)y); 
      } else 
       return (T)null; 
     } 
// 
     // The type here is not the same as the one for the class 
     // so we have renamed it from <T> to <N> to make it clearer. 
     public static<N extends Number> N add3(N x, N y) { 
      if (x instanceof Integer && y instanceof Integer) { 
       return (N) (Integer) ((Integer)x + (Integer)y); 
      } else if (x instanceof Double && y instanceof Double) { 
       return (N) (Double) ((Double)x + (Double)y); 
      } else 
       return (N)null; 
     } 
    } 
1

Louis Wasserman के रूप में बताया, वहाँ जावा में ऐसा करने के लिए कोई रास्ता नहीं है। हालांकि, कुछ समाधान-बहुत मुश्किल प्रोग्रामिंग का उपयोग करके एक समाधान प्रस्तुत किया जा सकता है।आइए समाधान के साथ शुरू करें जो मुझे पसंद है: SylvainL का प्रश्न का उत्तर। हालांकि, मेरा मानना ​​है कि हम एक कदम पीछे जा सकते हैं और के के हर प्रकार को संभाल सकते हैं। यदि आप Java API देखते हैं, तो आप ध्यान दें कि Number के किसी उप-वर्ग को कुछ अमूर्त विधियों को ओवरराइड करना होगा; अर्थात् intValue() (साथ ही अन्य)। इन तरीकों का उपयोग करके, हम पॉलिमॉर्फिज्म को अपनी वास्तविक क्षमता में उपयोग कर सकते हैं। वर्ग हम SylvainL के जवाब से है लिया, हम इस तरह के रूप में एक नया वर्ग का उत्पादन कर सकते हैं:

public final class EveryNumberClass<E extends Number> 
{ 
    public static int add(E x, E y) 
    { 
     return x.intValue() + y.intValue(); 
    } 

    public static int subract(E x, E y) 
    { 
     return x.intValue() - y.intValue(); 
    } 
} 

ये अभियान गुणा और भाग करने के लिए विस्तारित किया जा सकता है, और जब Integer रों तक ही सीमित नहीं, लेने के लिए इस्तेमाल किया जा सकता मेंNumber और एक ऑपरेशन दिए गए उचित व्यवहार को व्यक्त करें। और intValue() विधि का व्यवहारNumber का एक पूर्णांक प्रतिनिधित्व वापस नहीं कर सकता है, यह निश्चित रूप से करता है (मैंने most numbers के लिए स्रोत कोड में देखा, जिसमें atomic ones और math ones शामिल हैं)। एकमात्र समस्या तब होगी जब अप्रत्याशित व्यवहार intValue() से वापस आ जाएगा, जो परमाणु संख्याओं के साथ हो सकता है, उपयोगकर्ता ने Number एस परिभाषित किया है, या जब बड़ी संख्या को कम करने के लिए मजबूर किया जाता है। यदि वे आपकी परियोजना (या आपकी लाइब्रेरी के लिए) के लिए चिंतित हैं, तो मैं long मानों का उपयोग करने पर विचार करता हूं, या SylvainL के उत्तर का जिक्र करता हूं।

0

आशा इस कोई मदद कर सकता है, जो जेनेरिक्स

public <T> T add(T a, T b) 
    { 
     return (T) (String.valueOf((Integer.parseInt(a.toString()) + Integer.parseInt(b.toString())))); 
    } 
    public <T> T sub(T a, T b) 
    { 
     return (T) (String.valueOf((Integer.parseInt(a.toString()) - Integer.parseInt(b.toString())))); 
    } 
    public < T> T mul(T a,T b) 
    { 
     return (T) (String.valueOf((Integer.parseInt(a.toString()) * Integer.parseInt(b.toString())))); 
    } 
    public <T> T div (T a, T b) 
    { 
     return (T) (String.valueOf((Integer.parseInt(a.toString())/Integer.parseInt(b.toString())))); 
    } 
    public <T> T mod(T a, T b) 
    { 
     return (T) (String.valueOf((Integer.parseInt(a.toString()) % Integer.parseInt(b.toString())))); 
    } 
    public <T> T leftShift(T a, T b) 
    { 
     return (T) (String.valueOf((Integer.parseInt(a.toString()) << Integer.parseInt(b.toString())))); 
    } 
    public <T> T rightShift(T a, T b) 
    { 
     return (T) (String.valueOf((Integer.parseInt(a.toString()) >> Integer.parseInt(b.toString())))); 
    } 
0
enum Operator { 
    ADD, SUBTRACT, DIVIDE, MULTIPLY; 
} 

public class GenericArithmeticOperation { 

    public GenericArithmeticOperation() { 
     // default constructor 
    } 

    public <E> Integer doArithmeticOperation(E operand1, E operand2, Operator operator) { 
     if (operand1 instanceof Integer && operand2 instanceof Integer) { 
      switch (operator) { 
      case ADD: 
       return (Integer) ((Integer) operand1 + (Integer) operand2); 
      case SUBTRACT: 
       return (Integer) ((Integer) operand1 - (Integer) operand2); 
      case MULTIPLY: 
       return (Integer) ((Integer) operand1 * (Integer) operand2); 
      case DIVIDE: 
       return (Integer) ((Integer) operand1/(Integer) operand2); 
      } 
     } 
     throw new RuntimeException(operator + "is unsupported"); 
    } 

    public static void main(String[] args) { 
     GenericArithmeticOperation genericArithmeticOperation = new GenericArithmeticOperation(); 
     System.out.println(genericArithmeticOperation.doArithmeticOperation(10, 6, Operator.ADD)); 
     System.out.println(genericArithmeticOperation.doArithmeticOperation(10, 6, Operator.SUBTRACT)); 
     System.out.println(genericArithmeticOperation.doArithmeticOperation(4, 6, Operator.MULTIPLY)); 
     System.out.println(genericArithmeticOperation.doArithmeticOperation(21, 5, Operator.DIVIDE)); 
    } 
} 
संबंधित मुद्दे