美文网首页Java
Java中的泛型/范型

Java中的泛型/范型

作者: Ricky_Zuo | 来源:发表于2018-01-06 22:13 被阅读14次

维基百科中关于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<String> list = new ArrayList<String>();  
list.add("Hello Generics");  
String s = list.get(0);   //不需要类型转换

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

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

使用泛型的注意事项

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

泛型使用举例

创建参数化类型-泛型类

//simple
class MyGen<T> {
    T obj;

    void add(T obj) {
        this.obj = obj;
    }

    T get() {
        return obj;
    }
}

public class Generics {

    public static void main(String args[]) {
        MyGen<Integer> m = new MyGen<Integer>();
        m.add(2);
        //m.add("test");   //Compile time error
        System.out.println(m.get());
    }
}

//complex from agile java
import java.util.*;
public class MultiHashMap <K,V> {
   private Map<K, List<V>> map = new HashMap<K, List<V>>();

   public static <K extends Comparable<K>,V> List<K>
         sortedKeys(MultiHashMap<K, V> map) {
      List<K> keys = new ArrayList<K>();
      keys.addAll(map.keys());
      Collections.sort(keys);
      return keys;
   }

   public Set<K> keys() {
      return map.keySet();
   }

   public int size() {
      return map.size();
   }

   public void put(K key, V value) {
      List<V> values = map.get(key);
      if (values == null) {
         values = new ArrayList<V>();
         map.put(key, values);
      }
      values.add(value);
   }

   public List<V> get(K key) {
      return map.get(key);
   }

   protected Set<Map.Entry<K, List<V>>> entrySet() {
      return map.entrySet();
   }

   public interface Filter<T> {
      boolean apply(T item);
   }

   public static <K,V> void filter(final MultiHashMap<K, ? super V> target,
                                   final MultiHashMap<K, V> source,
                                   final Filter<? super V> filter) {
      for (K key : source.keys()) {
         final List<V> 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<K extends Date,V>
   extends MultiHashMap<K,V> {
   public List<V> getPastEvents() {
      List<V> events = new ArrayList<V>();
      for (Map.Entry<K,List<V>> 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<? extends Shape> lists) {
        for (Shape s : lists) {
            s.draw(); // calling method of Shape class by child class instance
        }
    }

    public static void main(String args[]) {
        List<Rectangle> list1 = new ArrayList<Rectangle>();
        list1.add(new Rectangle());

        List<Circle> list2 = new ArrayList<Circle>();
        list2.add(new Circle());
        list2.add(new Circle());

        drawShapes(list1);
        drawShapes(list2);
    }
}

demo来源

相关文章

  • 泛型

    java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一Java泛型深入理解加泛型面试数组的协变性与范型的不可变性

  • Java中的泛型/范型

    维基百科中关于Java泛型的描述 Java 泛型的参数只可以代表类,不能代表个别对象。由于Java泛型的类型参数之...

  • Java泛型教程

    Java泛型教程导航 Java 泛型概述 Java泛型环境设置 Java泛型通用类 Java泛型类型参数命名约定 ...

  • Java泛型

    参考:Java知识点总结(Java泛型) 自定义泛型类 自定义泛型接口 非泛型类中定义泛型方法 继承泛型类 通配符...

  • JAVA泛型的理解

    泛型大家都接触的不少,但是由于Java历史原因,Java中泛型一直被称为伪泛型,因此对Java中的泛型,有很多不注...

  • Kotlin 泛型

    Kotlin 支持泛型, 语法和 Java 类似。例如,泛型类: 泛型函数: 类型变异 Java 的泛型中,最难理...

  • Android 开发也要掌握的Java知识 - Java泛型

    如果需要看泛型擦除Java泛型擦除 1.Java泛型有什么用?为啥要使用泛型? Java中数组的类型是定义的时候就...

  • 15、泛型常用特点

    泛型常用特点 泛型是Java SE 1.5之后的特性,《Java 核心技术》中对泛型的定义是: “泛型” 意味着编...

  • Java 泛型

    什么是泛型 Java 1.5 开始引进的参数性类型的,是在编译器进行类型擦除的类型转化,所以Java的泛型是伪范型...

  • java 泛型解析

    Java 泛型 1、泛型的精髓是什么 2、泛型方法如何使用 概述: 泛型在java中具有重要地位,在面向对象编程模...

网友评论

    本文标题:Java中的泛型/范型

    本文链接:https://www.haomeiwen.com/subject/xcgynxtx.html