通用通配符调用不会编译

时间:2016-02-29 15:00:42

标签: java generics

我目前正在与Generics合作,而我没有经验丰富。我遇到了这个问题:

我让这个课比较了实现Comparable的2个值并做了其他一些事情,让我们说增加compareTo()值:

public final class Type<T extends Comparable<T>> {
    public int compare(T val1, T val2) {
        int compTemp = val1.compareTo(val2);
        compTemp++;
        // do stuff
        return compTemp;
    }
}

现在我创建了Type的一些实例:

Type<Integer> t1 = new Type<Integer>();
Type<String> t2 = new Type<String>();

现在我想将它们放入Map.因为我无法预测Type的泛型类型我使用了wilcard ?

Map<String, Type<?>> map = Maps.newHashMap();

map.put("t1", t1);
map.put("t2", t2);

如果我想调用Type.compare() t1,而不是map.get(t1)

t1.compare(1,1); // compiles fine
map.get("t1").compare(1, 1); // does not compile

后者抛出编译错误:

  

该类型的方法比较(捕获#3-of?,捕获#3-of?)   Type不适用于参数(int,int)

我知道这是因为我的通配符参数,但我并不完全知道为什么以及如何解决这个问题。 唯一的#34;修复&#34;我看到是使用原始类型的Map,但是这会显示几个警告。 我想现在我对wilcard参数有很大的误解。

我感谢每一个答案!

2 个答案:

答案 0 :(得分:2)

您在地图中使用wildcard <?>表示您的地图不知道确切的类型。对于Map,它们都存储为Type<Object>。 你可以做的一件事是某种类型的不安全的铸造

((Type<Integer>)map.get("t1")).compare(1, 1); // does compile but is type unsafe

另一种解决方案是在构造函数中创建Type对象时存储泛型类。然后,您可以使用另一种方法泛型类型在compare方法中进行某种类型的安全转换。请参阅此Type

public final class Type<T extends Comparable<T>> {
    Class<T> type;
    Type(Class<T> _type){
        type = _type;
    }

    public <E extends Comparable<E>> int compare(E val1, E val2) {
        T v1 = type.cast(val1);
        T v2 = type.cast(val2);

        int compTemp = v1.compareTo(v2);
        compTemp++;
        // do stuff
        return compTemp;
    }
}

现在你可以这样做:

    Type<Integer> t1 = new Type<Integer>(Integer.class);
    Type<String> t2 = new Type<String>(String.class);

    Map<String, Type<?>> map = new HashMap<>();

    map.put("t1", t1);
    map.put("t2", t2);

    map.get("t1").compare(1, 1); // compiles fine
    map.get("t2").compare("one", "one"); // compiles fine

答案 1 :(得分:2)

我假设你想在运行时做这样的事情:

String key = getKeyFromParams(p1, p2);
map.get( key ).compare(p1, p2);

由于编译器不知道它为密钥返回的值的泛型类型,因此您不能以这种方式调用compare()。

但是,您可以稍微重构一下代码以使其正常工作(仍有警告并且需要注意不要破坏任何内容):

  1. 让您的compare()方法接受Comparable参数
  2. 将泛型类传递给构造函数并使用它来检查compare()中的参数
    • 如果参数类型正常则比较
    • 如果他们不匹配类型类则抛出异常
  3. 使用类型类作为映射键并将其用于查找
  4. 示例:

    public final class Type<T extends Comparable<T>> {
      private final Class<T> typeClass;
    
      public Type( Class<T> typeClass) { 
        this.typeClass = typeClass;
      }
    
      public int compare(Comparable val1, Comparable val2) {
        if( !(typeClass.isInstance( val1 ) && typeClass.isInstance( val2 ) ) ) {
          throw new IllegalArgumentException("message");
        } 
    
        int compTemp = val1.compareTo(val2);
        compTemp++;
        // do stuff
        return compTemp;
      }
    
      //getter for the typeClass
    }
    

    地图的包装:

    class TypeComparator { 
      Map<Class<?>, Type<?>> map = new HashMap<Class<?>, Test.Type<?>>();
    
      public void addType(Type<?> type) {
        map.put( type.getTypeClass(), type );
      }
    
      public <T extends Comparable<T>> void compare(T p1, T p2) {
        map.get( p1.getClass() ).compare( p1, p2 );
      }
    }
    

    最后这样称呼它:

    //add some types
    TypeComparator comp = new TypeComparator();
    comp.addType( new Type<Integer>( Integer.class ));
    comp.addType( new Type<String>( String.class ));
    
    //compare ints    
    comp.compare( 1, 1 );
    
    //compare Strings
    comp.compare( "1", "1" );
    
    //won't compile
    comp.compare( "1", 1 );
    

    最后的一些想法:

    • 您必须处理地图中没有类型的情况(例如,如果在示例中传递了Double个参数)
    • 您仍然会收到警告,但如果您在实施中隐藏它们并注意不要对错误的类型进行投射,那么您应该没问题。