Java 泛型介绍和使用方法

发布于 2021-03-12 12:58:59 字数 3558 浏览 1176 评论 0

在没有泛型前,从集合中读取的元素都必须进行强制转换,比如:

List foos = new ArrayList();
foos.add(new Foo());
Foo = (Foo)foos.get(0);  //必须强制转换

否则连编译没法通过,但是有了泛型之后,编译器可以在插入数据的时候自动帮你转换,编译时告知是否插入了错误类型。

List<Foo> foos = new ArrayList<Foo>();
foos.add(new Foo());
Foo = foos.get(0);  //无需转换

使用泛型的需要注意的陷进

首先需要知道几个术语:

  • 泛型:声明的时候,拥有一个或多个类型参数的类或者接口,称之为泛型类或泛型接口,两者又统称为泛型(generic type) 如:List就声明了一个String类型的参数
  • 参数化类型(parameterized type):参数化类型包含一个类或者接口名称C,以及实际的类型参数列表<t1,...tn></t1,...tn>
  • 原生类型(raw type):原生类型是满足以下条件之一:
    1. 使用的泛型类型声明的名称,而没有任何伴随的实际类型的参数
    2. 元素的类型为原生类型的数组类型
    3. 原生类型R的任何非静态类型成员,且它不是从R的超类或者超接口派生而来的

举例:

public class MyType<E> {
    class Inner { }
    static class Nested { }

    public static void main(String[] args) {
        MyType mt;          // warning: MyType is a raw type
        MyType.Inner inn;   // warning: MyType.Inner is a raw type

        MyType.Nested nest; // no warning: not parameterized type
        MyType<Object> mt1; // no warning: type parameter given
        MyType<?> mt2;      // no warning: type parameter given (wildcard OK!)
    }
}

这里,mtinn就是原生类型的,而ntst不是,因为他是静态类型成员,mt1mt2属于参数化类型。

陷进一: 不要使用原生态类型

本质上,原生类型的行为方法和泛型没什么两样,就像如下代码:

List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!

代码没有任何问题,但是,

for (Object o : names) {
    String name = (String) o;
    System.out.println(name);
} // throws ClassCastException!
  //    java.lang.Boolean cannot be cast to java.lang.String

如上代码在运行的时候,就会抛出ClassCastException的异常。

有了泛型,编译器就能帮你完成类型检测的工作.

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

原生类型 List 与 List 参数化类型的区别

原生类型List躲避了泛型检查,参数化类型 List 告知编译器,它能装任意类型的对象,虽然你可以将List传递给类型List的参数,但是不能将它传递给类型List 的参数。为什么呢?这是子类型化(subtyping)的规则。

子类型化(subtyping)

常规类中,如果类B继承A,那么类B就是类A的子类,但是这条规则并不能适用于泛型中。

class A {}
class B extends A {}

List<B> lb = new ArrayList<>();
List<A> la = lb;  //compile-time error

[generics-listParent.gif] 尽管Integer是Number的子类,但是List并不是List的子类,两者没有任何关系,而他两的共同父类是List<?>.

为了通过List的元素来访问Number的方法,可以使用向上通配符:

List<? extends Integer> intList = new ArrayList<>();
List<? extends Number> numList = intList  //Ok,List<? extends Integer> is a subtype of List<? extends Number>

相关资源

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

文章
评论
84963 人气
更多

推荐作者

卷耳

文章 0 评论 0

佚名

文章 0 评论 0

℉服软

文章 0 评论 0

qq_2gSKZM

文章 0 评论 0

凉宸

文章 0 评论 0

gyhjy

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文