简体   繁体   English

Java类型擦除问题

[英]Java Type Erasure Problem

I've made an example to demonstrate my problem: 我举了一个例子来证明我的问题:

Metrical.java Metrical.java

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

Widget.java 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 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; }
}

Algorithm.java Algorithm.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)
    {

    }
}

So, in Algorithm.java , Set< Pair< T >> is being seen as a Set< T > and thus I am having type erasure problems. 因此,在Algorithm.java中Set <Pair <T >>被视为Set <T> ,因此我遇到类型擦除问题。 However, is there any way I can get away with something like this without naming the methods differently? 但是,有没有什么办法可以在不命名方法的情况下摆脱这样的事情? Both variants of the algorithm are meant to operate on T 's, but I need to allow for different arguments. 算法的两种变体都是为了对T进行操作,但我需要允许不同的参数。 They compute the same thing, so in an effort to avoid confusion, I would rather not name them differently. 他们计算同样的事情,所以为了避免混淆,我宁愿不以不同的名字命名。 Is there any way to accommodate this? 有没有办法容纳这个?

No there isn't. 不,没有。

You have to remember that someone could call your method with just a vanilla Set, in which case which one would be called? 你必须记住,有人可以用一个香草集调用你的方法,在这种情况下会调用哪一个?

That's why you can't do it. 这就是为什么你不能这样做的原因。 Just like you can't do: 就像你做不到:

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

Same problem. 同样的问题。

The type information isn't available at runtime (ie type erasure). 类型信息在运行时不可用(即类型擦除)。

Sorry, the bad news is that you cannot do this: 对不起,坏消息是你不能这样做:

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

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

Due to erasure, both will erase to the same signature. 由于擦除,两者都将擦除相同的签名。 There is no way around this short of renaming one of the methods. 没有办法解决其中一种方法的重命名问题。

Sadly, this is the major area where Java Generics falls down... there is just no good solution. 遗憾的是,这是Java Generics倒闭的主要领域......没有好的解决方案。

I've generally resorted to making a new class, with the interface as Set<Pair<T>> , but that wraps Set<Pair<T>> (without extending it, which would cause the same problem). 我通常使用接口作为Set<Pair<T>>创建一个新类,但是包装Set<Pair<T>> (不扩展它,这会导致同样的问题)。

I've written an article about type erasure which can be of your interest. 我写了一篇关于类型擦除的文章,这可能是你感兴趣的。 It gives the common widely known solution and also a tricky way to circumvent the problem. 它提供了常见的广为人知的解决方案,也是解决问题的棘手方法。 I don't know if it will be relevant for you. 我不知道它是否适合你。 Anyway, it contains some techniques which may be useful under certain circumstances. 无论如何,它包含一些在某些情况下可能有用的技术。

See also: Using TypeTokens to retrieve generic parameters 另请参阅: 使用TypeTokens检索通用参数

I hope it helps. 我希望它有所帮助。

Use public class Widget<K, P> implements Metrical<K extends Widget<P>> . 使用public class Widget<K, P> implements Metrical<K extends Widget<P>>

public double distance(Widget other) {} becomes public double distance(Widget<P> other) {} public double distance(Widget other) {}成为public double distance(Widget<P> other) {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM