2015-03-27 28 views
20

Tôi có một cặp lớp ClassA & ClassB như hình dưới đây.
trường hợp 1:Java Generics - Phương pháp ghi đè

class ClassA<T extends Number>{ 
    void method(T t){} 
} 

class ClassB extends ClassA<Integer>{ 
    @Override 
    void method(Integer i){} 
} 

trường hợp 2:

class ClassA{ 
    void method(Number t){} 
} 

class ClassB extends ClassA{ 
    @Override 
    void method(Integer i){} 
} 

Tôi có hai câu hỏi ở đây.
[q1] Tôi có đúng không nếu tôi nói vậy, case2 là biểu diễn thời gian chạy của case1 (sau khi xóa)?

[q2] Nếu tôi đúng về [q1], thì tại sao case1 được chấp nhận là ghi đè hợp lệ? (Tôi biết lý do tại sao case2 không phải là ghi đè hợp lệ vì các thông số không giống nhau.)

Ai đó hãy làm sáng tỏ điều này. Cảm ơn trước.

+1

Trong trường hợp '1', nó được xác định rằng 'T' là' Số nguyên', do đó trọng số với 'T = Số nguyên' là hợp lệ. Nhưng 'Số' không phải là' Số nguyên', nó sẽ hoạt động nếu nó là ' '.Hoặc ít nhất là có thể làm việc, tôi cần phải kiểm tra. – EpicPandaForce

Trả lời

20

Câu trả lời cho [q1] là không. Trình biên dịch sẽ tạo ra phương pháp cầu trong ClassB mà thực sự sẽ vượt qua method(Number).

class ClassB extends ClassA{ 
    // bridge method 
    void method(Number i){ 
     method((Integer)i); 
    } 

    void method(Integer i){} 
} 

Bạn sẽ có câu trả lời hoàn chỉnh trong số java doc về loại tẩy xóa.

0

Siêu lớp thực tế của ClassBClassA<Integer>. Do chức năng thành viên method có thời gian biên dịch chữ ký:

void method(Integer t){} 

Bạn có thể thuyết phục chính mình bằng cách gọi một cái gì đó giống như

ClassA a = new ClassB(); 
a.method(1.0); 

Bạn sẽ thấy một lỗi thời gian chạy. Trong thực tế nó chỉ có thể biên dịch này, bởi vì tôi đã sử dụng phiên bản xóa của ClassA. Trên thực tế, mọi chuyển nhượng cho loại chung chung trừ ClassA<Integer> (ví dụ: ClassA<Number>) sẽ không thành công do các loại không tương thích.

1

Trong Java (kể từ phiên bản 5) các kiểu trả về của một phương thức ghi đè phải là biến thể và các tham số của các phương thức ghi đè phải là contravariant.

Điều đó có nghĩa là lớp ghi đè có thể cụ thể hơn trong những gì nó trả về và chấp nhận nhiều hơn trong những gì nó nhận được.

Trong ví dụ thứ 2 của bạn, hãy tưởng tượng biến số loại ClassA với phiên bản ClassB làm giá trị. Tuy nhiên

ClassA a = new ClassB(); // This is legal, since ClassB is a subclass of ClassA 
a.method(1.0); // This is legal, since ClassA.method accepts Number 

Cách khác sẽ là ok:

public class ClassC { public Number method(Integer i) {...} } 
public class ClassD extends ClassC { 
    @Override 
    public Integer method(Number n) {...} 
} 

là hợp lệ, vì ClassD vẫn đáp ứng các hợp đồng được xác định bởi ClassC.

+1

-1, xin lỗi. Điều này sai: các kiểu tham số của các phương thức ghi đè phải khớp với * chính xác *. Contravariance không đủ. Mã ví dụ của bạn sẽ không biên dịch. – ruakh

+0

'ClassA a = new ClassB(); a.method (1.0); 'chỉ hoạt động vì một kiểu thô. (Nó sẽ ném một 'ClassCastException'.) Hơn nữa phương pháp ghi đè trong Java làm ** không ** cho phép các tham số contravariant. – Radiodef

+0

Bạn nói đúng. Một phương thức cầu đã được tạo cho các đối số contravariant. –

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