2014-09-03 17 views
9

Giả sử tôi có một lớp chung mà tôi sử dụng mà tuyên bố như thế này:Java generic đối tượng với nhiều giao diện đúc

public class ConfigurableRuleKey<R extends Configurable & Rule> extends Key<R> { 

    private final R rule 

    public ConfigurableRuleKey(R rule) { 
     this.rule = rule; 
    } 

    /* Additional methods are declared here */ 

} 

Và tôi muốn thực hiện một phương pháp nhà máy để kiểm tra nếu quy tắc thông qua thực hiện giao diện Configurable, khi tạo quy tắc cấu hình hoặc chỉ cần tạo một phím cơ bản:

public static <R extends Rule> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return new ConfigurableRuleKey<>(rule); //This will not compile 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 

vấn đề là trong phương pháp nhà máy của tôi, tôi không thể vượt qua quy tắc để xây dựng các ConfigurableRuleKey bởi vì nó không phù hợp với những hạn chế chung tuyên bố (sự kiện nếu tôi muốn exp kiểm tra cẩn thận rằng nó thực hiện Configurable). Câu hỏi đặt ra là làm cách nào để tôi có thể truyền đối tượng quy tắc của mình để nó phù hợp với các hạn chế của hàm tạo trong ConfigurableRuleKey?

Trả lời

3

Tôi đã tìm thấy một cách để làm những gì bạn yêu cầu mà không cần sử dụng các loại nguyên liệu, nhưng nó vẫn liên quan đến một cặp diễn viên được kiểm soát:

@SuppressWarnings("unchecked") 
public static <R extends Rule, T extends Rule & Configurable> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return (Key<R>)new ConfigurableRuleKey<>((T)rule); 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 

Tôi không chắc chắn nếu điều này là tốt hơn so với câu trả lời sp00m, nhưng nó là khác nhau, ít nhất. :)

Lý do thực chất tại sao điều này không thể được xây dựng đúng trong các Generics của Java có vẻ là các loại giao lộ cần phải được xây dựng từ các giao diện cụ thể và không thể được xây dựng từ các biến kiểu khác. Do đó, không có cách nào để xây dựng T trong ví dụ này theo cách mà nó bị ràng buộc bởi R. Không có khả năng đó, thậm chí không có cách nào để có một phương pháp ma thuật giống như Class.asSubclass để trừu tượng hành vi này.

EDIT: Có liên quan, có vẻ như Java 8 đã giới thiệu các loại giao lộ ẩn danh nơi bạn có thể truyền tới nhiều giao diện - ví dụ: (Configurable & Rule)rule - nhưng ngay cả điều đó cũng không giúp ích gì ở đây, vì cùng lý do như trên, bạn không thể truyền tới (Configurable & R). Nó sẽ giúp loại bỏ biến loại T, tuy nhiên:

@SuppressWarnings("unchecked") 
public static <R extends Rule> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return (Key<R>)new ConfigurableRuleKey<>((Configurable & Rule)rule); 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 
+0

IDE của tôi cho tôi biết mã này sẽ không biên dịch nhưng thực tế nó có vẻ như vậy. :) Cảm ơn. Tôi nghĩ tôi sẽ báo cáo vấn đề này cho nhóm Hỗ trợ IDE của tôi. – SimY4

+0

@ SimY4: Chỉ cần tò mò thôi, chỉ cần IDE phàn nàn về điều gì? – Dolda2000

+0

Tôi đang sử dụng IntelliJ Idea 14 Xem trước quyền truy cập sớm – SimY4

2

này nên phù hợp với nhu cầu của bạn:

@SuppressWarnings({ "rawtypes", "unchecked" }) 
public static <R extends Rule> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return new ConfigurableRuleKey((Configurable) rule); 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 

Bạn tự kiểm tra rằng ruleConfigurable, vì vậy các diễn viên là an toàn.

+0

Bạn đang sử dụng các loại thô và ngăn chặn tất cả các cảnh báo, tôi nghĩ rằng đó không phải là những gì OP muốn. – WilQu

+0

@WilQu: Tôi nghi ngờ có thể làm những gì OP muốn mà không phá vỡ generics một chút, bởi vì để thực sự khởi tạo một 'ConfigurableRuleKey' trực tiếp, một loại cụ thể là cả' Configurable' và 'Rule' là cần thiết, và Hàm 'create' không có quyền truy cập vào bất kỳ kiểu cụ thể nào như vậy. – Dolda2000

+0

@WilQu Tôi không ngăn chặn tất cả các cảnh báo, chỉ có 'rawtypes' để trình biên dịch không kiểm tra các generics (tôi không chắc chắn nó có thể được thực hiện khác), và' unchecked' vì trình biên dịch không thể biết nếu cast là an toàn (trong khi nó chắc chắn là, kiểm tra bằng tay nhờ 'instanceof'). – sp00m

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