2012-08-13 22 views
19

Tôi có siêu lớp Foo. Và một quán Bar mở rộng nó.xung đột tên Java Generics, có cùng một sự xóa bỏ

public class Bar extends Foo 

Chức năng trong Foo:

protected void saveAll(Collection<?> many) 

Chức năng trong Bar:

public void saveAll(Collection<MyClass> stuff) { 
    super.saveAll(stuff); 
} 

Bắt lỗi:

Name clash: The method saveAll(Collection<MyClass>) of type Bar has the same erasure as saveAll(Collection<?>) of type Foo but does not override it. 

Tôi đang làm gì sai?

+2

Tôi đã tự do xóa thẻ 'ngủ đông' vì dường như không liên quan đến câu hỏi. –

Trả lời

12

Bạn đang ghi đè phương thức saveAll với loại không tương thích. Có lẽ bạn muốn làm một cái gì đó như:

public class Bar extends Foo<MyClass> 

Chức năng trong Foo<E>

protected void saveAll(Collection<E> many) 

và chức năng trong Bar:

public void saveAll(Collection<MyClass> stuff) { 
    super.saveAll(stuff); 
} 
+1

Foo sau đó cần phải được khai báo là 'public class Foo ' ... –

8

Do tính năng loại tẩy xoá của Java, JVM sẽ không có thể biết liệu nó có phải là phương thức có kiểu MyClass được tham số hay là kiểu đầu tiên cần được gọi.

Nếu có thể hoặc áp dụng, mô hình phổ biến nhất là sử dụng tôi đã nhìn thấy để tránh điều này là thay đổi lớp Foo để có một loại parametrized cũng như:

public class Foo<T> { 
    protected void saveAll(Collection<T> many) {} 
} 

và sau đó có Bar chỉ đơn giản là thực hiện Foo cho loại cụ thể của bạn:

public class Bar extends Foo<MyClass> { 
    public void saveAll(Collection<MyClass> many) { 
     super.saveAll(many); 
    } 
} 
+0

Lưu ý: Điều này không giúp Foo là một giao diện, nếu một lớp thực hiện Bar có thể (thiết kế xấu) thực hiện 'Foo ' và 'Foo 'nơi bạn chạy lại trong cùng một kiểu xóa vì tham số chung bị xóa thành' Bộ sưu tập' một lần nữa. "Tốt hơn" sử dụng 'T' làm Tham số –

1

Khi trình biên dịch biên dịch thành mã byte một quá trình được gọi là Xoá bỏ xảy ra. Điều này loại bỏ các thông tin loại từ các bộ sưu tập. Tôi tin rằng nó sẽ tự làm các phôi vv như là một phần của quá trình tạo mã byte. Nếu bạn loại bỏ các phần chung của lớp học của bạn (ví dụ: < ..>) thì bạn sẽ thấy bạn có hai phương thức saveAll. Lỗi là bạn có hai lưu tất cả các phương thức sẽ có chữ ký giống nhau. Các bộ sưu tập có đối tượng kiểu trong mã byte.

Hãy thử xóa < ..> có thể làm cho nó rõ ràng hơn. Khi bạn đặt < ...> quay lại sau đó xem xét tên của các phương thức. Nếu chúng khác nhau thì nó nên biên dịch.

Ngoài ra tôi không nghĩ rằng đây là vấn đề hibernate nên thẻ này nên được loại bỏ. Đây là một vấn đề chung về java mà bạn có.

gì bạn có thể làm ở đây là gõ lớp

public class Bar extends Foo<MyClass> 

và sau đó có các loại phương pháp để T

public void saveAll(Collection<MyClass> stuff) { 
    super.saveAll(stuff); 
} 

và sau đó là tuyên bố của Foo sẽ là một cái gì đó giống như

public abstract class Bar extends Foo<T> { 
    public void saveAll(Collection<T> stuff) { 
} 
+1

Tại sao bỏ phiếu xuống? – RNJ

1

Bạn chỉ ghi đè các phương thức có Chữ ký khác nhau.

Ý tưởng hay là sử dụng quy tắc PECS (Nhà sản xuất - Mở rộng, Người tiêu dùng - Siêu) được mô tả trong Ấn bản Java hiệu quả thứ hai của Joshua Bloch.

theo quy tắc này, nó sẽ trông như thế này.

Trong lớp Foo:

public class Foo<E>{ 

protected void saveAll(Collection<? super E> many){....} 

protected void getAll(Collection<? extends E> many){....} 

} 
+0

Trên thực tế, phương thức saveAll có thể sẽ lặp qua danh sách và lưu từng phần tử, và do đó xử lý danh sách như một nhà sản xuất. Trong trường hợp đó, nó cần phải được định nghĩa là 'void void saveAll (Bộ sưu tập nhiều) {....} ' – herman

4

Khi chạy, các loại tham số được thay thế bằng Object. Vì vậy, saveAll(Collection<?>)saveAll(Collection<MyClass>) được chuyển thành saveAll(Collection). Đây là một cuộc đụng độ tên. Hãy xem here để biết chi tiết.

Bạn có thể làm điều này:

public class Foo<T> { 
    protected void saveAll(Collection many) { 
     // do stuff 
    } 
} 

public class Bar extends Foo<MyClass> { 
} 
+1

Điều gì xảy ra nếu giao diện là chỉ đọc? – MAZDAK

+0

@MAZDAK xin lỗi nhưng tôi không hiểu câu hỏi của bạn. – gontard

+0

Tôi đã cố gắng thực hiện điều này bằng 'org.apache.kafka.common.serialization.Serializer' nhưng không thể chỉnh sửa giao diện này. – MAZDAK

0

Trong khi câu trả lời hiện tại là chính xác, lỗi này một cách dễ dàng xảy ra khi bạn khai báo kiểu thực tế không nằm trong "extends ..." khoản nhưng trong tên lớp thực tế:

sai:

public class Bar<MyClass> extends Foo 
{ 
    ... 
} 

đúng:

public class Bar extends Foo<MyClass> 
{ 
    ... 
} 
Các vấn đề liên quan