2010-10-06 42 views
29

Tôi đang cố gắng tạo một lớp chung trong Java sẽ thực hiện các phép toán trên các số. Trong ví dụ sau đây, bổ sung, như sau:Tôi có thể thực hiện các phép tính số học trên Bảng số không?

public class Example <T extends Number> { 

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

} 

Tha thứ sự ngây thơ của tôi vì tôi tương đối mới với Java Generics. Mã này không biên dịch được với lỗi:

The operator + is undefined for the argument type(s) T, T

Tôi nghĩ rằng với việc bổ sung "Số mở rộng" mã sẽ biên dịch. Có thể làm Java này hay tôi sẽ phải tạo các phương thức ghi đè cho từng loại số?

+1

Có thể muốn xem Scala hoặc Groovy nếu bạn muốn làm điều này. Họ có quá tải toán tử và chức năng ngôn ngữ cụ thể của miền :) –

Trả lời

26

Số không có toán tử + được liên kết với nó, cũng như không thể do không có quá tải toán tử.

Nó sẽ là tốt đẹp mặc dù. Về cơ bản, bạn đang yêu cầu java để autobox một descedant của Số đó xảy ra bao gồm Integer, Float và Double, có thể được autoboxed và có một toán tử cộng áp dụng, tuy nhiên, có thể có bất kỳ số lượng khác không biết con cháu của số không thể được tự động đóng hộp và điều này không thể được biết cho đến khi chạy. (Damn erasure)

+3

"có thể có bất kỳ số lượng con cháu không biết nào khác của Số không thể được tự động", chẳng hạn như 'BigInteger' và' BigDecimal', cả hai đều mở rộng 'Số'. – Powerlord

+0

Tôi nghĩ, nếu Số có .add (a, b) .sub (a, b) .mult (a, b) ... chúng ta có thể sử dụng chúng một cách đơn giản và sử dụng Generics, có thể là một giao diện NumberHero đang được thực hiện bởi IntegerHero có thể mở rộng một lớp tương tự như Integer (vì chúng ta không thể mở rộng các lớp cuối cùng), có thể thực hiện thủ thuật này không? –

0

Xem xét Example<Number>, cách + hoạt động như thế nào? Không có add hoặc tương tự trong Number hoặc thậm chí thích số Integer.

Tồi tệ hơn xem xét final class FunkyNumber extends Number { ... weird stuff, no add op ... }.

1

Có những câu hỏi tương tự với câu hỏi này và câu trả lời là bạn không thể làm như vậy.

Bạn có thể kiểm tra xem a và b là một thể hiện của Long/Double/Integer/etc hay không. và ủy quyền thêm vào các phương thức như:

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

Và bạn sẽ cần tạo một loại cho mọi loại mở rộng Số, vì vậy điều đó không thực sự khả thi. Nói cách khác, không sử dụng generics cho các phép toán số. Số như một siêu lớp là khá hạn chế.

17

Vấn đề của bạn không thực sự liên quan đến generics, thay vì các toán tử, nguyên thủy so với các đối tượng và autoboxing.

nghĩ về điều này:

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

Ở trên không biên dịch

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

Trên đây không biên dịch, nhưng chỉ vì autoboxing - đó là loại một keo cú pháp hacky giới thiệu trong Java 5, và chỉ hoạt động (trong thời gian biên dịch) với một số loại cụ thể: int-Integer chẳng hạn.

Đằng sau hậu trường, trình biên dịch Java được viết lại báo cáo kết quả cuối cùng ("Tôi phải Unbox ab để áp dụng các toán tử tổng hợp với kiểu dữ liệu nguyên thủy, và hộp kết quả để gán nó vào đối tượng c") như sau:

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

Java không thể hủy hộp thư Number vì không biết lúc biên dịch loại bê tông và do đó không thể đoán được đối tác nguyên thủy của nó.

2

Có, Nathan là chính xác. Nếu bạn muốn một cái gì đó như thế này, bạn phải viết nó cho mình

public class Example <T extends Number> { 
    private final Calculator<T> calc; 
    public Example(Calculator<T> calc) { 
     this.calc = calc; 
    } 

    public T add(T a, T b){ 
     return calc.add(a,b); 
    } 
} 

public interface Calculator<T extends Number> { 
    public T add(T a, T b); 
} 

public class IntCalc implements Calculator<Integer> { 
    public final static IntCalc INSTANCE = new IntCalc(); 
    private IntCalc(){} 
    public Integer add(Integer a, Integer b) { return a + b; } 
} 

... 

Example<Integer> ex = new Example<Integer>(IntCalc.INSTANCE); 
System.out.println(ex.add(12,13)); 

Quá xấu Java không có các lớp học kiểu (Haskell) hoặc đối tượng tiềm ẩn (Scala), nhiệm vụ này sẽ là một trường hợp sử dụng hoàn hảo ...

3

Bạn có thể làm một cái gì đó như thế này

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

Ngay cả những thư viện thời gian chạy java có vấn đề này, hầu hết các phương pháp đối phó với nguyên thủy phải lặp lại trong các chức năng tương tự.

Tùy chọn nhanh nhất là viết mã cho một loại và sau đó sao chép và thay thế loại để tạo phương thức cho các loại khác. Một kịch bản ngắn là đủ để làm điều này.

Các vấn đề liên quan