• java 泛型


    java - 泛型
    泛型说明

    泛型(generics)是JDK5 中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

    泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。这种参数类型可以用在类,接口和方法中,分别被称为泛型类泛型接口泛型方法

    为什么要使用泛型

    泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率

    安全性

    //集合未使用泛型
    List list = new ArrayList();
    
    list.add("smile");
    list.add(30);//编译正常
    
    //集合使用泛型
    List<String> newList = new ArrayList();
    
    newList.add("smile");
    newList.add(30);//编译不正常
    

    使用泛型后,定义好的集合newList在编译的时候,add(30)就会编译失败。

    相当于告诉编译器每个集合接收的对象类型是什么,编译器在编译期就会做类型检查,告知是否插入了错误类型的对象,使程序更加安全,增强了程序的健壮性。

    消除转换

    //未使用泛型
    List list = new ArrayList();
    
    list.add("smile");
    String name = (String) list.get(0);
    
    //使用泛型
    List<String> newList = new ArrayList();
    
    newList.add("smile");
    String newName = newList.get(0);
    

    使用泛型的一个附带好处是,消除代码中许多强制类型转换,这使得代码更加可读,并减少出错机会

    提升性能

    在非泛型编程中,将简单的类型作为Object传递的时看会引起Boxing(装箱)和Unboxing(拆箱)操作,这两个过程都是具有很大开销的。引入泛型后,就不必进行Boxing和Unboxing操作了,所以运行效率相对较高,特别是在对集合操作非常频繁的系统中,这个特点带来的性能提升更加明显。

    泛型变量固定了类型,使用的时候就已经知道是值类型还是引用类型,避免了不必要的装箱,拆箱操作。

    重用性

    提升了代码的重用性

    使用泛型

    泛型有三种使用方法

    • 泛型类

      将泛型定义在类上

      public class className <T> {}
      

      泛型类型必须是引用类型(非基本数据类型)

      List<int> list = new ArrayList<>();//编译异常
      

      使用泛型的数组,不能初始化

      class GenericTest<T> {
          private T[] values;
      
          public void setValue(T value) {        
              this.values = new T[3];//编译异常
          }
      }
      
      //由于初始化的数组,需要开辟内存空间,在不清楚具体类型的时候,编译器无法开辟驻准确的空间大小
      

      静态方法中不能使用类的泛型

      class GenericTest<T> {
          private T value;
          
          public static void test(T value) {//编译异常
              System.out.println(value);
          }
      }
      
      //由于静态方法独属于类,而类的泛型属于声明后的对象
      

      静态属性中不能使用类的泛型

      class GenericTest<T> {
          private static T value;//编译异常
          
          public  GenericTest(T value) {
              System.out.println(value);
          }
      }
      
      //由于静态属性独属于类,而类的泛型属于声明后的对象
      

      定义泛型类,在类名后添加一对尖括号,并在尖括号中填写类型参数,参数可以有多个,多个参数使用,进行分隔

      public class className<T,E,V> {}
      

      通常类型参数我们都使用大写的单个字母表示:

      T: 任意类型type

      E:集合中元素类型 element

      K:key-value形式 key

      V:key-value形式 value

      泛型使用

      public class Generic{
          public static void main(String[] args) {
              GenericTest<String> generic = new GenericTest<>("smile");
      
              System.out.println(generic.getValue());
          }
      }
      
      //定义泛型
      class GenericTest<T> {
          private T value;
          
          public GenericTest(T value) {
              this.value = value;
          }
      
          public T getValue() {
              return value;
          }
      
          public void setValue(T value) {
              this.value = value;
          }
      }
      
    • 泛型接口

      将泛型定义在接口上

      public interface interfaceName <T> {}
      

      泛型接口使用

      1. 继承使用

        interface GenericInterfaceA <T> {
            T run(T value);
        }
        
        //不指定泛型类,默认使用Object
        interface GenericInterfaceD extends GenericInterfaceA {
        
        }
        
        //继续使用父接口的泛型,不指定具体的泛型
        interface GenericInterfaceB<T> extends GenericInterfaceA<T> {
        }
        
        //指定具体的泛型类型
        interface GenericInterfaceC extends GenericInterfaceA<String> {
            
        }
        
      2. 实现使用

        //接口实现过程中,不指定具体的泛型类,默认使用Object
        class GenericClassA implements GenericInterfaceA{
            @Override
            public Object run(Object value) {
                return null;
            }
        }
        
        //接口实现过程中,指定具体的泛型类
        class GenericClassC implements GenericInterfaceA<String>{
            @Override
            public String run(String value) {
                return null;
            }
        }
        
        //接口继承的时候,已经指定接口继承泛型,不需要额外指定
        class GenericClassD implements GenericInterfaceC{
            @Override
            public String run(String value) {
                return null;
            }
        }
        
    • 泛型方法

      将泛型定义在方法上

      public <T> returnType functionName(T variableName) {}
      

      泛型方法可以是普通方法,静态方法,或构造方法

      class GenericClassA implements GenericInterfaceA{
          @Override
          public Object run(Object value) {
              return null;
          }
      
          //构造方法
          public <T> GenericClassA(T name){
              System.out.println(name);
          }
      
          //普通方法
          public <T> void testA(T name) {
              System.out.println(name);
          }
      
          //静态方法
          public static <T> void testB(T name) {
              System.out.println(name);
          }
      }
      

      是否拥有泛型方法,与其所在的类是否是泛型没有关系

      使用泛型方法的时候,通常不必指明类型参数,因为编译器会为我们找出具体的类型。这称为类型参数推断(type argument inference)。类型推断只对赋值操作有效,其他时候并不起作用

      public class Generic{
          public static void main(String[] args) {
              GenericFunction genericFunction = new GenericFunction();
            	//会自动进行类型推断
              genericFunction.run("smile");
          }
      }
      
      class GenericFunction {
          public <T> void run(T name) {
              System.out.println(name);
          }
      }
      
  • 相关阅读:
    品味性能之道<六>:图形化SQL分析工具
    品味性能之道<五>:SQL分析工具
    品味性能之道<四>:管理重于技术
    品味性能之道<三>:方法论
    品味性能之道<二>:性能工程师可以具备的专业素养
    品味性能之道<一>:性能测试思维与误区
    网络协议学习笔记
    Java内存泄露监控工具:JVM监控工具介绍
    Loadrunner脚本回放无法准确定位欲删除元素
    C++ 虚函数
  • 原文地址:https://www.cnblogs.com/ywjcqq/p/16289138.html
Copyright © 2020-2023  润新知