JAVA 泛型分析

1.泛型的概述

什么是泛型?为什么要使用泛型?

泛型,即“参数化类型”。所谓参数化类型就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。说白了就是要给你的代码增加健壮性,尽可能的在编译时就可以检测出BUG来。

泛型就是在定义类时,让类型变成参数。类型参数可以让你重复利用相同的代码,但是可以有不同的输入类型。与普通方法中的参数不同,方法中输入的是变量的值,而泛型输入的参数是类型。而且参数类型可运用在类、接口、方法中。

2.如何定义泛型的作用

  • 使用泛型可以在编译器进行强类型检查时减少错误,毕竟修复编译错误可比修复运行时错误更容易。
  • 使用泛型最常见的就是省去类型转换

举个例子,下面是没用泛型的代码,需要显示的类型转换

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

使用泛型后,就不需要自己类型转换了。

List<String> list = new ArrayList<String>();
list.add("hello world");
String s = list.get();
  • 可以写出泛型的算法

例如java集合框架,在使用泛型后,集合就可以应用在不同的类型上了。

 

3.怎样定义泛型类型

下面举一个例子 

基本book类

为了可以操作任何类型的对象,所用的属性类型是Object

public class Book{ 
    private Object;
    public void set(Object object){
        this.object = object;
        }
    public Object get(){
        return object;
    }
}

由于它的方法接收和返回都是Object对象,你可以想传什么穿什么,传原始类型都可以。但是这样就没有就没有办法在编译阶段检察。

这时有可能set了一个Integer,但是get时以为是一个String,就会出现运行时错误。

泛型版本的Book类

class name<T1,T2,T3......Tn>{}

类型参数的部分跟在后面,用尖括号括起来,这表示类型参数(也叫类型变量)就是T1....T2,类型变量可以在类中的任何地方使用。

下面是用泛型重写的Book类

public class Book<T>{
    //T代表Type的意思
    T object;
    public T getObject(){
        return object;
    }
    public void setObject(T object){
        this.object = object;
    }
}

可以看到,以前的Object出现的地方呗T所替代。类型变量可以使任何的非原始类型,包括任何类,任何接口,任何数组,甚至是任何一个类型变量。

接下来演示一下使用泛型后和上面的区别

public static void main(String[] args){
    BookT<Integer> b = new BookT<Integer>();
    b.setObject(123);
    //变化一,由于实例化时,已经制定了类型的实际参数是Integer,
    //因此这里就只能set一个Integer,不能传入其他类型,
    //编译器会帮助检察错误
    Integer integer = b.getObject();
    //变化二,这里不需要强制转换,因为编译器能判断这里类型就是 Integer
    System.out.println(integer);
}

4.怎样实例化一个泛型

需要将类定义中T替代成一个具体类型,如Integer

Book<integer> integerBook;    就像是传了一个参数一样。

Book<integer>也叫参数化的类型

实例化的代码:

Book<integer>  integerBook = new Book<integer>();

5.钻石操作符 Diamond

JDK7以后,只要编译器可以根据上下文来推断出类型参数,在初始化时,就不必要将类型传给构造函数,使用空的尖括号就可以,这种尖括号也称为“钻石操作符”,如此,上面的实例化代码可以写成下面这样。

Book<Integer> integerBox = new Box<>();

 在new后面的类上,就不用指定T的类型了,但是<>还是保留着,这个非常必要。

在多个类型在同样适用:

Pair<String, Integer> p1 = new OrderedPair<String, Integer>("ing", 8);
Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world");

 同样由于编译器可以推断类型,同样可以使用钻石操作符,上面的实例化可简化为:

Pair<String, Integer> p1 = new OrderedPair<>("ing", 8);
Pair<String, String> p2 = new OrderedPair<>("hello", "world");

 泛型的raw类型

如果在实例化时,丢掉了<>,不向泛型类传递实际的类型会怎么样呢?

如果对于泛型的类,没有提供类型的实际参数,这就是泛型类的raw类型(raw type),使用raw类型,本质上退化成了泛型出现之前的代码,也就是Object的情况。

 

  •  注意,普通的类,即非泛型类不是raw类

raw type 返回的是Object,这里为了向前兼容,将参数化的类型赋值给 raw 类型是合法的。但如果将一个raw类型,赋值给一个参数化的类型,将会收到一个警告。另外 如果使用raw type调用泛型方法,也会得到一个警告。

为什么会受到警告呢?因为编译器会进行强类型检查,当使用了raw type时,编译器没有足够的信息来做类型检查,所以就会报一个unchecked 的警告。所以尽量不要使用raw type。

6.了解泛型中的通配符

在使用泛型时,可以指定泛型是限定区域,例如:

必须是某某类的子类或某某接口的实现类,

<T extends 类或接口1 & 接口2>

 

类型通配符是使用?代替方法具体的类型实参。

  1. <? extends Parent> 指定了泛型类型的上届

  2.  <? super Child> 指定了泛型类型的下届

  3.  <?> 指定了没有限制的泛型类型

注意

在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。

在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加

类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。

 

 

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值