【问题标题】:Types by argument?按参数类型?
【发布时间】:2010-07-15 15:37:05
【问题描述】:

我想知道在 Java 中是否可以通过参数传递类型。

让我解释得更好:

假设下一个代码

class Bee {
    // Class implementation
}

class Worker extends Bee {
    // Class implementation
}


class Queen extends Bee {
    // Class implementation
}

现在用我的蜜蜂对象创建一个容器

Vector<Bee> x=new Vector<Bee>();
// ...
for(i=0;i<10;i++)
    x.add(new Worker());
// ...
for(i=0;i<10;i++)
    x.add(new Queen());

现在我想创建一个通用方法来迭代向量并返回具有特定类型蜜蜂、工蜂或蜂王的集合。如何做到这一点?

编辑

我试过了

search(x,Worker.class);

static public <T extends Bee> Set<T> search(List<Bee> bees, Class<T> clazz){
    // ...
}

我收到错误报告“方法搜索(列表,类)不适用于参数(集,类)”。问题出在第二个参数上,因为类型不兼容。

【问题讨论】:

    标签: java types arguments


    【解决方案1】:

    从您的编辑中我看到,您仍在为实施而苦苦挣扎。这是一个工作示例:

    public static void main(String[] args) {
        Collection<Bee> bees = new ArrayList<Bee>();
        bees.add(new Hive.Worker());
        bees.add(new Hive.Queen());
        Set<Queen> queens = getBeesOfOneType(bees, Queen.class);
    }
    
    private static <T extends Bee> Set<T> getBeesOfOneType(Collection<Bee> bees, Class<T> beeType) {
        Set<T> result = new HashSet<T>();
        for (Bee bee : bees) {
            if (beeType.isInstance(bee)) {
                // The following cast is safe. The previous if makes sure that
                // that bee can be cast to T at this place
                T beeTypeInstance = beeType.cast(bee);
                result.add(beeTypeInstance);
            }
        }
        return result;
    }
    

    仍然有一个类型安全警告,我很确定这个警告无法消除。编译器现在没有,我们只选择 T 型蜜蜂,所以它必须警告我们。

    【讨论】:

    • 干得好。这正是我想要的。谢谢。
    • 您应该禁止该警告,因为您可以证明它是安全的。将该强制转换移动到局部变量声明的右侧将使您最小化@SuppressWarnings 的范围。
    • @ILMTitan - 感谢您的评论,以前从未使用过这样的注释,也不会是最后一次!今天学到了新东西:)
    • 为什么不使用beeType.cast(bee) 并完全避免未经检查的演员表?在我看到之前无法投票。
    • @Andreas:它如何做并不重要,重要的是它说它做了什么。你永远不会得到 ClassCastException 因为你已经执行了beeType.isInstance...我不是说不要先使用 isInstance !您可能更喜欢注释和注释您自己的源代码,但不幸的是,您错了。使用库函数,尤其是在创建它们时EXACT 的目的是避免您在此处执行的操作。
    【解决方案2】:

    您可以使用instanceof 表达式来测试BeeWorker 还是Queen。您可以使用它来根据子类型过滤您的Vector&lt;Bee&gt;(或者更好的是List&lt;Bee&gt;)。

    Guava 还提供了Iterables.filter(Iterable&lt;?&gt; unfiltered, Class&lt;T&gt; type) 供你使用。

    【讨论】:

    • 为什么这被否决了?我现在写论文太累了,但我的答案肯定没有用吗?
    • 你从我这里得到了补偿。你的回答有用的。
    • @Andreas:我也支持一下,因为你的确实有一个例子。也许我累的时候不应该stackoverflow。
    • @Andreas:我想我明白为什么我们的答案被否决了:它们本身并不是真正的通用方法。使用instanceof,您必须对类型进行硬编码。不过,我仍然坚持我的番石榴推荐。如此之多,以至于我将尝试提供一个示例 sn-p。也许明天。
    • +1 表示 Guava 建议;我不认为 instanceof 符合您所说的通用要求。
    【解决方案3】:

    使用Class 作为方法的参数

    public <T extends Bee> Set<T> filterBeesByType(List<Bee> bees, Class<T> clazz)
    

    顺便说一句,通过接口(@98​​7654323@、List 等)而不是实现(Vector)来引用集合类型是一种很好的做法。

    【讨论】:

    • 将 List 过滤到 List 中而不是 Set 中会更合适。此外,public 应该在泛型声明之前。否则,这是一个正确的答案。
    • @So Many Questions: filterBeesByType(listOfBees, Worker.class)
    • @unbeli,谢谢,错过了public 错误。至于SetList的正确性问题,我认为这完全取决于意图,如果这段代码的目标是简单地将List过滤到与clazz匹配的类型或还删除重复项。最初的问题提到返回一个集合。两者都是有效的情况。
    • 过滤逻辑是if (clazz.isInstance(bee)) ...,假设您也希望子类型匹配。
    【解决方案4】:

    使用instanceof 运算符:

    public static Set<Queen> queensOnly(Collection<Bee> bees) {
      Set<Queen> queens = new HashSet<Queen>();
      for (Bee bee:bees) {
        if (bee instanceof Queen) {
          queens.add((Queen) bee);
        }
      }
      return queens;
    }
    

    【讨论】:

    • 投反对票?对于满足要求的解决方案?来吧,downvoter,告诉我怎么了!
    • OP 想要将类型作为参数传递(请参阅问题标题以及问题的第一行),因此这不满足要求。对不起,另一个答案是正确的,你的不是。
    • @unbeli - 啊,所以当这是一个 stict 要求时,它无法满足,因为,不,我们不能将类型作为参数传递:Class 对象不是一种”。类型只不过是一个概念。并且概念不能传递给方法,只能传递原语和对象引用。但无论如何,“另一个”答案更接近于 OP 的想法。
    • 当你说'传递一个整数'时,每个人都明白,你传递一个对象,代表一个整数,而不是整数的概念。当你说“传递一个类型”时,它的意思是传递一个对象,代表一个类型,这将是 Java 中的一个类。不要对个人投反对票;)
    猜你喜欢
    • 2023-04-08
    • 2021-06-27
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 2015-02-25
    相关资源
    最近更新 更多