2014-05-20 12 views
7

Trong khi chơi xung quanh với các giải pháp cho this question, tôi đã đưa ra đoạn mã sau, trong đó có một số cảnh báo trình biên dịch. Một cảnh báo là:Phương pháp chung kích hoạt lỗi an toàn loại - tại sao?

Type safety: The expression of type Test.EntityCollection needs unchecked conversion to conform to Test.EntityCollection<Test.Entity>

tôi không hoàn toàn hiểu tại sao cảnh báo này xuất hiện. Bằng cách chuyển một loại Class<M> và khai báo phương thức trả về EntityCollection<M>, tại sao tôi không làm đủ để thuyết phục trình biên dịch (Java 7) rằng kiểu chính xác đang được trả về?

static class Entity { 
} 

static class EntityCollection<E extends Entity> { 

    private EntityCollection(HashMap<?, E> map) { 
    } 

    public static <T extends HashMap<?, M>, M extends Entity> EntityCollection<M> getInstance(
      Class<T> mapType, Class<M> entityType) 
      throws ReflectiveOperationException { 

     T map = mapType.getConstructor().newInstance(); 
     return new EntityCollection<M>(map); 
    } 
} 

public static void main(String[] args) throws Exception { 
    // both compiler warnings are on the line below: 
    EntityCollection<Entity> collection = EntityCollection.getInstance(
      LinkedHashMap.class, Entity.class); 
} 

Điểm thưởng nếu có ai có thể cải thiện mã để tránh hoàn toàn cảnh báo. Tôi đã nhìn chằm chằm vào nó trong một thời gian và đã không mơ ước bất kỳ cách nào để giảm bớt các cảnh báo.

+0

Hmm, với một chút thử nghiệm hơn tôi không thể nhận hoặc Java 7 hoặc Java 8 để phản đối điều này (ngoại trừ một "bạn có thể sử dụng suy luận kim cương" trên 'return new EntityCollection (map)'). Khác hơn là nó rất hạnh phúc. Tôi đang sử dụng netbeans –

+0

@RichardTingle Tôi có thể nhận được Java 1.8.0_05 để cho tôi cảnh báo nếu tôi biên dịch với 'javac -Xlint: all' trên dòng lệnh. –

Trả lời

3

Vấn đề là getInstance là một phương pháp chung nhưng bạn không chuyển các tham số kiểu chung cho nó. Bạn có thể khắc phục nó bằng cách đi qua chúng như thế này:

public static void main(String[] args) throws Exception { 
     EntityCollection<Entity> collection = EntityCollection.<LinkedHashMap, Entity>getInstance(
       LinkedHashMap.class, Entity.class); 
    } 

Bạn vẫn sẽ phải đối phó một rawtypes cảnh báo vì LinkedHashMap là một kiểu generic. Đây là vấn đề trong trường hợp của bạn vì có một ký tự đại diện trong loại khóa.

Bạn phải đối mặt với một số vấn đề ở đây:

Bạn không thể vượt qua đối tượng lớp tham số như thế này: LinkedHashMap<Object, Entity>.class vì vậy bạn có khá nhiều khó khăn với rawtypes cảnh báo.

+0

Cảm ơn lời giải thích này. Lưu ý rằng đối số 'Class entityType' của tôi là thừa và tôi có thể xóa nó một cách hạnh phúc sau khi thực hiện các sửa đổi của bạn. –

+0

Vì vậy, bạn vấn đề chính là mỗi invocation của phương pháp này tạo ra một cảnh báo và bạn sẵn sàng để ngăn chặn chúng nếu bạn di chuyển chúng vào phương pháp? –

+0

Chủ yếu là tôi đã quan tâm đến sự hiểu biết tại sao mà cảnh báo cụ thể đã nhận được, do đó bạn đã có câu trả lời được chấp nhận của tôi. Câu trả lời của Claudio có thể chứng minh hữu ích hơn trong dài hạn, do cách dễ dàng hơn mà các cảnh báo có thể bị đàn áp. –

1

Vấn đề là T. Bạn đang thêm một ràng buộc vào phương pháp của bạn nói rằng T nên mở rộng HashMap<?, M>. Tuy nhiên, cách bạn sau này tham chiếu đến T giống như một tham số chung của loại Class (Class<T>). LinkedHashMap.class là loại Class<LinkedHashMap> không phải Class<LinkedHashmap<?, Entity>> (đó là những gì bạn cần)

Đối tượng Lớp luôn tham chiếu loại không được tham số hóa và điều đó có ý nghĩa. Vì ràng buộc chung tồn tại trong thời gian biên dịch, và bạn sẽ sử dụng Lớp đó để phản ánh động trạng thái và hành vi của một cá thể trong thời gian chạy. Dài câu chuyện ngắn, bạn có thể sử dụng một Class<HashMap> để xây dựng một trường hợp mới, không bị ràng buộc với bất kỳ loại nào.

Vì vậy, tôi đoán những gì bạn cần làm để mã của bạn để thay đổi điều đó hạn chế trong hình thức của nó như sau:

public static <T extends HashMap, M extends Entity> EntityCollection<M> getInstance(
      Class<T> mapType, Class<M> entityType) 
      throws ReflectiveOperationException { 

     T map = mapType.getConstructor().newInstance(); 
     return new EntityCollection<M>(map); 
} 
+0

Tôi thích cách này kéo cảnh báo vào phương thức factory (nơi chúng có thể bị chặn bằng '@SuppressWarnings ({" rawtypes "," unchecked "})') thay vì tiết lộ chúng cho người gọi. –

+0

Có, tôi không xóa hoàn toàn cảnh báo từ đây. Generics là cách quá cứng nhắc trong Java và tôi nghĩ rằng họ rơi ngắn trong những thứ như thế này. Tuy nhiên, câu hỏi là, chúng ta thực sự cần nhiều hơn? Việc đóng gói cảnh báo trên phương pháp nhà máy là đủ tốt và không thêm bất kỳ sự phức tạp nào thêm. – Claudio

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