Posso eseguire operazioni aritmetiche sulla baseclass Number?

Sto cercando di creare una class generica in Java che eseguirà operazioni sui numeri. Nell’esempio seguente, aggiunta, come segue:

public class Example  { public T add(T a, T b){ return a + b; } } 

Perdona la mia ingenuità dato che sono relativamente nuovo a Java Generics. Questo codice non riesce a compilare con l’errore:

L’operatore + non è definito per il tipo di argomento T, T

Ho pensato che con l’aggiunta di “extends Number” il codice si sarebbe compilato. È ansible fare questo Java o dovrò creare metodi sovrascritti per ogni tipo di Numero?

Il numero non ha un operatore + ad esso associato, né può esserlo poiché non vi è alcun sovraccarico dell’operatore.

Sarebbe carino comunque.

Fondamentalmente, stai chiedendo a java di autobox un descedant di Number che capita di includere Integer, Float e Double, che potrebbero essere autoboxed e avere un operatore plus applicato, tuttavia, potrebbe esserci un qualsiasi numero di altri discendenti sconosciuti di Number che non può essere autoboxed e questo non può essere conosciuto fino al runtime. (Dannazione cancellata)

Il tuo problema non è legato ai generici, piuttosto agli operatori, alle primitive rispetto agli oggetti e al selfboxing.

Pensaci:

 public static void main(String[] args) { Number a = new Integer(2); Number b = new Integer(3); Number c = a + b; } 

Quanto sopra non viene compilato

 public static void main(String[] args) { Integer a = new Integer(2); Integer b = new Integer(3); Number c = a + b; } 

Quanto sopra non viene compilato, ma solo a causa dell’autoboxing, che è una sorta di colla di syntax hacky introdotta in Java 5, e funziona solo (in fase di compilazione) con alcuni tipi concreti: int-Integer per esempio.

Dietro le quinte, il compilatore Java sta riscrivendo l’ultima istruzione (“Devo annullare unbox a e b per applicare l’operatore sum con i tipi di dati primitivi e boxare il risultato per assegnarlo all’object c “):

  Number c = Integer.valueOf( a.intValue() + b.intValue() ); 

Java non può unbox un Number perché non conosce al momento della compilazione il tipo concreto e quindi non può indovinare la sua controparte primitiva.

Puoi fare qualcosa di simile

  class Example  { public Number add(T a, T b){ return new Double(a.doubleValue() + b.doubleValue()); } } 

Sì, Nathan ha ragione. Se vuoi qualcosa di simile, devi scriverlo da solo

 public class Example  { private final Calculator calc; public Example(Calculator calc) { this.calc = calc; } public T add(T a, T b){ return calc.add(a,b); } } public interface Calculator { public T add(T a, T b); } public class IntCalc implements Calculator { public final static IntCalc INSTANCE = new IntCalc(); private IntCalc(){} public Integer add(Integer a, Integer b) { return a + b; } } ... Example ex = new Example(IntCalc.INSTANCE); System.out.println(ex.add(12,13)); 

Peccato che Java non abbia classi di tipi (Haskell) o oggetti impliciti (Scala), questo compito sarebbe un caso d’uso perfetto …

Ci sono domande simili a questa, e la risposta è che non puoi farlo in quel modo.

Potresti controllare se aeb sono un’istanza di Long / Double / Integer / etc. e debind l’aggiunta a metodi come:

 public Integer add(Integer a, Integer b) { return a+b; // this actually uses auto boxing and unboxing to int } 

E dovresti crearne uno per ogni tipo che estende Number, quindi non è fattibile. In altre parole, non utilizzare i generici per operazioni numeriche. Il numero come una superclass è piuttosto limitato.

Considera Example , come funzionerebbe + su questo? Non vi è alcun add o simile in Number o anche i like di Integer .

Peggio ancora considerare la final class FunkyNumber extends Number { ... weird stuff, no add op ... } .

Anche la libreria runtime Java ha questo problema, la maggior parte dei metodi che si occupano di primitive devono duplicare la stessa funzionalità.

L’opzione più veloce sarebbe quella di scrivere il codice per un tipo, quindi copiarlo e sostituirlo per generare i metodi per gli altri tipi. Un breve script dovrebbe essere sufficiente per farlo.