Java中的泛型/范型

维基百科中关于Java泛型的描述

Java 泛型的参数只可以代表类,不能代表个别对象。由于Java泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型,而且无法直接使用基本值类型作为泛型类型参数。Java编译程序在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。

由于运行时会消除泛型的对象实例类型信息等缺陷经常被人诟病,Java及JVM的开发方面也尝试解决这个问题,例如Java通过在生成字节码时添加类型推导辅助信息,从而可以通过反射接口获得部分泛型信息。通过改进泛型在JVM的实现,使其支持基本值类型泛型和直接获得泛型信息等。

Java允许对个别泛型的类型参数进行约束,包括以下两种形式(假设T是泛型的类型参数,C是一般类、泛类,或是泛型的类型参数):

  • T实现接口I
  • TC,或继承自C

泛型Since jdk1.5

摘自《Java代码与架构完美优化》
泛型的本质是参数化类型,所操作的数据类型被指定为一个参数。
Java中的泛型在编译器中实现,而不是在虚拟机中实现的,虚拟机对于泛型是一无所知的。因此,编译器一定要把泛型类修改为普通类,才能够在虚拟机中运行。Java中把这种技术称为擦除,泛型代码经过擦除后变成原生类型。

源代码>>>泛型>>>编译器>>>字节码(*.class文件)>>>JVM(类装载器,字节码校验器,解释器)>>>操作系统平台

使用泛型的优势

类型安全以及不需要进行类型转换

类型安全性:我们只能在泛型中只保存一种类型的对象。 它不允许存储其他对象。因此,也不再需要进行类型转换。下面给出使用泛型和不使用泛型的区别。

List list = new ArrayList();  
list.add("Hello Generics");  
String s = (String) list.get(0);  //需要类型转换
List list = new ArrayList();  
list.add("Hello Generics");  
String s = list.get(0);   //不需要类型转换

类型检查从运行时挪到编译时

编译时检查:在编译时检查,所以运行时不会出现问题。 良好的编程策略表明,在编译时处理这个问题要比运行时好得多。

使用泛型的注意事项

  • 在static方法中不可以使用泛型,泛型变量也不可以使用static关键字来修饰
  • 泛型常用符号的含义-T(Type)、K(Key)、V(Value)、E(Element),N(Number)尽管其它形式也可以作为变量的符号,但是我们习惯使用这几种符号。
  • 泛型只适用于对象,基本类型不适用,但是可以使用基本类型的包装类来实现,比如:
List intList = new ArrayList();
intList.add(1);  //自动将1转换成Integer
intList.add(2);
  • 开发人员在使用泛型的时候,很容易根据自己的直觉而犯一些错误。比如一个方法如果接收List作为形式参数,那么如果尝试将一个List的对象作为实际参数传进去,却发现无法通过编译。虽然从直觉上来说,Object是String的父类,这种类型转换应该是合理的。但是实际上这会产生隐含的类型转换问题,因此编译器直接就禁止这样的行为。http://www.infoq.com/cn/articles/cf-java-generics

    泛型使用举例

    创建参数化类型-泛型类

    //simple
    class MyGen {
        T obj;
    
        void add(T obj) {
            this.obj = obj;
        }
    
        T get() {
            return obj;
        }
    }
    
    public class Generics {
    
        public static void main(String args[]) {
            MyGen m = new MyGen();
            m.add(2);
            //m.add("test");   //Compile time error
            System.out.println(m.get());
        }
    }
    
    //complex from agile java
    import java.util.*;
    public class MultiHashMap  {
       private Map> map = new HashMap>();
    
       public static ,V> List
             sortedKeys(MultiHashMap map) {
          List keys = new ArrayList();
          keys.addAll(map.keys());
          Collections.sort(keys);
          return keys;
       }
    
       public Set keys() {
          return map.keySet();
       }
    
       public int size() {
          return map.size();
       }
    
       public void put(K key, V value) {
          List values = map.get(key);
          if (values == null) {
             values = new ArrayList();
             map.put(key, values);
          }
          values.add(value);
       }
    
       public List get(K key) {
          return map.get(key);
       }
    
       protected Set>> entrySet() {
          return map.entrySet();
       }
    
       public interface Filter {
          boolean apply(T item);
       }
    
       public static  void filter(final MultiHashMap target,
                                       final MultiHashMap source,
                                       final Filter filter) {
          for (K key : source.keys()) {
             final List values = source.get(key);
             for (V value : values)
                if (filter.apply(value))
                   target.put(key, value);
          }
       }
    }
    

    泛型方法

    public class Generics {
    
        public static < E > void printArray(E[] elements) {  
            for ( E element : elements){          
                System.out.println(element );  
             }  
             System.out.println();  
        }  
        public static void main( String args[] ) {  
            Integer[] intArray = {6, 66, 666};  
            String[] stringArray = { "6","66","666" };  
      
            System.out.println( "Printing Integer Array" );  
            printArray( intArray  );   
      
           System.out.println( "Printing String Array" );  
            printArray( stringArray );   
        }   
    }
    

    上限

    每个类型参数都有一个缺省为Object的上限,你可以将类型参数限制为不同的上限。这里需要使用extends关键字来指定某个类型参数的上限。

    //from agile java
    import java.util.*;
    public class EventMap
       extends MultiHashMap {
       public List getPastEvents() {
          List events = new ArrayList();
          for (Map.Entry> entry: entrySet()) {
             K date = entry.getKey();
             if (hasPassed(date))
                events.addAll(entry.getValue());
          }
          return events;
       }
    
       private boolean hasPassed(K date) {
          Calendar when = new GregorianCalendar();
          when.setTime(date);
          Calendar today = new GregorianCalendar();
          if (when.get(Calendar.YEAR) != today.get(Calendar.YEAR))
             return when.get(Calendar.YEAR) < today.get(Calendar.YEAR);
          return when.get(Calendar.DAY_OF_YEAR) <
             today.get(Calendar.DAY_OF_YEAR);
       }
    }
    

    通配符wildcard

    java允许使用一个通配符?来表示任意可能的类型,此外你可以使用extends子句限制通配符的上限。

    import java.util.ArrayList;
    import java.util.List;
    
    abstract class Shape {
        abstract void draw();
    }
    
    class Rectangle extends Shape {
        void draw() {
            System.out.println("drawing rectangle");
        }
    }
    
    class Circle extends Shape {
        void draw() {
            System.out.println("drawing circle");
        }
    }
    
    public class Generics {
        // creating a method that accepts only child class of Shape
        public static void drawShapes(List lists) {
            for (Shape s : lists) {
                s.draw(); // calling method of Shape class by child class instance
            }
        }
    
        public static void main(String args[]) {
            List list1 = new ArrayList();
            list1.add(new Rectangle());
    
            List list2 = new ArrayList();
            list2.add(new Circle());
            list2.add(new Circle());
    
            drawShapes(list1);
            drawShapes(list2);
        }
    }
    
    

    demo来源

    • https://www.javatpoint.com/generics-in-java
    • agile java

    你可能感兴趣的:(Java中的泛型/范型)