泛型详解


在这里插入图片描述

泛型的定义以及存在意义

泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
例如:GenericClass< T >{}

一些常用的泛型类型变量:
E:元素(Element),多用于java集合框架
K:关键字(Key)
N:数字(Number)
T:类型(Type)
V:值(Value)

如果要实现不同类型的加法,每种类型都需要重载一个add方法。

package com.base.fanxing;

public class NeedGeneric1{
	 private static int add(int a, int b) {
		 System.out.println(a + "+" + b + "=" + (a + b));
	     return a + b;
	 }

	 private static float add(float a, float b) {
	     System.out.println(a + "+" + b + "=" + (a + b));
	     return a + b;
	 }

	 private static double add(double a, double b) {
		 System.out.println(a + "+" + b + "=" + (a + b));
	     return a + b;
	 }

	 private static <T extends Number> double add(T a, T b) {
		 System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
	     return a.doubleValue() + b.doubleValue();
	 }

	 public static void main(String[] args) {
		 NeedGeneric1.add(1, 2);//1+2=3
	     NeedGeneric1.add(1f, 2f);//1.0+2.0=3.0
	     NeedGeneric1.add(1d, 2d);//1.0+2.0=3.0
	     NeedGeneric1.add(Integer.valueOf(1), Integer.valueOf(2));//1+2=3.0
	     NeedGeneric1.add(Float.valueOf(1), Float.valueOf(2));//1.0+2.0=3.0
	     NeedGeneric1.add(Double.valueOf(1), Double.valueOf(2));//1.0+2.0=3.0
	 }
}

取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易现“java.lang. ClassCast Exception”异常。

package com.base.fanxing;

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

/**
 * 为什么使用泛型
 * @author acer
 *
 */
public class NeedGeneric2 {
    static class C{

    }
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add("A");
        list.add("B");
        list.add(new C());
        list.add(100);
        //1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。
        //2.因此,取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。
        for (int i = 0; i < list.size(); i++) {
            String value= (String) list.get(i);
            System.out.println(value);
        }
    }
}

所以使用泛型的意义在于:
1,适用于多种数据类型执行相同的代码(代码复用)
2,泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

泛型类的使用

定义一个泛型类:public class GenericClass< T >{}

package com.base.fanxing;

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());//Generic Class
    }
}

泛型接口的使用

定义一个泛型接口:public interface GenericIntercace< T >{}

package com.base.fanxing;

public interface GenericIntercace<T> {
	T getData();
}

实现泛型接口方式一:public class ImplGenericInterface1 implements GenericIntercace

package com.base.fanxing;

// 泛型接口实现类-泛型类实现方式
public class ImplGenericInterface1<T> implements GenericIntercace<T>{
	
	private T data;
	
	private void setData(T data) {
		this.data = data;
	}
	
	@Override
	public T getData() {
		return data;
	}

	public static void main(String[] args) {
		ImplGenericInterface1<String> implGenericInterface1 = new ImplGenericInterface1<String>();
		implGenericInterface1.setData("Generic Interface1");
		System.out.println(implGenericInterface1.getData());//Generic Interface1
	}
}

实现泛型接口方式二:public class ImplGenericInterface2 implements GenericIntercace< String > {}

package com.base.fanxing;

//泛型接口实现类-指定具体类型实现方式
public class ImplGenericInterface2 implements GenericIntercace<String> {
	
    @Override
    public String getData() {
        return "Generic Interface2";
    }

    public static void main(String[] args) {
        ImplGenericInterface2 implGenericInterface2 = new ImplGenericInterface2();
        System.out.println(implGenericInterface2.getData());
    }
}

泛型方法的使用

定义一个泛型方法: private static< T > T genericAdd(T a, T b) {}

package com.base.fanxing;

public class GenericMethod1 {
	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) {
		GenericMethod1.add(1, 2);//1+2=3
		GenericMethod1.<Integer>genericAdd(1,2);//1+2=12
	}
}
package com.base.fanxing;

public class GenericMethod3 {

    static class Animal {
        @Override
        public String toString() {
            return "Animal";
        }
    }

    static class Dog extends Animal {
        @Override
        public String toString() {
            return "Dog";
        }
    }

    static class Fruit {
        @Override
        public String toString() {
            return "Fruit";
        }
    }

    static class GenericClass<T> {

        public void show01(T t) {
            System.out.println(t.toString());
        }

        public <T> void show02(T t) {
            System.out.println(t.toString());
        }

        public <K> void show03(K k) {
            System.out.println(k.toString());
        }
    }


    public static void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = new Dog();
        Fruit fruit = new Fruit();
        GenericClass<Animal> genericClass = new GenericClass<>();
        //泛型类在初始化时限制了参数类型
        genericClass.show01(dog);// Dog
//        genericClass.show01(fruit); 编译出错

        //泛型方法的参数类型在使用时指定   
        //以下两种写法都可以
        genericClass.<Animal>show02(dog);//Dog
        genericClass.show02(fruit);//Fruit

        genericClass.show03(animal);//Animal
        genericClass.<Animal>show03(dog);//Dog
        genericClass.show03(fruit);//Fruit
//        genericClass.<Dog>show03(animal); 编译出错
    }
}

限定泛型类型变量

1,对类的限定:public class TypeLimitForClass<T extends List & Serializable>{}
2,对方法的限定:public static<T extends Comparable>T getMin(T a, T b) {}

package com.base.fanxing;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

//类型变量的限定-类
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);
        integerArrayList.add(3);
        TypeLimitForClass<ArrayList> typeLimitForClass01 = new TypeLimitForClass<>();
        typeLimitForClass01.setData(stringArrayList);
        TypeLimitForClass<ArrayList> typeLimitForClass02 = new TypeLimitForClass<>();
        typeLimitForClass02.setData(integerArrayList);

        // 2
        System.out.println(getMinListSize(typeLimitForClass01.getData().size(), typeLimitForClass02.getData().size()));

    }

    public static <T extends Comparable<T>> T getMinListSize(T a, T b) {
        return (a.compareTo(b) < 0) ? a : b;
    }
}
package com.base.fanxing;

//类型变量的限定-方法
public class TypeLimitForMethod {
	/**
     * 计算最小值
     * 如果要实现这样的功能就需要对泛型方法的类型做出限定 	
     */
//    private static <T> T getMin(T a, T b) {
//        return (a.compareTo(b) < 0) ? a : b;
//    }

    /**
     * 限定类型使用extends关键字指定
     * 可以使类,接口,类放在前面接口放在后面用&符号分割
     * 例如:<T extends ArrayList & Comparable<T> & Serializable>
     */
    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(2, 4));//2
        System.out.println(TypeLimitForMethod.getMin("a", "r"));//a
    }
}

泛型中的约束和局限性

1,不能实例化泛型类
2,静态变量或方法不能引用泛型类型变量,但是静态泛型方法是可以的
3,基本类型无法作为泛型类型
4,无法使用instanceof关键字或==判断泛型类的类型
5,泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的
6,泛型数组可以声明但无法实例化
7,泛型类不能继承Exception或者Throwable
8,不能捕获泛型类型限定的异常但可以将泛型限定的异常抛出

package com.base.fanxing;

//泛型的约束和局限性
public class GenericRestrict1<T> {
	static class NormalClass{
		
	}
	
	private T data;
	
	/**
	 * 不能实例化泛型类
	 */
	public void setData() {
//		this.data = new T();
	}
	
	/**
	 * 静态变量或方法不能引用泛型类型变量
	 * 
	 */
//	private static T result;
//	private static T getResult() {
//		return result;
//	}
	
	/**
	 * 静态泛型方法是可以的
	 */
	private static <K> K getKey(K k){
		return k;
	}
	
	
	
	public static void main(String[] args) {
		NormalClass normalClassA = new NormalClass();
		NormalClass normalClassB = new NormalClass();
		
		// 基本类型无法作为泛型类型
//		GenericRestrict1<int> gen = new GenericRestrict1<>();
		GenericRestrict1<Integer> genericRestrict1 = new GenericRestrict1<Integer>();
		GenericRestrict1<String> genericRestrict2 = new GenericRestrict1<String>();
		
		/**
		 * 无法使用instanceof关键字判断泛型类的类型
		 * 
		 */
//		if(genericRestrict1 instanceof GenericRestrict1<Integer>) {
//			// ...
//		}
		
		// 无法使用==判断两个泛型类的实例
//		if(genericRestrict2 == GenericRestrict1<String>) {
//			//...
//		}
		
		/**
		 * 泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的
		 */
		System.out.println(normalClassA == normalClassB);
		System.out.println(genericRestrict1 == genericRestrict1);
		System.out.println(genericRestrict1.getClass() == genericRestrict2.getClass());
		System.out.println(genericRestrict1.getClass());
		System.out.println(genericRestrict2.getClass());
		
		/**
		 * 泛型数组可以声明但是无法实例化
		 */
		GenericRestrict1<String>[] genericRestrict1s;
//		genericRestrict1s = new GenericRestrict1<String>[10];
		genericRestrict1s = new GenericRestrict1[10];
		genericRestrict1s[0] = genericRestrict2;
	}
}
package com.base.fanxing;

//泛型和异常
public class GenericRestrict2 {
	private class MyException extends Exception {
    }

    /**
     * 泛型类不能继承Exception或者Throwable
     * Generic class may not extend 'java.lang.Throwable'
     */
//    private class MyGenericException<T> extends Exception {
//    }
//
//    private class MyGenericThrowable<T> extends Throwable {
//    }

    /**
     * 不能捕获泛型类型限定的异常
     * Cannot catch type parameters
     */
    public <T extends Exception> void getException(T t) {
//        try {
//
//        } catch (T e) {
//	
//        }
    }

    /**
     *可以将泛型限定的异常抛出
     */
    public <T extends Throwable> void getException(T t) throws T {
        try {

        } catch (Exception e) {
            throw t;
        }
    }
}

泛型类型继承规则

1,对于泛型参数是继承关系的泛型类之间是没有继承关系的
2,泛型类可以继承其它泛型类,例如:public class ArrayList extends AbstractList
3,泛型类的继承关系在使用中同样会受到泛型类型的影响

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) {
//        Son 继承自 Father
        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<>();

        /**
         * 对于传递的泛型类型是继承关系的泛型类之间是没有继承关系的
         * GenericInherit<Father> 与GenericInherit<Son> 没有继承关系
         * Incompatible types.
         */
        father = new Son();
//        fatherGenericInherit=new GenericInherit<Son>();

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

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

    }

    private static class SubGenericInherit<T> extends GenericInherit<T> {

    }

通配符类型

1,<? extends Parent> 指定了泛型类型的上届
2,<? super Child> 指定了泛型类型的下届
3,<?> 指定了没有限制的泛型类型
在这里插入图片描述

// 泛型通配符测试类
public class GenericByWildcard {
    private static void print(GenericClass<Fruit> fruitGenericClass) {
        System.out.println(fruitGenericClass.getData().getColor());
    }

    private static void use() {
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        print(fruitGenericClass);
        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        //类型不匹配,可以使用<? extends Parent> 来解决
//        print(orangeGenericClass);
    }

    /**
     * <? extends Parent> 指定了泛型类型的上届
     */
    private static void printExtends(GenericClass<? extends Fruit> genericClass) {
        System.out.println(genericClass.getData().getColor());
    }

    public static void useExtend() {
        GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
        printExtends(fruitGenericClass);
        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        printExtends(orangeGenericClass);

        GenericClass<Food> foodGenericClass = new GenericClass<>();
        //Food是Fruit的父类,超过了泛型上届范围,类型不匹配
//        printExtends(foodGenericClass);

        //表示GenericClass的类型参数的上届是Fruit
        GenericClass<? extends Fruit> extendFruitGenericClass = new GenericClass<>();
        Apple apple = new Apple();
        Fruit fruit = new Fruit();
        /*
         * 道理很简单,? extends X  表示类型的上界,类型参数是X的子类,那么可以肯定的说,
         * get方法返回的一定是个X(不管是X或者X的子类)编译器是可以确定知道的。
         * 但是set方法只知道传入的是个X,至于具体是X的那个子类,不知道。
         * 总结:主要用于安全地访问数据,可以访问X及其子类型,并且不能写入非null的数据。
         */
//        extendFruitGenericClass.setData(apple);
//        extendFruitGenericClass.setData(fruit);

        fruit = extendFruitGenericClass.getData();

    }

    /**
     * <? super Child> 指定了泛型类型的下届
     */
    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);

        GenericClass<HongFuShiApple> hongFuShiAppleGenericClass = new GenericClass<>();
        // HongFuShiApple 是Apple的子类,达不到泛型下届,类型不匹配
//        printSuper(hongFuShiAppleGenericClass);

        GenericClass<Orange> orangeGenericClass = new GenericClass<>();
        // Orange和Apple是兄弟关系,没有继承关系,类型不匹配
//        printSuper(orangeGenericClass);

        //表示GenericClass的类型参数的下界是Apple
        GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>();
        supperAppleGenericClass.setData(new Apple());
        supperAppleGenericClass.setData(new HongFuShiApple());
        /*
         * ? super  X  表示类型的下界,类型参数是X的超类(包括X本身),
         * 那么可以肯定的说,get方法返回的一定是个X的超类,那么到底是哪个超类?不知道,
         * 但是可以肯定的说,Object一定是它的超类,所以get方法返回Object。
         * 编译器是可以确定知道的。对于set方法来说,编译器不知道它需要的确切类型,但是X和X的子类可以安全的转型为X。
         * 总结:主要用于安全地写入数据,可以写入X及其子类型。
         */
//        supperAppleGenericClass.setData(new Fruit());

        //get方法只会返回一个Object类型的值。
        Object data = supperAppleGenericClass.getData();
    }

    /**
     * <?> 指定了没有限定的通配符
     */
    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<>();
        //setData 方法不能被调用, 甚至不能用 Object 调用;
//        genericClass.setData(foodGenericClass);
//        genericClass.setData(new Object());
        //返回值只能赋给 Object
        Object object = genericClass.getData();
    }
}

获取泛型的参数类型

Type是什么?
这里的Type指java.lang.reflect.Type, 是Java中所有类型的公共高级接口, 代表了Java中的所有类型. Type体系中类型的包括:数组类型(GenericArrayType)、参数化类型(ParameterizedType)、类型变量(TypeVariable)、通配符类型(WildcardType)、原始类型(Class)、基本类型(Class), 以上这些类型都实现Type接口。

参数化类型,就是我们平常所用到的泛型List、Map;
数组类型,并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ;
通配符类型, 指的是<?>, <? extends T>等等
原始类型, 不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;
基本类型, 也就是我们所说的java的基本类型,即int,float,double等

package com.base.fanxing;

import java.lang.reflect.Type;

public interface ParameterizedType extends Type{
	// 返回确切的泛型参数,如Map<String,Integer>返回[String,Integer]
	Type[] getActualTypeArguments();
	
	//返回当前class或interface声明的类型,如List<?>返回List
	Type getRawType();
	
    //返回所属类型. 如,当前类型为O<T>.I<S>, 则返回O<T>. 顶级类型将返回null 
    Type getOwnerType();
}
package com.base.fanxing;

import java.lang.reflect.Type;

public class GenericType<T> {
	private T data;

    public T getData() {
        return data;
    }

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

    public static void main(String[] args) {
        GenericType<String> genericType = new GenericType<String>() {};
        Type superclass = genericType.getClass().getGenericSuperclass();
        //getActualTypeArguments 返回确切的泛型参数, 如Map<String, Integer>返回[String, Integer]
        Type type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; 
        System.out.println(type);//class java.lang.String
    }
}

虚拟机是如何实现泛型的

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

GenericClass<String> stringGenericClass=new GenericClass<>();
GenericClass<Integer> integerGenericClass=new GenericClass<>();

C++中GenericClass< String >和GenericClass< Integer >是两个不同的类型
Java进行了类型擦除之后统一改为GenericClass< Object >

package com.base.fanxing;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

//泛型原理测试类
public class GenericTheory {
	 public static void main(String[] args) {
	        Map<String, String> map = new HashMap<>();
	        map.put("Key", "Value");
	        System.out.println(map.get("Key"));
	        GenericClass<String, String> genericClass = new GenericClass<>();
	        genericClass.put("Key", "Value");
	        System.out.println(genericClass.get("Key"));
	    }

	    public static class GenericClass<K, V> {
	        private K key;
	        private V value;

	        public void put(K key, V value) {
	            this.key = key;
	            this.value = value;
	        }

	        public V get(V key) {
	            return value;
	        }
	    }

	    /**
	     * 类型擦除后GenericClass2<Object>
	     * @param <T>
	     */
	    private class GenericClass2<T> {

	    }

	    /**
	     * 类型擦除后GenericClass3<ArrayList>
	     * 当使用到Serializable时会将相应代码强制转换为Serializable
	     * @param <T>
	     */
	    private class GenericClass3<T extends ArrayList & Serializable> {

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值