2012-05-21 39 views
7

Hy vọng ai đó có thể giúp tôi thoát khỏi sự hỗn loạn này.Các generics Java truyền tham số

tôi đã thực hiện phương pháp này:

public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { 
} 

Dùng paramter T để chắc chắn rằng các lớp học sử dụng như chìa khóa cũng giống như các lớp sử dụng như tham số trong MyInterface.

Bây giờ, tôi muốn chuyển một bản đồ mà các lớp khác nhau làm khóa, tất nhiên và triển khai tương ứng của MyInterface.

Nhưng nó không hoạt động, nhận được lỗi cú pháp do thông số loại. Đây là mã, tôi hy vọng là tự giải thích.

import java.util.HashMap; 
    import java.util.Map; 

    public class Test { 

    public static void main(String[] args) { 
     Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); 

    //  Map<Class<Object>, MyInterface<Object>> map = new HashMap<Class<Object>, MyInterface<Object>>(); 

     map.put(Object.class, new MyObjectImpl()); 

     //if I use Map<Class<Object>, MyInterface<Object>> I get a compiler error here 
     //because map<String> is not map<Object> basically 
     map.put(String.class, new MyStringImpl()); 

     //this would be possible using <?>, which is exactly what I don't want 
    //  map.put(String.class, new MyIntegerImpl()); 

     //<?> generates anyways a compiler error 
     myMethod(map); 
    } 

    //use T to make sure the class used as key is the same as the class of the parameter "object" in doSomething 
    public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { 

    } 

    interface MyInterface<T> { 
     void doSomething(T object); 
    } 

    static class MyObjectImpl implements MyInterface<Object> { 
     @Override 
     public void doSomething(Object object) { 
      System.out.println("MyObjectImpl doSomething"); 
     } 
    } 

    static class MyStringImpl implements MyInterface<String> { 
     @Override 
     public void doSomething(String object) { 
      System.out.println("MyStringImpl doSomething"); 
     } 
    } 

    static class MyIntegerImpl implements MyInterface<Integer> { 
     @Override 
     public void doSomething(Integer object) { 
      System.out.println("MyIntegerImpl doSomething"); 
     } 
    } 
} 
+0

tên lớp kết thúc trong 'Impl' thường triệu chứng của quá kỹ thuật (ví dụ nó ngụ ý chỉ có một thi hành một giao diện cho , không thể được thi hành). – Romain

+1

Hãy quên nó đi, điều này không thể làm việc được. Generics chỉ có thể xác định một bản đồ đồng nhất.Bạn không thể thực thi bất kỳ thứ gì trên cơ sở từng mục nhập, chỉ giống với tất cả các mục nhập bản đồ. –

+0

@Romain tốt, tên thực tế không giống như vậy, chỉ cần viết nó để làm một ví dụ rõ ràng. Nhưng bình luận của bạn cũng có thể áp dụng. Ý bạn là nó ngụ ý chỉ thực hiện 1, tôi có 3 cái gì? – Ixx

Trả lời

8

Bạn không thể làm điều đó, vì không có hạn chế quy định tại Map 's put() phương thức giữa keyvalue. Nếu bạn muốn đảm bảo rằng bản đồ của bạn được phổ biến đúng cách (tức là tạo ra khó khăn như vậy), ẩn bản đồ đằng sau một số API mà sẽ kiểm tra tính chính xác, ví dụ:

public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) { 
    map.put(clazz, intf); 
} 

Sau đó, chỉ cần gọi các registerInterface thay vì bằng tay Populating bản đô.

+0

map.put (clazz, intf) Tôi nghĩ :) – Aif

+0

@Aif, cảm ơn - đã sửa. – npe

0

Tôi không nghĩ rằng đây có thể:

Class<T> chỉ bao giờ chấp nhận T.class như giá trị. Class<Object> sẽ không chấp nhận String.class, mặc dù Object là một siêu lớp của Chuỗi.

Vì lý do này, bất kỳ bản đồ nào có Class<T> là khóa chỉ có thể có một phần tử, với T.class làm giá trị khóa, bất kể giá trị của T.

Trình biên dịch sẽ chỉ chấp nhận bản đồ có giá trị T là tham số xác định. Bạn không thể viết Map<Class<?>, MyInterface<?>> vì mỗi? được giả định là khác nhau: nó không khớp với Map<Class<T>, MyInterface<T>> yêu cầu T có cùng giá trị.

Điều đó nói rằng, myMethod sẽ chỉ chấp nhận các bản đồ một lần, mà không có vẻ hữu ích.

0

Thay đổi phương pháp chữ ký của bạn để

public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) { 

} 

nay khai và gọi bạn nên làm việc ..

Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); 
    map.put(Integer.class, new MyIntegerImpl()); 
    map.put(String.class, new MyStringImpl()); 
    map.put(Object.class, new MyObjectImpl()); 
    myMethod(map); 
+0

Nhưng bản đồ này vẫn cho phép bạn thực hiện 'map.put (Integer.class, MyStringImpl());' là chính xác những gì KHÔNG được hỏi trong câu hỏi. Btw, OP đã gợi ý rằng trong câu hỏi của anh ta. –

3

Theo như tôi biết, bạn không thể khai báo một Bản đồ như mô tả trong Java. Tất cả những gì bạn có thể làm là thực hiện kiểm tra kiểu và/hoặc thêm ràng buộc.

Ổi cung cấp thứ gì đó tiếp cận vấn đề của bạn với ClassToInstanceMap. Vì vậy, một trong những cách để làm điều này sẽ được sử dụng MapConstraints.constrainedMap (như ví dụ dưới đây)

import java.text.ParseException; 
import java.util.HashMap; 
import java.util.Map; 

import com.google.common.collect.MapConstraint; 
import com.google.common.collect.MapConstraints; 

public class Main { 

    interface MyInterface<T> { 
     void doSomething(T object); 

     Class<T> getType(); 
    } 

    static class MyObjectImpl implements MyInterface<Object> { 
     @Override 
     public void doSomething(Object object) { 
      System.out.println("MyObjectImpl doSomething"); 
     } 

     @Override 
     public Class<Object> getType() { 
      return Object.class; 
     } 
    } 

    static class MyStringImpl implements MyInterface<String> { 
     @Override 
     public void doSomething(String object) { 
      System.out.println("MyStringImpl doSomething"); 
     } 

     @Override 
     public Class<String> getType() { 
      return String.class; 
     } 
    } 

    static class MyIntegerImpl implements MyInterface<Integer> { 
     @Override 
     public void doSomething(Integer object) { 
      System.out.println("MyIntegerImpl doSomething"); 
     } 

     @Override 
     public Class<Integer> getType() { 
      return Integer.class; 
     } 
    } 

    public static void main(String[] args) throws ParseException { 

     Map<Class<?>, MyInterface<?>> map = MapConstraints.constrainedMap(new HashMap<Class<?>, Main.MyInterface<?>>(), 
       new MapConstraint<Class<?>, MyInterface<?>>() { 
        @Override 
        public void checkKeyValue(Class<?> key, MyInterface<?> value) { 
         if (value == null) { 
          throw new NullPointerException("value cannot be null"); 
         } 
         if (value.getType() != key) { 
          throw new IllegalArgumentException("Value is not of the correct type"); 
         } 
        } 
       }); 
     map.put(Integer.class, new MyIntegerImpl()); 
     map.put(String.class, new MyStringImpl()); 
     map.put(Object.class, new MyObjectImpl()); 
     map.put(Float.class, new MyIntegerImpl()); //<-- Here you will get an exception 
    } 
} 
+0

+1 bởi vì rất nhiều thông tin nhưng câu trả lời khác là chung chung hơn, theo ý kiến ​​hiện tại của tôi. – Ixx

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