java 泛型

java 泛型

1.泛型简介

使用泛型,可以限制集合能接收的对象类型,并且消除了类型转换的需要

List<T> list=new ArrayList<T>(); //使用泛型
T t=list.get(0);

List  list=new ArrayList(); //不使用泛型
T t=(T)list.get(0); 

相关术语:(以ArrayList<E>、ArrayList<Integer>为例)

  • ArrayList<E>定义了一个泛型类型,“E”称为 “类型变量”或“类型参数”。
  • ArrayList<Integer>称为“参数化的类型”,“Integer”称为“实际类型参数”。
  • ArrayList称为泛型类型ArrayList<E>的“原始类型(raw type)”。

泛型中标记含义:

  • E - Element (在集合中使用,因为集合中存放的是元素)
  • T - Type(Java 类)
  • K - Key(键)
  • V - Value(值)
  • N - Number(数值类型)
  • ? - 表示不确定的java类型
  • S、U、V - 2nd、3rd、4th types

通配符对应类名,类对应变量名。可以这样做个对比

一般使用<T>来声明类型持有者名称,自定义泛型类时,类持有者名称可以使用T(Type)如果是容器的元素可以使用E(Element),若键值匹配可以用K(Key)和V(Value)等,若是<?>,则是默认是允许Object及其下的子类,也就是java的所有对象了

2.泛型类

实例:

class Pair<T>{
    private T first;
    private T second;
    public Pair(){
        setFirst(null);
        setSecond(null);
    }
    public Pair(T f,T s){
        this.setFirst(f);
        this.setSecond(s);
    }

    public T getSecond() {
        return second;
    }
    public void setSecond(T second) {
        this.second = second;
    }
    public T getFirst() {
        return first;
    }
    public void setFirst(T first) {
        this.first = first;
    }
}

实例化:使用时,必须给T指定一个具体的类型(比如String):Pair<String>

注意:

  • 泛型参数必须是引用类型,不适用于基本数据类型
  • 不能定义泛型化数组 Pair<String>[] table=new Pair<String>[10];是错的
  • 不能直接创建泛型类型的实例
public Pair()  {
    first=new T();
    second=new T();
}//是错误的
  • 泛型类型不能直接或间接继承自Throwable,也无法抛出或捕获泛型类型的异常对象
  • 不能定义静态泛型成员

从泛型类派生子类:

不允许基类中有泛型参数

class Child extends MyClass<T>{} //是错误的
class Child extends MyClass<String>{}//对的

如果MyClass是泛型类,在定义子类时不指定泛型参数,则MyClass的泛型参数默认为Object

3.泛型方法

可以在普通类或泛型类中定义泛型方法:

public class TestMain {

    public static void main(String[] args) {
        String[] names={"aaa","bbb","ccc"};
        String mid=ArrayUtils.<String>getMiddle(names);
        //上句等同于
        mid=ArrayUtils.getMiddle(names);
    }
}
class ArrayUtils{
    public static  <T> T getMiddle(T[] arr){
        return arr[arr.length/2];
    }
}
<T> T 可以类比 T\[\] arr

可变参数,使用…定义个数可变参数:

    public static <T> List<T> toList(T... arr){
        List<T> list=new ArrayList<T>();
        for(T o:arr) list.add(o);
        return list;
    }

4.泛型多态特性

public class TestMain {

    public static void main(String[] args) {
        List<Number> nums=new ArrayList<Number>();
        nums.add(2);
        nums.add(3.14);
        for (Number number : nums) {
            System.out.println(number.getClass().getName());
        }

//      List<Integer> ints=new ArrayList<Integer>();
//      ints.add(1);
//      ints.add(2);
//      List<Number> nums2=ints;//报错

    }
}

以上例子总结:

List<Number> ArrayList<Number>是父子类关系

List<Number> List<Integer>不是父子俩关系!!!

5.泛型约束

有的时候,我们希望对泛型参数进行一些限制,比如,希望它实现XXX接口,必须是XXX的子类等等

指定泛型方法的泛型参数类型必须实现Comparable接口
public static <T extends Comparable> T min(T[] a){
    //
}

还可以指定多个约束条件:

T extends Comparable & Serializable

注意:多个约束中最多只能是一个类,且放在第一位

参数约束实例:

public class TestMain <T extends Number>{

    public static void main(String[] args) {
        TestMain<Integer> ai=new TestMain<Integer>();//OK

        //TestMain<String> as=new TestMain<String>();//错误
    }
}

JDK中”?”真实事例:

interface Collection<E> {      
    public boolean addAll(Collection< ? extends E > c);
    ... 
}

故以下代码正确:
List<Number> nums = new ArrayList<Number>();
List<Integer> ints = Arrays.asList(1, 2);
List<Double> dbls = Arrays.asList(2.78, 3.14);
nums.addAll(ints);
nums.addAll(dbls); 
<? extends T>表示该通配符所代表的类型是T类型的子类。

<? super T>表示该通配符所代表的类型是T类型的父类。

6.泛型类型擦除原理

public class Pair<T>{
    private T first;
    private T second;
}

对上述代码,Java编译器会将上述的T转为Object,以便在JVM上运行。——这就是擦除(erasure)

原因:Java虚拟机不直接支持泛型类型

泛型方法翻译实例:

public static <T extends Comparable> T min(T[] a) 

擦除后:

public static Comparable Min(Comparable[] a) 

也就是说实际并没有泛型这么一个东西。。。JVM在擦除后生成类型转换检查指令来匹配通配符。

参考:

金旭亮Java编程系列(大部分)

https://blog.csdn.net/u013378580/article/details/51850791

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值