我是仿制药的新手,所以不确定我哪里出错了......
我有一个名为Cat,Dog和Rabbit的类,它们实现了Animal的接口.
以下代码将编译
Set<? extends Animal> animalSet;
Set<Dog> dogSet = new HashSet<Dog>();
animalSet = dogSet;
Run Code Online (Sandbox Code Playgroud)
但是下面的代码不会
Map<String, Set<? extends Animal>> animalMap;
Map<String, Set<Dog>> dogMap = new HashMap<String, Set<Dog>>();
animalMap = dogMap; // this line will not compile
Run Code Online (Sandbox Code Playgroud)
编译器说这些类型是不兼容的.我哪里错了?
UPDATE
谢谢大家的帮助
我通过添加另一个通配符更改了第一行代码以下代码将编译
Map<String, ? extends Set<? extends Animal>> animalMap;
Map<String, Set<Dog>> dogMap = new HashMap<String, Set<Dog>>();
animalMap = dogMap;
Run Code Online (Sandbox Code Playgroud)
另请参阅下面的Cyrille Ka给出的解决方案 - 使用putAll()将值从dogMap传输到animalMap,而不是将dogMap分配给animalMap.
我编写了这个方便的通用函数,用于将集合集合转换为单个集合:
public static <T> Set<T> makeSet(Collection<Collection<T>> a_collection) {
Iterator<Collection<T>> it = a_collection.iterator();
Set<T> result = new HashSet<T>();
while (it.hasNext()) {
result.addAll(it.next());
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后我试着打电话给它:
List<List<String>> resultLists = ... ;
Set<String> labelsSet = CollectionsHelper.makeSet(resultLists);
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
<T>makeSet(java.util.Collection<java.util.Collection<T>>) in CollectionsHelper
cannot be applied to (java.util.List<java.util.List<java.lang.String>>)
Run Code Online (Sandbox Code Playgroud)
现在a List 是a Collection,a String 是a T.那么为什么这不起作用,我该如何解决呢?
大家好,我尝试扩展一个HashMap<String,String>强制执行"全小写"规则
public class HttpQueryMap extends HashMap<String,String>
{
...
@Override
public void putAll(Map<? extends String, ? extends String> m)
{
...
Iterator<Map.Entry<String,String>> iterator = m.entrySet().iterator();
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
我收到编译时错误
incompatible types
required: Iterator<Entry<String,String>>
found: Iterator<Entry<CAP#1,CAP#2>>
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends String from capture of ? extends String
CAP#2 extends String from capture of ? extends String
Run Code Online (Sandbox Code Playgroud)
下一个解决方案可以完成这项工作,但实际上很难看:
public class HttpQueryMap extends HashMap<String,String>
{
...
@Override
public void putAll(Map<? extends String, ? extends String> m)
{
... …Run Code Online (Sandbox Code Playgroud) 以下在JDK8中编译得很好,但是与JDK7 给出了不兼容的类型错误.
List<List<? extends Number>> xs = Arrays.asList(Arrays.asList(0));
Run Code Online (Sandbox Code Playgroud)
根据这个答案,List<List<? extends Number>>没有超类型的关系List<List<Integer>>.
在Java 8中改变了什么使得这个任务有效?我也有一个很难理解为什么它不会在Java 7的工作.
这两个语句使用JDK7编译时没有类型错误:
List<? extends Number> xs = Arrays.asList(0);
List<? extends List<? extends Number>> ys = Arrays.asList(Arrays.asList(0));
Run Code Online (Sandbox Code Playgroud)
对我来说,这两个都在JDK7中工作似乎非常不直观,但上面的原始示例却没有.所有这些当然都适用于JDK8.我想要真正理解这里发生了什么,我需要理解为什么这些例子在Java 7中是合法的,但原始的例子却不是.
此代码导致javac编译错误(但值得注意的是,不是Eclipse 4.2.2!):
public interface Foo<T> {
}
class Bar<T> implements Foo<Iterable<T>> {
}
class Test {
void test(Foo<? extends Iterable<? extends String>> foo) {
Bar<?> bar = (Bar<?>) foo;
}
}
Run Code Online (Sandbox Code Playgroud)
来自javac的错误是这样的:
Foo.java:9: error: inconvertible types
Bar<?> bar = (Bar<?>) foo;
^
required: Bar<?>
found: Foo<CAP#1>
where CAP#1 is a fresh type-variable:
CAP#1 extends Iterable<? extends String> from capture of ? extends Iterable<? extends String>
Run Code Online (Sandbox Code Playgroud)
将转换更改为(Bar) foo(即使用原始类型)允许代码编译,就像更改类型一样foo简单Foo<? extends Iterable<?>>.
编辑:非常有趣,这个简单的改变导致Eclipse拒绝,但javac接受:
void test(Foo<Iterable<String>> foo) { …Run Code Online (Sandbox Code Playgroud) 我正在使用来自第三方库(Reflection)的方法,该方法应该找到给定类型的子类型并且看起来像
public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type) {
...
Run Code Online (Sandbox Code Playgroud)
当调用者代码看起来像
Class<?> type = ...
Set<Class<?>> subTypes = reflections.getSubTypesOf(type);
Run Code Online (Sandbox Code Playgroud)
我收到编译错误:" cannot convert from Set<Class<? extends capture#19-of ?>> to Set<Class<?>>".以下修复了这种情况:
Class<?> type = ...
Set<?> subTypes = reflections.getSubTypesOf(ht);
Run Code Online (Sandbox Code Playgroud)
所以看起来不正确的唯一可能的补救措施Set<Class<? extends ?>>是Set<?>,但不是Set<Class<?>>.为什么会这样?谢谢你对此有任何解释.
Java通过<? extends class>过滤可用于在这种情况下构建新HashMap的Java类的方式为我提供了一种方法,例如:
我可以这样做:
Map<String,? extends Serializable> map1 = new HashMap<String,String>();
Run Code Online (Sandbox Code Playgroud)
没错,因为String实现了Serializable,所以编译器让我做到了。
但是当我尝试这样做时:
Map<String,GenericClass<? extends Serializable>> map2 = new HashMap<String, GenericClass<String>>();
Run Code Online (Sandbox Code Playgroud)
作为GenericClass:
public class GenericClass<T>
{
.
.
.
}
Run Code Online (Sandbox Code Playgroud)
编译器抛出错误说:
Type mismatch: cannot convert from HashMap<String,GenericClass<String>> to Map<String,GenericClass<? extends Serializable>>
Run Code Online (Sandbox Code Playgroud)
我想知道怎么回事?
也许编译器无法检测到extended类是泛型类型的一部分。
我在我的项目中创建了一个工厂类,它允许我(理论上)为任何(支持的)给定类型创建管理器.与管理器交互允许我改变给定类型的某些属性.我面临的问题是当我尝试为泛型类型创建一个管理器时,编译器会破坏我的希望和梦想.
以下代码是我正在使用的精简版本.我尝试创建'test3Manager'的行不会编译,我试图理解为什么会这样.它下面的行显示了一个'解决方法',我试图避免.
import java.util.List;
public class GenTest {
public static void main(String[] args) {
String test1 = "";
IRandomType<String> test2 = null;
IAnotherRandomType<?> test3 = null;
IManager<String> test1Manager = Factory.createManager(test1);
IManager<IRandomType<String>> test2Manager = Factory.createManager(test2);
IManager<IAnotherRandomType<?>> test3Manager = Factory.createManager(test3); // Doesn't compile. Why?
// Work around?
IManager<?> test3ManagerTmp = Factory.createManager(test3);
IManager<IAnotherRandomType<?>> test3Manager2 = (IManager<IAnotherRandomType<?>>) test3ManagerTmp;
}
public interface IRandomType<T> {}
public interface IAnotherRandomType<T> {}
public interface IManager<T> {}
public static class Factory {
public static <T> IManager<T> createManager(T object) {
return …Run Code Online (Sandbox Code Playgroud) 发现了有关使我烦恼的无限制通配符的事实。例如:
public class Test {
private static final Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
public static void main(String[] args) {
getSomeMap();
}
static Map<?, Map<?, ?>> getSomeMap() {
return someMap; //compilation fails
}
}
Run Code Online (Sandbox Code Playgroud)
尽管可以使用Map<?, ?>或Map<?, Map<Integer, String>>返回类型,但失败。
有人可以告诉我确切原因吗?提前致谢。
更新资料
我认为,对于此问题,我似乎理解并最简单的解释(忽略所有这些复杂的规则)是Capture Conversion(link)中的最后一个注释:Capture conversion is not applied recursively.
我想知道这段代码有什么问题:
Map <? extends String, ? extends Integer> m = null;
Set<Map.Entry<? extends String, ? extends Integer>> s = m.entrySet();
Run Code Online (Sandbox Code Playgroud)
编译器抱怨错误消息:
类型不匹配:无法转换
Set<Map.Entry<capture#1-of ? extends String,capture#2-of ? extends Integer>>为Set<Map.Entry<? extends String,? extends Integer>>
应该是什么类型的s?Eclipse建议,Set<?>但我想尝试更具体.
我有一个列表包含未来的任务,未来的类型是未知的,所以我创建一个带通配符类型的列表?,但是当我向列表中添加一个元素时,就会发生编译错误.
这是代码:
private List<Pair<String, Future<?>>> futureTasks = Collections.synchronizedList(
new ArrayList<Pair<String, Future<?>>>(8));
// taskId is a string
futureTasks.add(Pair.makePair(taskId, getExecutors().submit(
new Callable<String>() {
public String call() {
try {
return exportAccountSrcTask(tmpFile); // return a string
} catch (Exception e) {
logger.error("failed to export account src", e);
}
return null;
}}))
);
Run Code Online (Sandbox Code Playgroud)
编译错误:
add(Pair<String,Future<?>>)类型中的方法List<Pair<String,Future<?>>>不适用于参数(Pair<String,Future<String>>)
我有一个问题(简化):
public void method(List<List<?>> list){...}
Run Code Online (Sandbox Code Playgroud)
调用时给出了一个编译错误:
method(new ArrayList<List<String>>()); // This line gives the error
Run Code Online (Sandbox Code Playgroud)
在阅读了类似的线程之后,我明白如果我将方法签名重写为:
public void method(List<? extends List<?>> list){...}
Run Code Online (Sandbox Code Playgroud)
现在,我的问题是,为什么以下工作呢?
public <T> void method(List<List<T>> list){...}
Run Code Online (Sandbox Code Playgroud) generics ×12
java ×12
collections ×2
wildcard ×2
covariance ×1
eclipse ×1
extends ×1
hashmap ×1
java-8 ×1
nested ×1
serializable ×1