Java泛型

本文详细介绍了Java泛型的概念、泛型类、泛型接口和泛型方法的定义,以及如何限定类型变量。同时,讨论了泛型的约束和局限性,如不能实例化、不能用于静态变量等。此外,还阐述了泛型的继承规则、通配符类型的使用,并通过示例展示了在实际开发中如何利用泛型解析JSON数据。
摘要由CSDN通过智能技术生成

原文章地址:https://www.jianshu.com/p/986f732ed2f1

1. 泛型存在的意义?

泛型:即“参数化类型”,将类型由原来的具体类型参数化,然后再使用/调用时传入具体的类型。
意义

1.适用于多种数据类型执行相同的代码
2. 泛型中的类型在使用时指定,不需要强制类型转换

2. 泛型类,泛型接口,泛型方法如何定义?

  • 泛型类定义:
public class GenericClass<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static void main(String[] args) {
        GenericClass<String> genericClass = new GenericClass<>();
        genericClass.setData("Generic Class");
        System.out.println(genericClass.getData());
    }
}
  • 泛型接口定义
 public interface GenericInterface<T> {
    T getData();
}
  • 泛型接口实现方式1:泛型接口实现类+泛型类型
public class GenericInterfaceImpl<T> implements GenericInterface<T>{
    private T data;
    private void setData(T data){
        this.data = data;
    }
    @Override
    public T getData() {
        return data;
    }
    public static void main(String[] args) {
        GenericInterfaceImpl<String> genericInterface = new GenericInterfaceImpl<>();
        genericInterface.setData("Generic Interface1");
        System.out.println(genericInterface.getData());
    }
}
  • 泛型接口实现方式2:泛型接口实现类 + 具体类型
public class GenericInterfaceImpl2 implements GenericInterface<String> {
    private String data;

    private void setData(String data){
        this.data = data;
    }
    @Override
    public String getData() {
        return data;
    }

    public static void main(String[] args) {
        GenericInterfaceImpl2 genericInterfaceImpl = new GenericInterfaceImpl2();
        genericInterfaceImpl.setData("Generic Interface");
        System.out.println(genericInterfaceImpl.getData());
    }
}
  • 泛型方法定义
public class GenericMethod {
    private static int add(int a,int b){
        System.out.println(a + "+" + b + "=" + (a+b));
        return a + b;
    }
    private static <T> T genericAdd(T a,T b){
        System.out.println(a + "+" + b + "=" + a + b);
        return a;
    }
    public static void main(String[] args) {
        System.out.println("return: " + GenericMethod.add(1,2));
        System.out.println("return: " + GenericMethod.genericAdd("a","b"));
    }
}

3. 如何限定类型变量?

  • 对类进行类型限定:public class TypeLimitForClass<T extends List & Serializable>
public class TypeLimitForClass<T extends List & Serializable> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
    public static void main(String[] args) {
        ArrayList<String> stringArrayList = new ArrayList<>();
        stringArrayList.add("A");
        stringArrayList.add("b");
        ArrayList<Integer> integerArrayList = new ArrayList<>();
        integerArrayList.add(1);
        integerArrayList.add(2);
        TypeLimitForClass<ArrayList> typeLimitForClass = new TypeLimitForClass<>();
        typeLimitForClass.setData(stringArrayList);
        TypeLimitForClass<ArrayList> typeLimitForClass1 = new TypeLimitForClass<>();
        typeLimitForClass1.setData(integerArrayList);

    }
}
  • 对方法进行类型限定:public static <T extends Comparable<T>> T getMin
public class TypeLimitForMethod {
    public static <T extends Comparable<T>> T getMin(T a,T b){
        return (a.compareTo(b) < 0) ? a : b;
    }
    public static void main(String[] args) {
        System.out.println(TypeLimitForMethod.getMin(1,5));
        System.out.println(TypeLimitForMethod.getMin("a","b"));
    }
}

4. 泛型中使用的约束和局限性有哪些?

1、泛型不能被实例化

public class GenericRestrict1<T> {
    static class NormalClass{
    }
    private T data;

    public void  setData(){
        this.data = new T();//Type parameter 'T' cannot be instantiated directly
    }
}

2、静态变量不能是泛型类型,但是静态泛型方法是可以的

private static T data1;//cannot be referenced from a static context
public static <K> K getData(K k){
        return k;
}

3、基本类型无法作为泛型类型

GenericRestrict1<int> restrict2 = new GenericRestrict1<int>();//Type argument cannot be of primitive type

4、无法使用instanceof关键字或==判断泛型类的类型

restrict1 instanceof GenericRestrict1<String> //Illegal generic type for instanceof

5、泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的

NormalClass normalClassA = new NormalClass();
NormalClass normalClassB = new NormalClass();

System.out.println(normalClassA == normalClassB);//false
System.out.println(restrict1.getClass() == integerGenericRestrict1.getClass());//true
System.out.println(restrict1.getClass());
System.out.println(integerGenericRestrict1.getClass());

6、泛型数组可以声明但无法实例化

GenericRestrict1<String>[] genericRestrict1s;//可以被声明
//genericRestrict1s = new GenericRestrict1<String>[10]; 不可声明为泛型
genericRestrict1s = new GenericRestrict1[10];
genericRestrict1s[0] = restrict1;

7、泛型类不能继承Exception或者Throwable

private class MyGenericException<T> extends Exception{
}
private class MyGenericThrowable<T> extends Throwable{
}
public <T extends Exception> void getExecption(T t){
    try {
    }catch (T e){
    }
}

8、不能捕获泛型类型限定的异常但可以将泛型限定的异常抛出

5. 泛型类型的继承规则是什么?

1、对于泛型参数是继承关系的泛型类之间是没有继承关系的

public class GenericInherit<T> {
    private T data1;
    private T data2;

    public T getData1() {
        return data1;
    }

    public void setData1(T data1) {
        this.data1 = data1;
    }

    public T getData2() {
        return data2;
    }

    public void setData2(T data2) {
        this.data2 = data2;
    }
    public static <V> void setData2(GenericInherit<Father> data2){

    }

    public static void main(String[] args) {
        Father father = new Father();
        Son son = new Son();
        GenericInherit<Father> fatherGenericInherit = new GenericInherit<>();
        GenericInherit<Son> sonGenericInherit = new GenericInherit<>();
        SubGenericInherit<Father> fatherSubGenericInherit = new SubGenericInherit<>();
        SubGenericInherit<Son> sonSubGenericInherit = new SubGenericInherit<>();

        father = new Son();

        setData2(fatherGenericInherit);
        setData2(fatherSubGenericInherit);
        //setData2(sonGenericInherit);    ERROR
        //泛型类的继承关系在使用中同样会受到泛型类型的影响
        setData2(sonSubGenericInherit);
    }
}

2、泛型类可以继承其它泛型类,例如: public class ArrayList extends AbstractList

		/**
         * 泛型类可以继承其它泛型类,例如: public class ArrayList<E> extends AbstractList<E>
  	     */
        fatherGenericInherit = new SubGenericInherit<Father>();

3、泛型类的继承关系在使用中同样会受到泛型类型的影响

6. 泛型中的通配符类型是什么?

public class GenericByWildcard {
    private static void print(GenericClass<Fruit> fruitGenericClass) {
        System.out.println(fruitGenericClass.getData().getType());
    }

    private static void use() {
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        print(fruitGenericClass);
        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        //传递的泛型之间是继承关系的泛型类之间是没有继承关系的
        //print(orangeGenericClass);   ERROR
    }

    /**
     * <? extends Fruit>规范了泛型的上限,即继承自Fruit的类都接受
     *
     * @param superGenericClass
     */
    private static void printExtend(GenericClass<? extends Fruit> superGenericClass) {
        System.out.println(superGenericClass.getData().getType());
    }

    private static void useExtend() {
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        printExtend(fruitGenericClass);
        GenericClass<Apple> appleGenericClass = new GenericClass<>();
        printExtend(appleGenericClass);
        GenericClass<Food> foodGenericClass = new GenericClass<>();
        //food超过了fruit会报错
        //printExtend(foodGenericClass);
        GenericClass<? extends Fruit> genericClass = new GenericClass<>();
        Apple apple = new Apple();
        Fruit fruit = new Fruit();
        /**
         * get时编译器可以肯定返回的是个X,set时编译器无法知道参数是X的哪个子类
         */
        //genericClass.setData(apple);
        //genericClass.setData(fruit);
        fruit = genericClass.getData();
    }

    public static void printSuper(GenericClass<? super Apple> genericClass) {
        System.out.println(genericClass.getData());
    }

    public static void useSuper() {
        GenericClass<Food> foodGenericClass = new GenericClass<>();
        printSuper(foodGenericClass);
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        printSuper(fruitGenericClass);
        GenericClass<Apple> appleGenericClass = new GenericClass<>();
        printSuper(appleGenericClass);
        //HongFuShi是Apple的子类所以类型不匹配
        GenericClass<HongFuShi> hongFuShiGenericClass = new GenericClass<>();
//        printSuper(hongFuShiGenericClass);
        GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>();
        supperAppleGenericClass.setData(new Apple());
        supperAppleGenericClass.setData(new HongFuShi());
        /*
        * ? super X 表示类型的下界,参数类型是X的超类
        * 那么可以肯定的说,get方法返回的一定是X的一个超类,具体是哪个不清楚
        * 但是可以肯定的说,Object一定是他的超类,所以get方法返回Object
        * 编译器是可以确定知道的,对于set方法来说,编译器不知道它需要的确切类型,但是X和X的子类可以安全的转型为X
        * 主要用于安全的写入数据,可以写入X及其子类型
        * */
        Object data = supperAppleGenericClass.getData();
    }

    /**
     * 没有指定的限定符
     * @param genericClass
     */
    public static void printNonLimit(GenericClass<?> genericClass){
        System.out.println(genericClass.getData());
    }

    public static void useNonLimit(){
        GenericClass<Food> foodGenericClass = new GenericClass<>();
        printNonLimit(foodGenericClass);
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        printNonLimit(fruitGenericClass);
        GenericClass<Apple> appleGenericClass = new GenericClass<>();
        printNonLimit(appleGenericClass);

        GenericClass<?> genericClass = new GenericClass<>();
//        genericClass.setData(foodGenericClass);
//        genericClass.setData(new Object());
        

        Object data = genericClass.getData();
    }
}
  1. 如何获取泛型的参数类型?

8. 虚拟机是如何实现泛型的?

Java泛型是Java1.5之后才引入的,为了向下兼容。Java采用了C++完全不同的实现思想。Java中的泛型更多的看起来像是编译期用的
Java中泛型在运行期是不可见的,会被擦除为它的上级类型。如果是没有限定的泛型参数类型,就会被替换为Object.即泛型擦除

9. 在日常开发中是如何运用泛型的?

1.泛型解析JSON数据封装

未完待续……

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值