Java泛型理解与泛型的具体使用

一、泛型定义

泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。泛型也可以看出是一个变量,用来接收数据类型。

以集合类ArrayList源码为例:

//类定义时,不知道集合中会存储什么类型的参数,所以类型使用泛型
//E:未知的数据类型 
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
//成员方法get        
public E get(int index) {}
//成员方法add
public boolen add(E e){}

二、泛型使用

以集合类ArrayList创建具体类型时为例:

//创建集合对象时指定String数据类型
Collection<String> collection = new ArrayList<>();

/**
* public boolean add(E e):把给定的对象添加到当前集合中。
*/
collection.add("Hello");
collection.add("World");
collection.add("!!!!!");

三、使用泛型的好处

不使用泛型在程序运行期可能会发生类型转换错误

 public static void main(String[] args) {
        ArrayList arrayList = new ArrayList<>();
		//不使用时泛型时,集合中可以任意加入Object类型
        arrayList.add("Hello");
        arrayList.add(100000);


        Iterator iterator= arrayList.iterator();
        while(iterator.hasNext()){
            Object object= iterator.next();
            System.out.println(object);

            //不使用泛型,在程序运行期进行Object类型强制转换时会发生类型转换错误
            //Exception in thread "main" java.lang.ClassCastException:
            // java.lang.Integer cannot be cast to java.lang.String
            String string =(String)object;  
            System.out.println(string);
        }
    }

使用泛型在代码编译期就可以提示类型错误

 public static void main(String[] args) {

        //定义时指定String类型
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("Hello");
        //在编译期时就发生错误
        //arrayList.add(100000);

        //迭代器根据集合对象的数据类型进行定义
        Iterator<String> iterator= arrayList.iterator();
        while(iterator.hasNext()){
            //使用泛型,由于在定义时就指定了数据类型,不需要进行类型转换
            String string = iterator.next();
            System.out.println(string);
        }
    }

四、定义含有泛型的类

泛型类,是在实例化类的时候指明泛型的具体类型
以下代码为定义含有泛型的类MyGenericClass

/**
 * @author zhuhuix
 */
public class MyGenericClass<E> {

    private E name;

    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }

    public static void main(String[] args) {
    	//创建MyGenericClass对象,泛型使用String
        MyGenericClass<String> myGenericClass1 = new MyGenericClass<>();
        myGenericClass1.setName("jack");
        System.out.println(myGenericClass1.getName());

        //创建MyGenericClass对象,泛型使用Integer
        MyGenericClass<Integer> myGenericClass2 = new MyGenericClass<>();
        myGenericClass2.setName(10000);
        System.out.println(myGenericClass2.getName());

    }
}

五、定义含有泛型的方法

泛型方法,是在调用方法的时候指明泛型的具体类型
以下代码为普通类为定义一个泛型的方法

/**
 * @author  zhuhuix
 * 定义一个普通类,在普通类中定义泛型方法及调用
 */
public class MyGenericMethod {

    //定义泛型的方法:在public 与void之间有一个泛型T,可以认为此方法为泛型方法
    public <T> void myMethod(T t){
        System.out.println(t);
    }

    public static void main(String[] args) {
        MyGenericMethod myGenericMethod = new MyGenericMethod();
        //调用泛型方法时指定泛型参数为String
        myGenericMethod.myMethod("Hello");
        //调用泛型方法时指定泛型参数为Integer
        myGenericMethod.myMethod(10000);
    }
}

五、定义含有泛型的接口

泛型接口与泛型类的定义及使用相同。

/**
 * @param <T> 接口中的泛型
 * @author zhuhuix
 */
public interface MyGenericInterface<T> {

    void myGenericIntefaceMethod(T t);

}

//接口中使用泛型,则实现类也必须使用泛型
public class MyGenericInterfaceImpl<T> implements MyGenericInterface<T> {

    @Override
    public void myGenericIntefaceMethod(T t) {
        System.out.println(t);
    }

    public static void main(String[] args) {
       //创建MyGenericInterface对象,指定泛型为String
        MyGenericInterface<String> myGenericInterface1= new MyGenericInterfaceImpl<>();
        myGenericInterface1.myGenericIntefaceMethod("Hello World");

        //创建MyGenericInterface对象,指定泛型为Integer
        MyGenericInterface<Integer> myGenericInterface2= new MyGenericInterfaceImpl<>();
        myGenericInterface2.myGenericIntefaceMethod(111111);
    }
}

六、泛型的通配符

1、泛型通配符的常规用法

泛型的通配符用 ? 表示,代表任意的数据类型,不能创建对象使用,只能作为方法的参数使用。也就是说泛型通配符?只能出现在方法的参数中。

/**
 * @author zhuhuix
 */
public class MyGenericMatch {

    //该成员方法通过迭代器进行遍历ArrayList,
    // 但传入的集合参数为不确定的数据类型,所以用泛型通配符进行定义
    public static void printArray(ArrayList<?> arrayList){
        Iterator<?> iterator = arrayList.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    public static void main(String[] args) {
        ArrayList<String> arrayListString = new ArrayList<>();
        arrayListString.add("Hello");
        arrayListString.add("World");
        arrayListString.add("!!!!!");

        ArrayList<Integer> arrayListInteger = new ArrayList<>();
        arrayListInteger.add(1);
        arrayListInteger.add(2);
        arrayListInteger.add(3);

        //通配String类型
        printArray(arrayListString);
        //通配Integer类型
        printArray(arrayListInteger);
    }
}

2、泛型通配符的上限限定与下限限定

上限限定:? extends E 代表使用的泛型只能是E类型的子类/本身
下限限定:? super E 代表使用的泛型只能是E类型的父类/本身
也就是说通过上下限的限定,限定方法参数数据类型的范围。

/**
 * @author zhuhuix
 */
public class MyGenericMatchLimit {
    
    //泛型上限限定:泛型通配符?必须时Number类型或者Number类型的子类
    public static void printCollection1(Collection<? extends Number> collection){
        Iterator<?> iterator = collection.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    //泛型下限限定:泛型通配符?必须时Number类型或者Number类型的父类
    public static void printCollection2(Collection<? super Number> collection){
        Iterator<?> iterator = collection.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    public static void main(String[] args) {
        Collection<Integer> collection1 = new ArrayList<>();
        Collection<Number> collection2 = new ArrayList<>();
        Collection<Object> collection3 = new ArrayList<>();
        
        //正确
        printCollection1(collection1);
        
        //正确
        printCollection1(collection2);
        
        //报错:Object为Number的父类,超过上限,泛型上限限定只能是Number或Number的子类
        //printCollection1(collection3);

        //报错:Integer为Number的子类,超过下限,泛型下限限定只能是Number或Number的父类
        //printCollection2(collection1);
        
        //正确
        printCollection2(collection2);
        
        //正确
        printCollection2(collection3);
        
    }
}

原创文章 56 获赞 8 访问量 4729

猜你喜欢

转载自blog.csdn.net/jpgzhu/article/details/105763338