泛型Java

泛型


Java泛型是java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

那么为什么需要泛型呢?

ArrayList list = new ArrayList();
list.add("abc");
list.add(123);
System.out.println(list.toString());

猜猜结果是什么? [abc, 123]
忘了提醒了,ArrayList本身就是一个泛型类。

一般我们定义序列,都是指定了类型比如

ArrayList<String> list1 = new ArrayList<String>();

但是当我们需要往里面塞其他类型(boolean、Integer、double等),就会报错了。
为了方便存储,我们不管是什么类型了,直接塞,但是直接取就要小心。

插曲:记得毕业后第一家公司的时候,写好webservice发布之后,就直接难道json数据,然后通过一个泛型接口转换成自己需要的class实体,使用数据。这也许是我理解的最基础的使用了。

泛型的特点?

  • 只在编译阶段有效
//证明一
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
Class c1 = list1.getClass();
Class c2 = list2.getClass();
System.out.printf("list1.getClass().getName() = " + c1.getName());
System.out.printf("list2.getClass().getName() = " + c2.getName());
System.out.printf(String.valueOf(c1 == c2));

猜猜结果是什么?

list1.getClass().getName() = java.util.ArrayList
list2.getClass().getName() = java.util.ArrayList
true

既然为true,就证明了编译之后,程序会采取去泛型化的措施,也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦除(认为list1、list2就只是ArrayList类型)。成功编译过后的class文件中是不包含任何泛型信息的。

//证明二
ArrayList<String> list = new ArrayList<String>();
Class c1 = list.getClass();
try {
    Method e = c1.getMethod("add", Object.class);
    e.invoke(list, 10);
    System.out.println(list.toString());
} catch (Exception e) {
    e.printStackTrace();
}
//结果是 [10]

首先,反射的操作都是在运行时做的。说明泛型信息不会进入到运行时阶段。
===并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。

泛型类和泛型类使用(同理泛型接口)

public static void main(String args[]) {
    test5();
}
private static void test5(){
    FanXing1<Integer> intObject = new FanXing1<Integer>(123);
    FanXing1<String> strObject = new FanXing1<String>("abc");
    System.out.println("intObject.getType() = " + intObject.getType()
            + ", intObject.getValue() = " + intObject.getValue());
    System.out.println("strObject.getType() = " + strObject.getType()
            + ", strObject.getValue() = " + strObject.getValue());
}

public static class FanXing1<T> {
    private T ob; // 定义泛型成员变量

    public FanXing1(T ob) {
        this.ob = ob;
    }

    public T getValue() {
        return ob;
    }

    public String getType() {
        return ob.getClass().getName();
    }
}
//结果
intObject.getType() = java.lang.Integer, intObject.getValue() = 123
strObject.getType() = java.lang.String, strObject.getValue() = abc

无规矩不成方圆,泛型注意事项

  • 1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
  • 2、不能对确切的泛型类型使用instanceof操作,编译时会出错。
  • 3、泛型的类型参数可以有多个。
  • 4、不能创建一个确切的泛型类型的数组。(如下)
  • 5、泛型的参数类型还可以是通配符类型。(如下)
List<Integer>[] lsa = new List<Integer>[10]; //编译报错generic array creation
List<?>[] lsa = new List<?>[10]; //编译不报错

泛型的通配符和上下边界

List<Double> doub = new ArrayList<Double>();
List<Number> number = doub; //报错
//Double虽然是Number的子类,但List不是List的子类型

于是乎,我们需要一个在逻辑上可以用来同时表示为List和List父类的一个引用类型,类型通配符应运而生。

List<Double> doub = new ArrayList<Double>();
List<?> number = doub; //编译通过

这个就是通配符。

import java.util.ArrayList;
import java.util.List;

public class test2 {
    public static void main(String[] args){
        List<Double> data1 = new ArrayList<Double>();
        data1.add(11.11d);
        List<Integer> data2 = new ArrayList<Integer>();
        data2.add(11);
        getData(data1); //这句编译不过,见下图
        getData(data2);
    }

    public static void getData(List<? extends Integer> data) {
        System.out.println(data.toString());
    }
}

这里写图片描述
这个就是上下边界。

使用泛型的好处?

  • 1.类型安全。
    泛型的主要目标是提高Java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于创建者的脑子里(幸运的话,还存在于代码注释中)。
  • 2.消除强制类型转换。
    泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
  • 3.性能收益。
    不需要怀疑,性能一定有提升,只是达不到质变的程度。由于泛型的实现方式,支持泛型(几乎)不需要JVM或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。
import java.util.ArrayList;

public class test1 {
    public static void main(String[] args){
        ArrayList list = new ArrayList();
        list.add("abc");
        System.out.println(list.get(0));
    }
}
//泛型代码编译出来class文件大小是 687字节。
import java.util.ArrayList;

public class test2 {
    public static void main(String[] args){
        ArrayList<String> list = new ArrayList<String>();
        list.add("abc");
        System.out.println(list.get(0));
    }
}
//非泛型代码编译出来class文件大小是 799字节。

太TM明显了,不说了这个了。

  • 4.提高代码重用率。
    就像插曲中说的,一个泛型转换实体类接口,就搞定几乎所有的json转换工作,减少代码量,简洁清晰。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值