Java 泛型

Java泛型

1. 什么是泛型?

是JDK5引起的新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型,类型安全,将本来在运行期的类型ClassCastException错误提前在编译期发现。

2. 为什么使用泛型:

  1. 泛型可以增强编译时错误检测,减少因类型问题引发的异常。
  2. 泛型可以避免类型转换
    3 . 泛型算法可以增加代码复用性

3. 泛型的类型参数命名约定

按照约定,类型参数名称命名为单个大写字母,以便可以在使用普通类或接口名称时能够容易地区分类型参数。常用的类型参数名称列表如下:
E - 元素,主要由Java集合(Collections)框架使用。
K - 键,主要用于表示映射中的键的参数类型。
V - 值,主要用于表示映射中的值的参数类型。
N - 数字,主要用于表示数字。
T - 类型,主要用于表示第一类通用型参数。
S - 类型,主要用于表示第二类通用类型参数。
U - 类型,主要用于表示第三类通用类型参数。
V - 类型,主要用于表示第四个通用类型参数。

测试用例一:
/**
 * 不使用泛型需要强制类型转换
 *  result :
 *  list.get(0) : class java.lang.String
 *  s : class java.lang.String
 */
private static  void demo1(){
    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);//向下转型,不转将会报错
    System.out.println(" list.get(0) :" + list.get(0).getClass());
    System.out.println(" s :" + s.getClass());
}
/**
* 使用泛型不需要强制类型转换
 * result :
 * demo2 list.get(0) :class java.lang.String
 * demo2 s :class java.lang.String
 */
private static  void demo2(){
    List<String> list = new ArrayList<>();
    list.add("hello");
    String s = list.get(0);//不需要类型转换
    System.out.println("demo2 list.get(0) :" + list.get(0).getClass());
    System.out.println("demo2 s :" + s.getClass());
}

泛型的类型写法:

/**
 * 泛型类(泛型接口也是这样定义)
 * class name<T1, T2 ,T3>{}
 *
 * @param <T1>
 */
public class Box<T1> {
    private T1 t;
    /**
     * 泛型接口
     * @param <T>
     */
    private interface Generics<T>{}

    /**
     *  泛型方法,没有返回值的
     * @param t2
     * @param <T2>
     */
    public <T2> void test(T2 t2){
    }
    // 这个也不是泛型泛型
    public void test2(List<String> list){
    }
    // 这个也不是泛型泛型
    public void test3(List<?> list){
    }
    //注意这个不是泛型方法,就是一个泛型的入参
    public void set(T1 t) {
        this.t = t;
    }
    //注意这个不是泛型方法 
    public T1 get() {
        return t;
    }
}

下面是要注意的泛型的接口实现:

interface Generics<T> {}
//1. 泛型类/泛型接口  继承/实现
class Generics2<T> implements Generics<T>{}
//2. 泛型类/泛型接口  继承/实现
class Generics3 implements Generics<String>{}

受限的类型参数:
功能:对泛型变量的范围作出限制
格式:
单一限制 :
多种限制: <U extends A &B &C>
extends 表达的意义:兼有“类继承”和接口实现的意思。

////inspect
public static <U extends Number> void inspect(U u){
    System.out.println("U :" + u.getClass().getName());
}
private static  void demo3(){
    inspect(10L);
    inspect("111");//报错
}

多重限定:

static class A {}
static interface B {}
static interface C {}
//只能继承一个实例类A 接口可以继承多个
static class D1<T extends A & B & C> {}

受限类型的使用案例,这种因为方法里面使用了compareTo,如果不将T限定为Comparable,
而是让T继承一个没有实现compareTo方法的类,函数将报错:

public static <T extends Comparable<T>> int countGreater(T[] anArray, T elem) {
    int count = 0;
    for (T e : anArray) {
        //受限于Comparable<T>,所以可以使用compareTo方法
        if (e.compareTo(elem) > 0) {
           ++count;
        }
    }
    return count;
}

使用上限通配符:

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1,2,3,1,9);
    double s = sumofList(list);
    System.out.println(" upper_bounded s :" + s);
    List<Double> listDouble = Arrays.asList(1.1,2.2,3.5,1.8,9.4);
    double sumDouble = sumofList(listDouble);
    System.out.println(" upper_bounded sumDouble :" + sumDouble);

    //List<String> listString = Arrays.asList("a","b","c"); 报错
    //sumofList(listString);
}
// 表示list里面元素的集合只能是Number及其子类,使用的是上限通配符,就是Producer extends
public static double sumofList(List<? extends Number> list){
    double sum = 0f;
    //list.add(2); 副作用 ,只能读不能往里面添加
    for (Number n: list) {
        sum += n.doubleValue();
    }
    return sum;
}

泛型的约束

1.不能实例化对象。
2.静态域或者方法里面不能引用类型变量,至于为什么不能引用要看static变量的创建时机

//静态域或者方法里不能引用类型变量,虚拟机在创建对象的时候,先执行static
// 再构执行构造方法
//构造方法都没有
private static  T instance;
private static T getInstance(){}
//但是可以使用,这个T和前面的类型T可以完全没有关系
private static <T> T getInstance(){}
public class Restrict<T> {
    private T data;
    public static void main(String[] args) {
        Restrict<Double> restrict = new Restrict<>();
        Restrict<String> restrictString  = new Restrict<>();
        //true
        System.out.println(restrict.getClass() == restrictString.getClass());
        //class com.genericsdemo.why_use_generics_01.Restrict
        System.out.println(restrict.getClass());
    }
}
不能创建泛型数组
Restrict<Double>[] list  = new Restrict<Double> [10];
public class Restrict {
    //泛型类不能继承Exception
    private class problem<T> extends Exception{}
    //这种继承是可以的
    private class problem1<T> extends Restrict{}
}
//不能捕获泛型类对象
private <T extends Throwable> void dowork(){
    try {
    }catch (T t){}
}

泛型通配符的使用

只能在使用方法的时候使用,向上限定符extends 为了安全的读取
向下限定符super 为了安全的写入

在Javac编译之后可以看到去掉了泛型,义原生类型-fu来替换 差除替换泛型

public void fun(List<? extends Fruit> arraylist){
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值