zoukankan      html  css  js  c++  java
  • 【JavaSE】泛型

    Java泛型


    2019-07-05  22:00:24  by冲冲

    1. 泛型的引例

     1 List list = new ArrayList();
     2 list.add(1022);        //向集合中添加一个 Integer 类型的数据
     3 list.add("Yadiel");    //向集合中添加一个 String 类型的数据
     4 
     5 //遍历list元素
     6 for(int i = 0 ; i < list.size() ; i++){
     7     Object obj = list.get(i);  //注意这里每个类型都是 Object
     8     System.out.println(obj);
     9 }
    10  
    11 //如果遍历的时候就想得到自己想要的数据类型
    12 for(int i = 0 ; i < list.size() ; i++){
    13     String obj = (String) list.get(i);  //在取 Integer 的时候会报类型转换错误
    14     System.out.println(obj);
    15 }

     报错信息:

    意思是 集合中第二个数据是 Integer,但是我们取出来的时候将其转换为 String 了,所以报错。

    解决方案:

    ① 我们在遍历的时候,根据每个数据的类型判断,然后进行强转。缺陷是,如果数据成千上万,该方案不可取。

    ② 在往集合中加入数据的时候,就做好限制,比如这个集合只能添加 String 类型的,下一个集合只能添加 Integer 类型的(就像数组一样规定元素类型必须相同),那么在取数据时,由于前面已经限制了该集合的数据类型,那么就很好强转了。这第二种解决办法,也就是我们这篇文章讲的 泛型

    2. 泛型的概念

    泛型是Java SE1.5的新特性。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法

    在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

    3. 泛型的语法

    (1)引例的解决

     1 List<String> list = new ArrayList<String>();
     2 //list.add(1022);  //向集合中添加一个 Integer 类型的数据时,编译器会报错
     3 list.add("Aoa");   //向集合中添加一个 String 类型的数据
     4 list.add("Loa");   //向集合中添加一个 String 类型的数据
     5  
     6 //如果我们遍历的时候就想得到自己想要的数据类型
     7 for(int i = 0 ; i < list.size() ; i++){
     8     String obj = list.get(i);  //这里就不需要强转了,前面添加的是什么类型,这里获取的就是什么类型
     9     System.out.println(obj);
    10 }

    (2)泛型只在编译阶段有效

    1 List<String> list1 = new ArrayList<String>();
    2 List list2 = new ArrayList();
    3 Class c1 = list1.getClass();
    4 Class c2 = list2.getClass();
    5 System.out.println(c1==c2); //true

    由于反射是在运行时阶段,c1==c2为 true,说明编译之后的 class 文件中是不包含泛型信息。

    结论:Java 泛型只在编译阶段有效,即在编译过程中,程序会正确的检验泛型结果。而编译成功后,class 文件是不包含任何泛型信息的

    (3)泛型类

    在类名后面添加 类型参数 的声明部分,其他跟非泛型类完全一样。

    泛型类的类型参数声明部分,可以包含一个或多个类型参数,参数间用逗号隔开。

     1 public class Box<T> {
     2   private T t;
     3   public void add(T t) {
     4     this.t = t;
     5   }
     6   public T get() {
     7     return t;
     8   }
     9  
    10   public static void main(String[] args) {
    11     Box<Integer> integerBox = new Box<Integer>();
    12     Box<String> stringBox = new Box<String>();
    13  
    14     integerBox.add(new Integer(1022));
    15     stringBox.add(new String("肥猪"));
    16  
    17     System.out.println("整型值为 :"+ integerBox.get());
    18     System.out.println("字符串为 :"+ stringBox.get());
    19   }
    20 }

    输出结果:

    1 整型值为 :1022
    2 字符串为 :肥猪

    (4)泛型方法

    应用场景:假如需要写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?答案是泛型。

    定义泛型方法的规则:

    ① 所有泛型方法声明,都有一个 类型参数 的声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。

    ② 每一个 类型参数 声明部分可以包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

    ③ 类型参数 能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

    ④ 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char等)。

     1 public class GenericMethodTest {    //演示如何使用泛型方法打印不同字符串的元素
     2     // 泛型方法 printArray
     3     public static <E> void printArray(E[] inputArray) {
     4         // 输出数组元素
     5         for (E element : inputArray) {
     6             System.out.printf("%s ", element);
     7         }
     8         System.out.println();
     9     }
    10 
    11     public static void main(String args[]) {
    12         // 创建不同类型数组: Integer, Double 和 Character
    13         Integer[] intArray = { 1, 2, 3, 4, 5 };
    14         Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
    15         Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
    16 
    17         System.out.println("整型数组元素为:");
    18         printArray(intArray); // 传递一个整型数组
    19 
    20         System.out.println("
    双精度型数组元素为:");
    21         printArray(doubleArray); // 传递一个双精度型数组
    22 
    23         System.out.println("
    字符型数组元素为:");
    24         printArray(charArray); // 传递一个字符型数组
    25     }
    26 }

    输出结果:

    1 整型数组元素为:
    2 1 2 3 4 5 
    3 
    4 双精度型数组元素为:
    5 1.1 2.2 3.3 4.4 
    6 
    7 字符型数组元素为:
    8 H E L L O 

    (5)类型通配符?

    ① 类型通配符 通常使用 ? 代替具体的类型参数。例如 List<?> 在逻辑上是 List<String>,List<Integer> 等所有List<具体类型实参>的父类。

     1 import java.util.*;
     2  
     3 public class GenericTest {
     4      
     5     public static void main(String[] args) {
     6         List<String> name = new ArrayList<String>();
     7         List<Integer> age = new ArrayList<Integer>();
     8         List<Number> number = new ArrayList<Number>();
     9         
    10         name.add("yadiel");
    11         age.add(18);
    12         number.add(999);
    13  
    14         getData(name);
    15         getData(age);
    16         getData(number);
    17        
    18    }
    19  
    20    public static void getData(List<?> data) {
    21       System.out.println("data :" + data.get(0));
    22    }
    23 }

    输出结果:

    1 data :yadiel
    2 data :18
    3 data :999

    ② 类型通配符的上限和下限

    上限:<? extends T> 表示该通配符所代表的类型是 T类型 或者 T类型的子类。

    下限:<? super T>  表示该通配符所代表的类型是 T类型 或者 T类型的父类。

     1 import java.util.*;
     2  
     3 public class GenericTest {
     4      
     5     public static void main(String[] args) {
     6         List<String> name = new ArrayList<String>();
     7         List<Integer> age = new ArrayList<Integer>();
     8         List<Number> number = new ArrayList<Number>();
     9         
    10         name.add("yadiel");
    11         age.add(18);
    12         number.add(999);
    13  
    14         //getUperNumber(name);//String类型表示Number类型的子类,报错
    15         getUperNumber(age);   //输出18
    16         getUperNumber(number);//输出999
    17        
    18    }
    19    
    20    public static void getUperNumber(List<? extends Number> data) {
    21           System.out.println("data :" + data.get(0));
    22        }
    23 }

    设计泛型方法,返回三个可比较对象的最大值。

     1 public class MaximumTest
     2 {
     3    // 比较三个值并返回最大值
     4    public static <T extends Comparable<T>> T maximum(T x, T y, T z)
     5    {                     
     6       T max = x; // 假设x是初始最大值
     7       if ( y.compareTo( max ) > 0 ){
     8          max = y; //y 更大
     9       }
    10       if ( z.compareTo( max ) > 0 ){
    11          max = z; // 现在 z 更大           
    12       }
    13       return max; // 返回最大对象
    14    }
    15    public static void main( String args[] )
    16    {
    17       System.out.printf( "%d, %d 和 %d 中最大的数为 %d
    
    ",
    18                    3, 4, 5, maximum( 3, 4, 5 ) );
    19  
    20       System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f
    
    ",
    21                    6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
    22  
    23       System.out.printf( "%s, %s 和 %s 中最大的数为 %s
    ","pear",
    24          "apple", "orange", maximum( "pear", "apple", "orange" ) );
    25    }
    26 }

    输出结果:

    1 3, 4 和 5 中最大的数为 5
    2 
    3 6.6, 8.8 和 7.7 中最大的数为 8.8
    4 
    5 pear, apple 和 orange 中最大的数为 pear

    4. 注意事项

    ① 不能用基本类型来定义泛型,如 int、float。

    1 List<int> list = new ArrayList<int>(); //不能用 int 这样的基本类型定义泛型

    因为集合中只能存放引用类型的数据,即使你存入基本类型,Java还是会通过自动拆箱和自动装箱机制将其转换为引用类型。

    ② 如果使用 ? 接收泛型对象时,则不能设置被泛型指定的内容。

    1 List<?> list = new ArrayList<>();
    2 list.add("aa");  //错误,无法设置

    ③ 泛型方法的定义与其所在的类是否是 泛型类 是没有任何关系的,所在的类可以是泛型类,也可以不是泛型类。

    ④ 泛型类没有继承关系,即 String 为 Object 类的子类,则 List<String> 是 List<Object> 的子类这句话是错误的。

    正确:List<String>==List<Object>。 原因:泛型只是规定了List的元素类型,如果不符合,会在编译阶段报错。在运行阶段,无论List的元素是什么类型,List的类型都属于List。

    假设上面那句话是正确的,那么由于泛型的产生机制就是放什么类型的数据进去,取出来的就是什么类型,而不用进行类型转换。
    这里把 String 类型的数据放入Object 类的泛型集合中,那么取出来的应该就是 String 类的数据,而实际上取出来的是 Object 类的数据,这与泛型的产生机制相违背,故不成立!

    参考:

    https://www.cnblogs.com/ysocean/p/6826525.html

    https://www.runoob.com/java/java-generics.html

  • 相关阅读:
    Linux内核网络协议栈优化总纲
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 链表数据求和操作
  • 原文地址:https://www.cnblogs.com/yadiel-cc/p/11141952.html
Copyright © 2011-2022 走看看