Java中的泛型

Java中的泛型

泛型是一种参数化类型的机制。它可以使得代码适用于各种类型,从而编写更加通用的代码,例如集合框架。

泛型是一种编译时类型确认机制。它提供了编译期的类型安全,确保在泛型类型(通常为泛型集合)上只能使用正确类型的对象,避免了在运行时出现ClassCastException(类型转换错误异常)

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

使用泛型与不使用泛型的集合的区别

不使用泛型的集合

优点:集合不使用泛型,默认是Object类型,可以存储任何类型的元素

缺点:不安全,会引发异常

import java.util.ArrayList;

public class leeCode {
    public static void main(String[] args) {
        ArrayList e = new ArrayList();

        // 可以往集合里添加任意类型的元素
        e.add("字符串");
        e.add(1);
		
        // 因为无法确定集合里的对象类型,所以使用每个对象独有的方法
        // 会抛出异常
        for (Object k : e) {
            String s = (String)k;
            System.out.println(s.length());
        }
    }
}

使用泛型的集合

优点:避免了类型转换的麻烦,存取元素类型一致

缺点:指定了什么类型,就只能是什么类型,无法存入其他元素

import java.util.ArrayList;

public class leeCode {
    public static void main(String[] args) {
        // 使用泛型指定了集合存储的类型为String
        ArrayList<String> e = new ArrayList<String>();

        e.add("字符串1");
        // e.add(1);    error:只能存储字符串
        e.add("字符串2");

        for (String k : e) {
            System.out.println(k.length());
        }
    }
}

泛型的定义跟使用

作用:简单来说就是使一个类或者方法具有兼容性,可以根据我们需要的数据类型对某一种数据类型进行操作

定义和使用带有泛型的类

格式:

修饰符 class 类名<泛型变量>

Ex:

/*
	API中的ArrayList集合
*/
// E 代表一个未知的数据类型
class ArrayList<E> {
    public boolean add(E e) {
        // 方法体
    }
    
    public E get(int index) {
        // 方法体
    }
}
  • 什么时候确定泛型?

创建对象的时候确认泛型的类型

定义和使用带有泛型的方法

格式:

修饰符 <泛型变量> 返回值类型 方法名称 (参数)

Ex:

public class GenericMethodTest
{
   // 泛型方法 printArray 
   // 一个方法实现对多种数据类型的数据输出的功能,具备了一定的兼容性
   public static < E > void printArray( E[] inputArray )
   {
      // 输出数组元素            
         for ( E element : inputArray ){        
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }
 
    public static void main( String args[] )
    {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
 
        System.out.println( "整型数组元素为:" );
        printArray( intArray  ); // 传递一个整型数组
 
        System.out.println( "\n双精度型数组元素为:" );
        printArray( doubleArray ); // 传递一个双精度型数组
 
        System.out.println( "\n字符型数组元素为:" );
        printArray( charArray ); // 传递一个字符型数组
    } 
}

  • 什么时候确定泛型?

调用方法的时候确认泛型的类型

定义和使用带有泛型的接口

定义和使用含有泛型的类、接口、泛型通配符————————墨白

因为(继承)实现接口的时候对于泛型有两种情况,所以单独拿出来讨论。

当接口定义了泛型的时候,可以
1.实现(继承)时,保留接口(父类)的,这样相当于实现类(子类)也使用了泛型,在创建对象的时候确定泛型的数据类型。
2.实现(继承)时,直接把接口(父类)的写成想要实现的数据类型。

1、接口使用泛型

public interface MyInterFace<E> {
    public abstract E func1();
    public abstract E func2();
    public abstract E func3();
}

2、实现时指定是什么数据类型

public class MyImple implements MyInterFace<String> {
    public String func1(){
        System.out.println("fun1");
    }
    public String func2(){
        System.out.println("fun2");
    }
    public String func3(){
        System.out.println("fun3");
    }
}

或者实现类依旧带泛型

public class MyImple<E> implements MyInterFace<E> {
    public  E func1(){
        System.out.println("fun1");
        return null;
    }
    public  E func2(){
        System.out.println("fun2");
        return null;
    }
    public  E func3(){
        System.out.println("fun3");
        return null;
    }
}

泛型通配符

类型通配符一般是使用 ?代替具体的类型参数。例如 List 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
import java.util.*;
 
public class GenericTest {
     
    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();
        
        name.add("icon");
        age.add(18);
        number.add(314);
 
        getData(name);
        getData(age);
        getData(number);
       
   }
   // 因为getData()方法的参数是List类型的,所以name,age,number都可以作为这个方法的实参,这就是通配符的作用 
   public static void getData(List<?> data) {
      System.out.println("data :" + data.get(0));
   }
}
  • 类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
import java.util.*;
 
public class GenericTest {
     
    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();
        
        name.add("icon");
        age.add(18);
        number.add(314);
 		
        // 1报错,因为getUperNumber()方法中的参数已经限定了参数泛型上限为Number,所以泛型为String是不在这个范围之内,所以会报错 
        //getUperNumber(name);//1
        getUperNumber(age);//2
        getUperNumber(number);//3
       
   }
 
   public static void getData(List<?> data) {
      System.out.println("data :" + data.get(0));
   }
   
   public static void getUperNumber(List<? extends Number> data) {
          System.out.println("data :" + data.get(0));
       }
}

  • 3、类型通配符下限通过形如 List来定义,表示类型只能接受Number及其三层父类类型,如 Object 类型的实例。
posted @ 2020-03-12 20:28  lorz5  阅读(202)  评论(0编辑  收藏  举报