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);
        }
    }
    
posted @   易文杰  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示