Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何迭代通配符泛型?_Java_Generics_Foreach - Fatal编程技术网

Java 如何迭代通配符泛型?

Java 如何迭代通配符泛型?,java,generics,foreach,Java,Generics,Foreach,如何迭代通配符泛型?基本上,我希望内联以下方法: private <T extends Fact> void iterateFacts(FactManager<T> factManager) { for (T fact : factManager) { factManager.doSomething(fact); } } 我的问题很简单:是否有一种方法可以放置一些可以迭代的通配符类型,或者这是泛型的一个限制(意味着不可能这样做)?您总是可

如何迭代通配符泛型?基本上,我希望内联以下方法:

private <T extends Fact> void iterateFacts(FactManager<T> factManager) {
    for (T fact : factManager) {
        factManager.doSomething(fact);
    }
}

我的问题很简单:是否有一种方法可以放置一些可以迭代的通配符类型,或者这是泛型的一个限制(意味着不可能这样做)?

您总是可以返回到
对象

for (FactManager<?> factManager : factManagers) {
    ...
    for ( Object fact : factManager) {
        factManager.doSomething(fact);
    }
    ...
}

这与您定义的方法更精确地匹配(也就是说,如果您可以使用FactManager中的FactManager调用iterateFacts(),您就知道FactManager包含一些属于Fact子类的项)


只能在上定义(FactManager)的类型参数

  • 类型(即类/接口)
  • 方法,以及
  • 构造器
本地块需要一个类型参数,这是不可能的

是的,我有时也会错过这样的事情

但是,让方法在这里不内联并不是一个真正的问题——如果内联有助于解决性能瓶颈,Hotspot将再次内联它(不关心类型)

此外,拥有一个单独的方法允许为其指定一个描述性名称


只是一个想法,如果您经常需要:

interface DoWithFM {
   void <T> run(FactManager<T> t);
}

...
for (FactManager<?> factManager : factManagers) {
    ...
    new DoWithFM() { public <T> run(FactManager<T> factManager) {
        for (T fact : factManager) {
            factManager.doSomething(fact);
        }
    }.run(factManager);
    ...
}
...
接口DoWithFM{
无效运行(FACTT经理);
}
...
对于(FactManager FactManager:FactManager){
...
新建DoWithFM(){公共运行(FactManager FactManager){
for(事实:factManager){
factManager.doSomething(事实);
}
}.run(factManager);
...
}
...

否。在这种情况下,解决方法是创建一个助手方法

JLS有这个例子

publicstaticvoidreverse(List){rev(List);}
私有静态无效版本(列表){…}
问题是,我们有一个
列表
对象。我们知道它一定是一些
X
列表
,我们希望使用
X
编写代码。内部编译器会将通配符转换为类型变量
X
,但Java语言不会为程序员提供直接访问它的方法。但如果有方法,请接受通过调用
List
,我们可以将对象传递给该方法。编译器推断
T=X
,调用正常


如果没有类型擦除,运行时就可以知道
X
,那么Java肯定会给我们提供一种访问
X
的方法。但是到今天为止,因为
X
在运行时不可用,所以没有太多意义。可以提供一种纯合成的方法,这不可能比辅助方法更简单。

Well、 我可以想到一种使用内部类的方法,因为内部类与其封闭类型共享类型参数。此外,即使使用通配符,由于通配符捕获转换,您仍然可以处理集合

让我创建一个示例。这段代码编译和运行良好。但我不能确定内部类的使用是否会成为您的问题

//as you can see type parameter belongs to the enclosing class
public class FactManager<T> implements Iterable<FactManager<T>.Fact> {

    private Collection<Fact> items = new ArrayList<Fact>();

    public void doSomething(Fact fact) {
        System.out.println(fact.getValue());
    }

    public void addFact(T value) {
        this.items.add(new Fact(value));
    }

    @Override
    public Iterator<Fact> iterator() {
        return items.iterator();
    }


    public class Fact {
        //inner class share its enclosing class type parameter
        private T value;

        public Fact(T value) {
            this.value = value;
        }

        public T getValue() {
            return this.value;
        }

        public void setValue(T value) {
            this.value = value;
        }
    }

    public static void main(String[] args) {
        List<FactManager<String>> factManagers = new ArrayList<FactManager<String>>();

        factManagers.add(new FactManager<String>());
        factManagers.get(0).addFact("Obi-wan");
        factManagers.get(0).addFact("Skywalker");

        for(FactManager<? extends CharSequence> factManager : factManagers){
            //process thanks to wildcard capture conversion
            procesFactManager(factManager);
        }
    }

    //Wildcard capture conversion can be used to process wildcard-based collections
    public static <T> void procesFactManager(FactManager<T> factManager){
        for(FactManager<T>.Fact fact : factManager){
            factManager.doSomething(fact);
        }
    }
}
//正如您所看到的,类型参数属于封闭类
公共类FactManager实现了Iterable{
私有集合项=新建ArrayList();
公共无效剂量(事实){
System.out.println(fact.getValue());
}
公共无效添加事实(T值){
此.items.add(新事实(值));
}
@凌驾
公共迭代器迭代器(){
返回items.iterator();
}
公开课事实{
//内部类共享其封闭类类型参数
私人T值;
公共事实(T值){
这个值=值;
}
公共T getValue(){
返回此.value;
}
公共无效设置值(T值){
这个值=值;
}
}
公共静态void main(字符串[]args){
List factManagers=new ArrayList();
添加(新的FactManager());
factManagers.get(0.addFact(“欧比万”);
factManagers.get(0).addFact(“天行者”);

对于(factManager如果你内联该方法,很可能你确实知道
factManager
的类型。该变量目前是如何声明的?如果你试图内联该方法,你说
是什么意思?它几乎已经内联了。你可以使用反射,但不会出现编译错误,最终会导致运行时间错误。最后但并非最不重要的一点是,您的所有代码都需要try-catch保护为什么
FactManager
外部的东西会将其用作
Iterable
并在它包含的
FactManager
中循环,然后使用非常相同的
FactManager
对其进行处理?封装!FactManager
我会知道它有什么样的
facts
s。@科林:也许还有一些过滤在进行,或者外部因素必须决定调用FactManager的哪些方法?这是一个非常好的创造性解决方案。我确信在某些情况下我会使用它,很遗憾,在给定的情况下我不能。这并不是真的不同在这里使用
FactManager
,并不能真正消除对单独
procesFactManager
方法的需要(据我所知,这确实是问题的关键)。正如Alexander Pogrebnyak的回答所指出的,该方法在
FactManager
中声明为
void doSomething(T Fact)
导致以下错误消息:“FactManager类型中的方法doSomething(capture#4-of?extends Fact)不适用于参数(Fact)。”正如您所假设的,该方法在
FactManager
中声明为
无效doSomething(T Fact)
因此代码需要额外的强制转换:
factManager.doSomething((事实)事实);
这将是最实际的解决方案,但我想知道这是我的错还是泛型的限制。
for (FactManager<? extends Fact> factManager : factManagers) {
    for (Fact fact : factManager) {
          factManager.doSomething(fact);
    }
}
class FactManager<T extends Fact> implements Iterable<T> {
     ...
}
interface DoWithFM {
   void <T> run(FactManager<T> t);
}

...
for (FactManager<?> factManager : factManagers) {
    ...
    new DoWithFM() { public <T> run(FactManager<T> factManager) {
        for (T fact : factManager) {
            factManager.doSomething(fact);
        }
    }.run(factManager);
    ...
}
...
public static void reverse(List<?> list) { rev(list);}
private static <T> void rev(List<T> list) { ... }
//as you can see type parameter belongs to the enclosing class
public class FactManager<T> implements Iterable<FactManager<T>.Fact> {

    private Collection<Fact> items = new ArrayList<Fact>();

    public void doSomething(Fact fact) {
        System.out.println(fact.getValue());
    }

    public void addFact(T value) {
        this.items.add(new Fact(value));
    }

    @Override
    public Iterator<Fact> iterator() {
        return items.iterator();
    }


    public class Fact {
        //inner class share its enclosing class type parameter
        private T value;

        public Fact(T value) {
            this.value = value;
        }

        public T getValue() {
            return this.value;
        }

        public void setValue(T value) {
            this.value = value;
        }
    }

    public static void main(String[] args) {
        List<FactManager<String>> factManagers = new ArrayList<FactManager<String>>();

        factManagers.add(new FactManager<String>());
        factManagers.get(0).addFact("Obi-wan");
        factManagers.get(0).addFact("Skywalker");

        for(FactManager<? extends CharSequence> factManager : factManagers){
            //process thanks to wildcard capture conversion
            procesFactManager(factManager);
        }
    }

    //Wildcard capture conversion can be used to process wildcard-based collections
    public static <T> void procesFactManager(FactManager<T> factManager){
        for(FactManager<T>.Fact fact : factManager){
            factManager.doSomething(fact);
        }
    }
}