通用构造函数在Java中的作用是什么?

时间:2017-12-14 05:33:27

标签: java generics constructor

众所周知,通过使用类型参数,您可以在Java中使用泛型类:

class Foo<T> {
    T tee;
    Foo(T tee) {
        this.tee = tee;
    }
}

但是你也可以使用泛型构造函数,这意味着显式接收它们自己的泛型类型参数的构造函数,例如:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

我正在努力理解用例。这个功能让我做了什么?

5 个答案:

答案 0 :(得分:23)

我正在考虑的用例可能是某些人想要一个继承自2种类型的Object。例如。实现2 interfaces

public class Foo {

    public <T extends Bar & Baz> Foo(T barAndBaz){
        barAndBaz.barMethod();
        barAndBaz.bazMethod();
    }
}

虽然我从未在生产中使用它。

答案 1 :(得分:19)

在您提供的示例中,U在课程中没有任何作用,这很明显。构造函数,因为它在运行时实际上变为Object

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

但是,让我们说我希望我的构造函数只接受扩展其他类或接口的类型,如下所示:

class Foo<T extends Baz> {
    <U extends Bar> Foo(U u) {
        // I must be a Bar!
    }
}

请注意,该类已经使用了不同的泛型类型;这允许您在类定义中使用单独的,不相关的泛型类型。

当然,我从来没有使用过这样的东西,而且我从来没有看到它在使用过,但它是可能的!

答案 2 :(得分:15)

  

这个功能让我做了什么?

至少有它可以让你做的两件事,你不能这样做:

  1. 表达参数类型之间的关系,例如:

    class Bar {
        <T> Bar(T object, Class<T> type) {
            // 'type' must represent a class to which 'object' is assignable,
            // albeit not necessarily 'object''s exact class.
            // ...
        }
    }
    
  2. &LT;抽出&GT;

  3. 正如@Lino首先观察到的那样,它允许你表达参数必须与两个或更多不相关类型的组合兼容(当所有但最多只有一个是接口类型时才有意义)。请参阅Lino的答案。

答案 3 :(得分:10)

实际上,这个构造函数

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

就像generic method一样。如果你有这样的多个构造函数参数会更有意义:

class Bar {
    <U> Bar(U you, List<U> me) {
        // Why!?
    }
} 

然后你可以强制执行约束,它们与编译器有相同的时间。不使U成为全班的通用。

答案 4 :(得分:8)

因为未绑定的泛型类型会删除到Object,所以它与在构造函数中传递Object相同:

public class Foo {
    Object o;

    public Foo(Object o) {
        this.o = o;
    }
}

...但就像传递空白Object一样,除非您正在做一些聪明的,否则这几乎没有实际价值。

如果您传入绑定泛型,您会看到好处和胜利,这意味着您实际上可以保证您关注的类型。

public class Foo<T extends Collection<?>> {
    T collection;
    public Foo(T collection) {
        this.collection = collection;
    }
}

实际上,这更多地是关于灵活性,而不是革命性的东西。如果您希望灵活地传递特定类别的类型,那么您可以在此处执行此操作。如果您,那么标准课程没有任何问题。它仅仅是为了您的方便,因为类型擦除仍然是一个东西,未绑定的泛型与传递Object是相同的(并具有相同的实用程序)。