2010-10-03 20 views
16

Chcę zrobić ogólną metodę, która składa się z łącznej liczby List liczb.Java: Ogólne metody i numery

Co starałem to:

public static <T extends Number> T sumList(List<T> data) 
{ 
    T total = 0; 
    for (T elem : data) 
    { 
     total += elem; 
    } 
    return total; 
} 

Ale problemem jest to, że there is no += operator in T i że total can't be assigned to zero.

Jak mogę to zrobić?

Dzięki

+5

Wyjaśnia to wyraźnie, dlaczego język C++ jest lepszy od języka Java. :-P –

+1

@Chris: Rzeczywiście. C++ jest lepszy w tym przypadku ... –

+0

@ Cris, Martijn: Czy możesz wskazać na przykładowy kod, który wykonuje powyższe zadanie. Straciłem kontakt z C++. Chcę tylko zobaczyć, jak to zrobi w C++. – Emil

Odpowiedz

18

Są sposoby na zhackowanie tego wszystkiego, ale ogólnie rzecz biorąc, generics nie jest po prostu drogą do tego. Zbuduj metodę dla każdego konkretnego typu pierwotnego opakowania i zaimplementuj je osobno. To będzie zbyt dużo bólu głowy, aby uczynić go ogólnym; operacje arytmetyczne nie mogą się zdarzyć w sposób ogólny.

Tak naprawdę nic nie zyskujesz, również poprzez generowanie. To taki prosty i stały kod, że nie martwisz się powielaniem kodu, ponieważ to się nie zmieni. A ludzie nie będą przekazywać kodu swojego rodzaju; Domena typów, których dotyczy, jest już dobrze zdefiniowana i skończona.

+5

To boli, że to prawda, ale jest (+1) –

+10

wow to mnie zasmuca. – nont

4

Robiłem to niedawno (na podstawie kodu lambdaj) uwaga będzie potrzebował wszystkich swoich elementów być tego samego typu (naprawdę nie można dodać Byte i BigDecimal) i może rzucić CCE jeśli to nie jest i nie będzie obsługiwać niestandardowe Number:

public class SumAggregator<T extends Number> { 
    public T aggregate(Iterable<T> iterable) { 
     T result = null; 
     for (T item : iterable) { 
      result = aggregate(result, item); 
     } 
     return result; 
    } 


    @SuppressWarnings("unchecked") 
    protected T aggregate(T first, T second) { 
     if (first == null) { 
      return second; 
     } else if (second == null) { 
      return first; 
     } else if (first instanceof BigDecimal) { 
      return (T) aggregate((BigDecimal) first, (BigDecimal) second); 
     } else if (second instanceof BigInteger) { 
      return (T) aggregate((BigInteger) first, (BigInteger) second); 
     } else if (first instanceof Byte) { 
      return (T) aggregate((Byte) first, (Byte) second); 
     } else if (first instanceof Double) { 
      return (T) aggregate((Double) first, (Double) second); 
     } else if (first instanceof Float) { 
      return (T) aggregate((Float) first, (Float) second); 
     } else if (first instanceof Integer) { 
      return (T) aggregate((Integer) first, (Integer) second); 
     } else if (first instanceof Long) { 
      return (T) aggregate((Long) first, (Long) second); 
     } else if (first instanceof Short) { 
      return (T) aggregate((Short) first, (Short) second); 
     } else { 
      throw new UnsupportedOperationException("SumAggregator only supports official subclasses of Number"); 
     } 
    } 

    private BigDecimal aggregate(BigDecimal first, BigDecimal second) { 
     return first.add(second); 
    } 

    private BigInteger aggregate(BigInteger first, BigInteger second) { 
     return first.add(second); 
    } 

    private Byte aggregate(Byte first, Byte second) { 
     return (byte) (first + second); 
    } 

    private Double aggregate(Double first, Double second) { 
     return first + second; 
    } 

    private Float aggregate(Float first, Float second) { 
     return first + second; 
    } 

    private Integer aggregate(Integer first, Integer second) { 
     return first + second; 
    } 

    private Long aggregate(Long first, Long second) { 
     return first + second; 
    } 

    private Short aggregate(Short first, Short second) { 
     return (short) (first + second); 
    } 
} 

This code executed on ideone with examples.

+0

Dzięki, Colin. Ale w mojej sytuacji chcę użyć krótkiego kodu. Zapamiętam twoją pocztę, kiedy naprawdę potrzebuję generycznych. Ale mogę się obejść bez niego. –

+0

@Martijn Courteaux, w moim przypadku, nie mógłbym obejść się bez generycznych, ale jeśli można uniknąć generycznych i uniknąć, aby skończyć z tego rodzaju kodem (który jest naprawdę ciężki IMO [tony obsady]) powinieneś obejść się bez generycznych . –

+0

Rzeczywiście, o to chodzi. –

0

Możesz użyć biblioteki, takiej jak Generic Java Math (jej część numerów), która zapewnia ogólne operacje dla podklas Liczba. Zapewnia to sposób na ogólną pracę z liczbami, tak jak w twoim przykładzie, ale z przekazywaniem obiektu arytmetycznego, który dokonuje rzeczywistych obliczeń. Zobacz przykład na stronie głównej.
Musi używać typów pudełkowych, więc jeśli potrzebujesz prędkości, żadna implementacja generalna nie może tego zrobić w Javie, musisz użyć typów podstawowych.

0

Wystarczy popatrzeć na następujący przykład metoda rodzajowa dla sumowania dowolnego typu Ilość zmiennych list ... Jestem pewien, że to jest to, co zostało z prośbą o ..

Mark Peters jest również słuszne w jego odpowiedź, ale jest to również rozwiązanie, do którego należy dążyć.

public class GenericSum { 
@SuppressWarnings("unchecked") 
public static <E> E sumArray(E[] inputArray) { 
    Double result = 0.0; 
    // Sum array elements 
    for (E element : inputArray) { 
     result = ((Number) result).doubleValue() 
       + ((Number) element).doubleValue(); 
    } 
    return ((E) result); 
} 

public static void main(String args[]) { 
    // Create arrays of Integer, Double 
    Integer[] intArray = { 1, 2, 3, 4, 5 }; 
    Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; 

    System.out.println("Sum of doubles : " + sumArray(intArray)); 
    System.out.println("Sum of doubles : " + sumArray(doubleArray)); 
} 

} 
+0

to konwertuje wszystko na podwójne, co nie jest celem – NimChimpsky