繁体   English   中英

在方法和类中使用泛型和接口有什么区别

[英]What is the difference between using generics and interfaces in methods and classes

我想知道在泛型类或方法中使用接口(或超类型)与使用边界的通用方法(T扩展接口)之间有什么区别。

假设我有两个实现和接口的类(天真的例子):

public interface MeasurableDistance {
    public Point getPosition();
}

public class Person implements MeasurableDistance {
    private Point position;

    public Point getPosition() {
        return position;
    }
}

public class House implements MeasurableDistance {
    private Point position;

    public Point getPosition() {
        return position;
    }
}

1)以下列方式编写方法之间的区别是什么:

public int computeDistance(MeasurableDistance a, MeasurableDistance b) {
    Point a = a.getPosition();
    Point b = b.getPosition();
    //compute distance
    return distance,
}

和类似的东西

public <T extends MeasurableDistance, S extends MeasurableDistance> int computeDistance(T a, S b) {
    Point a = a.getPosition();
    Point b = b.getPosition();
    //compute distance
    return distance,
}

2)如果我想要一个类来保存MeasurableDistance对象:

public class Holder {
    private MeasurableDistance holder;

    public Holder() {};
    public add(MeasurableDistance a) {
        holder = a;
    }
}

或类似的东西

public class Holder<T extends MeasurableDistance> {
    private T holder;

    public Holder<T>() {};
    public add(T a) {
        holder = a;
    };
}

对于1,我认为它们应该完全相同,对吧? 显然称为非通用版本

Person a = new Person();
Person b = new Person();
House c = new House();
House d = new House();
computeDistance(a,c);
computeDistance(a,b);
computeDistance(c,d);

总是有效,因为computeDistance()会因为多态而将这些对象视为MeasurableDistance。 通用版本应该工作得太对了? 编译器将推断MeasurableDistance类型并相应地添加强制转换。 即使我想这样称呼它:

<Person, House>computeDistance(a,c);

它会产生相同的效果,方法看起来像

    Point a = (MeasurableDistance) a.getPosition();
    Point b = (MeasurableDistance) b.getPosition();

如果我没错的话。 或者,现在我考虑一下,它应该是这样的:

    Point a = (Person) a.getPosition();
    Point b = (House) b.getPosition();

它会起作用,因为Person和House都在实施这种方法。

那么泛型方法的优点是什么? 我已经读过它的类型安全,因为强制转换总是正确的,但是使用非泛型方法你根本就没有强制转换。

你似乎混淆了使用泛型的原因,以及使用有界泛型的原因。

使用有界泛型的原因意味着已经有理由使用泛型。

让我回顾一下。


使用泛型的原因在Java教程中进行了解释,其中一个最明显的原因是:

以下没有泛型的代码片段需要强制转换:

 List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0); 

重写以使用泛型时,代码不需要转换:

 List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no cast 

使用有界泛型的原因与使用泛型的原因是分开的。 如果你有理由使用泛型 ,使用边界让你需要一定类型的类型的功能:

public class MyClass<T> {
    private List<T> list;
    ...
    public void disposeAll() {
        for(T e : list)
            e.dispose(); // compile time error
    }
}

上面的错误可以通过添加一个绑定来解决:

public class MyClass<T extends Disposable> {...}

你所展示的案例实际上没有理由使用有界泛型,就像你已经指出的那样。 但这是因为他们没有(好的)理由首先使用泛型。

在第2种情况下,泛型允许您限制Holder可以持有的对象类型:

Holder<House> holder = new Holder<>();
holder.add(new Person()); // compile time error
holder.add(new House());

哪个不是很有用。 没有真正的理由在那里使用泛型。

但是,如果您还要检索该值,则泛型将非常有用:

Holder<House> holder = new Holder<>();
// holder.add(new Person());
holder.add(new House());
House h = holder.get(); // no cast

首先,当你定义一个类似的方法时

public <T extends MeasurableDistance, S extends MeasurableDistance>
    int computeDistance(T a, S b) {

    Point a = a.getPosition();
    Point b = b.getPosition();
    //compute distance
    return distance,
}

根本没有类型转换 此方法与方法签名完全相同

public int computeDistance(MeasurableDistance a, MeasurableDistance b)

这就是泛型类型参数在这里没有意义的原因; 他们不会改变任何事情。


根据经验,当您要声明两个或多个参数之间或参数(s)和返回类型之间的关系时,方法上的类型参数很有用。

public <T extends MeasurableDistance> T validate(T a, Rectangle area) {
    Point p = a.getPosition();
    if(!area.contains(p))
        throw new IllegalArgumentException();
    return a,
}

这里,我们在参数和返回类型之间有一个关系,允许使用它,如:

Person person;
Rectangle localArea;

public void setPerson(Person newPerson) {
    this.person = validate(newPerson, localArea);
}

因为通用签名指定当我们用Person替换T ,我们必须传入一个Person实例并保证返回一个Person实例。


同样,如果我们可以表达类的两个或更多成员之间的关系,那么类的通用签名是有用的。 例如, List表示这样的关系,因为我们addset的对象的类型与我们可以通过get检索的类型相同。

因此,当您添加一个方法来检索封装对象时,您的Holder类将是类型参数的合适用例,因为存储和检索方法之间存在关系。 因此,这两个方法之间也存在关系,并且保存该引用的成员变量的类型是正确实现逻辑所必需的。

暂无
暂无

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

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