什么是泛型
《Java编程思想》对 泛型的介绍:一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。
因此,泛型:就是适用于多种类型。从代码上讲,就是对类型实现了参数化。
语法
class 泛型类名称 < 类型形参列表 > {// 这里可以使用类型参数}class ClassName < T1 , T2 , ..., Tn > {}
例如:我们要实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值
  
   - 
    
     
    
    
     
      class MyArray2<T>{
     
    
- 
    
     
    
    
         
      public T[] 
      array=(T[])
      new 
      Object[
      10];
     
    
- 
    
     
    
    
         
      public T getValue(
      int pos){
     
    
- 
    
     
    
    
             
      return  
      array[pos];
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      public 
      void setValue(
      int pos, T val){
     
    
- 
    
     
    
    
             
      array[pos]=val;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      public 
      class Test2 {
     
    
- 
    
     
    
    
         
      public 
      static 
      void main(
      String[] args) {
     
    
- 
    
     
    
    
             
      //<>里面指定了类型,说明此时这个类里面只能放这个数据类型的数据
     
    
- 
    
     
    
    
             
      //并且<>中是引用类型
     
    
- 
    
     
    
    
     
              MyArray2<
      String> myArray2=
      new MyArray2<
      String>();
     
    
- 
    
     
    
    
     
              myArray2.setValue(
      0,
      "hello");
     
    
- 
    
     
    
    
     
              myArray2.setValue(
      1,
      "world");
     
    
- 
    
     
    
    
     
              System.out.println(myArray2.getValue(
      0));
     
    
- 
    
     
    
    
     
              System.out.println(myArray2.getValue(
      1));
     
    
- 
    
     
    
    
     
              MyArray2<
      Integer> myArray3=
      new MyArray2<
      Integer>();
     
    
- 
    
     
    
    
     
              myArray3.setValue(
      2,
      100);
     
    
- 
    
     
    
    
     
              System.out.println(myArray3.getValue(
      2));
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
1.<>当中指定类型后,编译器会根据你指定的类型参数来进行类型的检查
2.取元素时不用进行强转
T[]array=new T[10]//error是错误的
泛型的使用
语法
泛型类 < 类型实参 > 变量名 ; // 定义一个泛型类引用new 泛型类 < 类型实参 > ( 构造方法实参 ); // 实例化一个泛型类对象
例如上面代码:MyArray2<String> myArray2=new MyArray2<Stirng>();//后面<>中的类型可写可不写,编译器可以根据上下文推导出类型实参。
泛型如何编译
擦除机制

我们通过字节码发现在编译时,所有的T都变成了Object.
所以擦除机制就是在 编译的时候 把泛型T 擦除成了Object.运行期间没有这个泛型这个概念。
思考:既然T都被擦除成了Object了,为什么不能实例化泛型类型的数组?
T[]array=new T[10]//等价于Object[]array=new Object[10]; 错误
  
   - 
    
     
    
    
     
      class MyArray2<T>{
     
    
- 
    
     
    
    
         
      public T[] 
      array=(T[])
      new 
      Object[
      10];
     
    
- 
    
     
    
    
         
      public T getValue(
      int pos){
     
    
- 
    
     
    
    
             
      return  
      array[pos];
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      public 
      void setValue(
      int pos, T val){
     
    
- 
    
     
    
    
             
      array[pos]=val;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      public T[] getArray(){
     
    
- 
    
     
    
    
             
      return 
      array;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      public 
      class Test2 {
     
    
- 
    
     
    
    
         
      public 
      static 
      void main(
      String[] args) {
     
    
- 
    
     
    
    
     
             MyArray2 myArray2=
      new MyArray2();
     
    
- 
    
     
    
    
     
              myArray2.setValue(
      0,
      10);
     
    
- 
    
     
    
    
     
              myArray2.setValue(
      1,
      "hello");
     
    
- 
    
     
    
    
             
      Integer[] integers= (
      Integer[]) myArray2.getArray();
     
    
- 
    
     
    
    
     
              System.out.println(Arrays.toString(integers));
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    

因为返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,运行的时候,直接转给Intefer类型的数组,编译器认为是不安全的。
正确的创建方法(了解即可)
  
   - 
    
     
    
    
     
      class MyArray3<T>{
     
    
- 
    
     
    
    
     
          T[] 
      array;
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 通过放射创建,指定类型的数组
     
    
- 
    
     
    
    
     
       * @param clazz
     
    
- 
    
     
    
    
     
       * @param capacity
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      public MyArray3(
      Class<T>clazz,int capacity){
     
    
- 
    
     
    
    
             
      array=(T[]) 
      Array.newInstance(clazz,capacity);
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      public T getPos(
      int pos){
     
    
- 
    
     
    
    
             
      return 
      array[pos];
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      public 
      void setArray(
      int pos,T val){
     
    
- 
    
     
    
    
             
      array[pos]=val;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      public T[] getArray(){
     
    
- 
    
     
    
    
             
      return 
      array;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      public 
      class Test3 {
     
    
- 
    
     
    
    
         
      public 
      static 
      void main(
      String[] args) {
     
    
- 
    
     
    
    
     
              MyArray3<
      Integer> myArray3=
      new MyArray3<>(
      Integer.
      class,
      10);
     
    
- 
    
     
    
    
     
              myArray3.setArray(
      0,
      10);
     
    
- 
    
     
    
    
     
              myArray3.setArray(
      1,
      15);
     
    
- 
    
     
    
    
             
      Integer[] integers=myArray3.getArray();
     
    
- 
    
     
    
    
     
              System.out.println(Arrays.toString(integers));
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
泛型的边界
有上边界,无下边界。
语法
class 泛型类名称 < 类型形参 extends 类型边界 > {...}
例如:
public class MyArray < E extends Number > {...}
这里的extends不是继承的意思,表示边界是Number及其子类
应用:实现一个泛型类,找出数组最大值
因为泛型类T不是基本类型,不能简单的进行大于小于这样的比较,T是引用类型要使用比较器,也就是将T擦除成Comparable接口。
  
   - 
    
     
    
    
     
      class Alg<T extends Comparable<T>>{
      //将T擦成Comparable接口
     
    
- 
    
     
    
    
     
          public 
      T findMax(
      T[] array){
     
    
- 
    
     
    
    
             
      T max=array[
      0];
     
    
- 
    
     
    
    
             
      for (int i = 
      0; i < array.length; i++) {
     
    
- 
    
     
    
    
                 
      if(max.compareTo(array[i])<
      0){
     
    
- 
    
     
    
    
     
                      max=array[i];
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
             
      return max;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
泛型方法
1.成员方法:方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }
  
   - 
    
     
    
    
     
      class Alg{
     
    
- 
    
     
    
    
         
      public<T 
      extends Comparable<T>> T findMax(T[] 
      array){
     
    
- 
    
     
    
    
     
              T max=
      array[
      0];
     
    
- 
    
     
    
    
             
      for (
      int i = 
      0; i < 
      array.length; i++) {
     
    
- 
    
     
    
    
                 
      if(max.compareTo(
      array[i])<
      0){
     
    
- 
    
     
    
    
     
                      max=
      array[i];
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
             
      return max;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      public 
      class Test {
     
    
- 
    
     
    
    
         
      public 
      static 
      void main(
      String[] args) {
     
    
- 
    
     
    
    
     
              Alg alg=
      new Alg();
     
    
- 
    
     
    
    
             
      Integer[] 
      array=
      new 
      Integer[]{
      1,
      23,
      4,
      56,
      7,
      8};
     
    
- 
    
     
    
    
     
              System.out.println(alg.findMax(
      array));
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
56
2.静态方法,静态的泛型方法 需要在static后用<>声明泛型类型参数
  
   - 
    
     
    
    
     
      class Alg2{
     
    
- 
    
     
    
    
             
      //静态方法不依赖于对象的调用
     
    
- 
    
     
    
    
         
      public 
      static<T 
      extends Comparable<T>> T findMax(T[] 
      array){
     
    
- 
    
     
    
    
     
              T max=
      array[
      0];
     
    
- 
    
     
    
    
             
      for (
      int i = 
      0; i < 
      array.length; i++) {
     
    
- 
    
     
    
    
                 
      if(max.compareTo(
      array[i])<
      0){
     
    
- 
    
     
    
    
     
                      max=
      array[i];
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
             
      return max;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
通配符
     
      - 
       
        
       
       
        
         class 
         Message<T>{
        
       
- 
       
        
       
       
            
         private T message;
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
            
         public T 
         getMessage(
         ) {
        
       
- 
       
        
       
       
                
         return message;
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
            
         public 
         void 
         setMessage(
         T message) {
        
       
- 
       
        
       
       
                
         this.
         message = message;
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
        
         }
        
       
- 
       
        
       
       
        
         public 
         class 
         Test2 {
        
       
- 
       
        
       
       
            
         public 
         static 
         void 
         func(
         Message<?> message){
        
       
- 
       
        
       
       
                
         //message.setMessage(100);//不能修改,因为不知道参数是什么类型的
        
       
- 
       
        
       
       
                
         System.
         out.
         println(message.
         getMessage());
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
            
         public 
         static 
         void 
         main(
         String[] args) {
        
       
- 
       
        
       
       
                
         Message<
         String> message=
         new 
         Message<>();
        
       
- 
       
        
       
       
                
         String s=
         "中国世界第一";
        
       
- 
       
        
       
       
        
                 message.
         setMessage(s);
        
       
- 
       
        
       
       
                
         func(message);
        
       
- 
       
        
       
       
                
         Message<
         Integer> message2=
         new 
         Message<>();
        
       
- 
       
        
       
       
                
         Integer a=
         10;
        
       
- 
       
        
       
       
        
                 message2.
         setMessage(a);
        
       
- 
       
        
       
       
                
         func(message2);
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
        
         }
        
       
通过使用通配符,既可以传String也可以传Integer,扩大了参数的范围
通配符的上界(常用于获取元素)
语法
<? extends 上界 ><? extends Number > // 可以传入的实参类型是 Number 或者 Number 的子类
     
      - 
       
        
       
       
        
         class Food{
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
        
         }
        
       
- 
       
        
       
       
        
         class Fruit extends Food{
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
        
         }
        
       
- 
       
        
       
       
        
         class Apple extends Fruit{
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
        
         }
        
       
- 
       
        
       
       
        
         class Banana extends Fruit{
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
        
         }
        
       
- 
       
        
       
       
        
         class Alg2<T>{
        
       
- 
       
        
       
       
            
         private 
         T 
         val;
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
        
             public 
         T getVal() {
        
       
- 
       
        
       
       
                
         return 
         val;
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
         
        
       
- 
       
        
       
       
        
             public void setVal(
         T 
         val) {
        
       
- 
       
        
       
       
                
         this.
         val = 
         val;
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
        
         }
        
       
- 
       
        
       
       
        
         public 
         class Test3 {
        
       
- 
       
        
       
       
            
         /**
        
       
- 
       
        
       
       
        
          * ?通配符extends上限是Fruit及其子类
        
       
- 
       
        
       
       
        
          * @param temp
        
       
- 
       
        
       
       
        
          */
        
       
- 
       
        
       
       
        
             public static void func(
         Alg2<? 
         extends 
         Fruit> temp){
        
       
- 
       
        
       
       
                
         /*
        
       
- 
       
        
       
       
        
          Banana banana=temp.getVal();
        
       
- 
       
        
       
       
        
          Apple apple=temp.getVal();
        
       
- 
       
        
       
       
        
          不能进行修改,因为temp接收的是Fruit及其子类,无法确定参数是什么类型
        
       
- 
       
        
       
       
        
          */
        
       
- 
       
        
       
       
                
         Fruit fruit= temp.getVal();
         //temp放的是Fruit及其子类,所以可以用Fruit进行接收
        
       
- 
       
        
       
       
                
         System.out.println(temp.getVal());
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
        
             public static void main(
         String[] args) {
        
       
- 
       
        
       
       
                
         Alg2<
         Banana> alg2=
         new 
         Alg2<>();
        
       
- 
       
        
       
       
        
                 alg2.setVal(
         new 
         Banana());
        
       
- 
       
        
       
       
        
                 func(alg2);
        
       
- 
       
        
       
       
                
         Alg2<
         Apple> alg3=
         new 
         Alg2<>();
        
       
- 
       
        
       
       
        
                 alg3.setVal(
         new 
         Apple());
        
       
- 
       
        
       
       
        
                 func(alg3);
        
       
- 
       
        
       
       
        
             }
        
       
- 
       
        
       
       
        
         }
        
       
通配符的下限(常用于设置元素)
语法
<? super 下界 ><? super Integer > // 代表 可以传入的实参的类型是 Integer 或者 Integer 的父类类型
应用:
  
   - 
    
     
    
    
     
      class Food{
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      class Fruit extends Food {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      class Apple extends Fruit {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      class Banana extends Fruit {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      class Alg4<T>{
     
    
- 
    
     
    
    
         
      private 
      T 
      val;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
          public 
      T getVal() {
     
    
- 
    
     
    
    
             
      return 
      val;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
          public void setVal(
      T 
      val) {
     
    
- 
    
     
    
    
             
      this.
      val = 
      val;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      public 
      class Test4 {
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 通配符?下限super是Fruit及其父类
     
    
- 
    
     
    
    
     
       * @param temp
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
     
          public static void func(
      Alg4<? 
      super 
      Fruit> temp){
     
    
- 
    
     
    
    
             
      /**
     
    
- 
    
     
    
    
     
       * 因为最小的下限是Fruit,所以可以使用setVal进行修改
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
     
              temp.setVal(
      new 
      Banana());
      //向上转型
     
    
- 
    
     
    
    
     
              temp.setVal(
      new 
      Apple());
      //向上转型
     
    
- 
    
     
    
    
             
      /**
     
    
- 
    
     
    
    
     
       * temp可能是Fruit或者他的父类,无法用子类(Fruit)接收
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
             
      //Fruit fruit=temp.getVal();
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
             
      System.out.println(temp.getVal());
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
          public static void main(
      String[] args) {
     
    
- 
    
     
    
    
             
      Alg4<
      Fruit> alg4=
      new 
      Alg4<>();
     
    
- 
    
     
    
    
     
              alg4.setVal(
      new 
      Fruit());
     
    
- 
    
     
    
    
             
      Alg4<
      Food> alg41=
      new 
      Alg4<>();
     
    
- 
    
     
    
    
     
              alg41.setVal(
      new 
      Food());
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
(自动)装箱
  
   - 
    
     
    
    
     
      public 
      static 
      void main(
      String[] args) {
     
    
- 
    
     
    
    
             
      int a=
      10;
     
    
- 
    
     
    
    
             
      Integer integer1=a;
      //自动装箱
     
    
- 
    
     
    
    
             
      Integer integer2=
      new 
      Integer(a);
      //显示装箱
     
    
- 
    
     
    
    
             
      Integer integer3=
      Integer.valueOf(a);
      //显示装箱
     
    
- 
    
     
    
    
     
          }
     
    

通过字节码我们发现,装箱的底层是采用Integer.valueOf
(自动)拆箱
  
   - 
    
     
    
    
     
      public 
      static 
      void main(
      String[] args) {
     
    
- 
    
     
    
    
             
      Integer 
      integer=
      10;
     
    
- 
    
     
    
    
             
      int val=
      integer;
      //自动拆箱
     
    
- 
    
     
    
    
     
              System.out.println(val);
     
    
- 
    
     
    
    
             
      int val2=
      integer.intValue();
      //显示拆箱
     
    
- 
    
     
    
    
             
      double val3=
      integer.doubleValue();
      //显示拆箱
     
    
- 
    
     
    
    
     
          }
     
    
面试题:输出什么
  
   - 
    
     
    
    
     
      public 
      static 
      void main(
      String[] args) {
     
    
- 
    
     
    
    
             
      Integer a=
      127;
     
    
- 
    
     
    
    
             
      Integer b=
      127;
     
    
- 
    
     
    
    
     
              System.out.println(a==b);
     
    
- 
    
     
    
    
             
      Integer c=
      128;
     
    
- 
    
     
    
    
             
      Integer d=
      128;
     
    
- 
    
     
    
    
     
              System.out.println(c==d);
     
    
- 
    
     
    
    
     
          }
     
    
答案:
true
false
why?

装箱的底层是valueOf,查看他的源码发现在【-127,128】范围内有一个数组,不在这个范围内需要new 对象,所以127在数组内相同,128需要new 对象,地址不同
转载:https://blog.csdn.net/weixin_61427900/article/details/125505139
 
					