【问题标题】:Java Type Erasure ProblemJava 类型擦除问题
【发布时间】:2009-07-10 00:33:53
【问题描述】:

我做了一个例子来说明我的问题:

Metrical.java

public interface Metrical<T>
{
    double distance(T other);
}

Widget.java

public class Widget implements Metrical<Widget>
{
    private final double value;

    public Widget(double value) { this.value = value; }

    public double getValue() { return value; }

    public double distance(Widget other) { return Math.abs(getValue() - other.getValue()); }
}

Pair.java

public class Pair<T>
{
    private final double value;
    private final T object1, object2;

    public Pair(T object1, T object2, double value)
    {
        this.object1 = object1;
        this.object2 = object2;
        this.value = value;
    }

    public T getObject1() { return object1; }

    public T getObject2() { return object2; }

    public double getValue() { return value; }
}

算法.java

import java.util.Set;

public class Algorithm<T extends Metrical<T>>
{
    public void compute(Set<T> objects)
    {

    }

    public void compute(Set<Pair<T>> pairs)
    {

    }
}

因此,在 Algorithm.java 中,Set> 被视为一个 Set,因此我我有类型擦除问题。但是,有什么办法可以让我摆脱这样的事情而不用不同的方法命名?该算法的两种变体都旨在对 T 进行操作,但我需要允许不同的参数。它们计算相同的东西,所以为了避免混淆,我宁愿不给它们起不同的名字。有没有办法解决这个问题?

【问题讨论】:

  • 从技术上讲,这不是擦除问题。重载是在编译时完成的。添加额外的运行时类型信息也无济于事。

标签: java generics types type-erasure


【解决方案1】:

没有。

你必须记住,有人可以只用一个普通的 Set 来调用你的方法,在这种情况下会调用哪一个?

这就是你做不到的原因。就像你不能做的那样:

interface A {
  void blah(Set set);
  void blah(Set<T> set);
}

同样的问题。

类型信息在运行时不可用(即类型擦除)。

【讨论】:

    【解决方案2】:

    抱歉,坏消息是您不能这样做:

    public class Algorithm<T extends Metrical<T>> {
        public void compute(Set<T> objects) {
        }
    
        public void compute(Set<Pair<T>> pairs) {
        }
    }
    

    由于擦除,两者都将擦除到相同的签名。没有办法绕过重命名其中一个方法。

    【讨论】:

    • 重命名其中一种方法可能不是一个坏主意——因为它们都会做(稍微)不同的事情(我猜)。
    【解决方案3】:

    遗憾的是,这是 Java 泛型失败的主要领域......没有好的解决方案。

    我通常会创建一个新类,接口为Set&lt;Pair&lt;T&gt;&gt;,但它包装了Set&lt;Pair&lt;T&gt;&gt;(不扩展它,这会导致同样的问题)。

    【讨论】:

      【解决方案4】:

      我写了一篇关于类型擦除的文章,您可能会感兴趣。 它提供了常见的广为人知的解决方案,也是规避问题的棘手方法。 我不知道它是否与你有关。无论如何,它包含一些在某些情况下可能有用的技术。

      另请参阅:Using TypeTokens to retrieve generic parameters

      希望对你有帮助。

      【讨论】:

        【解决方案5】:

        使用public class Widget&lt;K, P&gt; implements Metrical&lt;K extends Widget&lt;P&gt;&gt;

        public double distance(Widget other) {} 变为 public double distance(Widget&lt;P&gt; other) {}

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-06-12
          • 2012-01-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多