再看泛型

来源:互联网 发布:日本旅游多少钱 知乎 编辑:程序博客网 时间:2024/04/30 14:24

基本介绍

泛型实现了参数化类型的概念,使代码可以应用于多种类型。泛型的出现最引人注目的一个原因,就是为了创造容器类。它的主要目的就是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。

泛型模式推荐名称

K – 键,比如映射的键。

V – 值,比如 List 和 Set 的内容,或者 Map 中的值。

E – 异常类。

T – 泛型。

为什么要使用泛型:
1. 编译期安全检查,防患于未然。
2. 从集合中取元素不需要进行手工转换,编译器会替你插入隐式的转换。
3. 参数化类型,让类的使用更加灵活。

注意:
虽然你可以将List < String > 传递给类型List的参数,但是不能将它传给类型List< Object >的参数。泛型有子类型化的规则,List< String >是原生态类型List的一个子类型,而不是参数化类型List< Object >的子类型。

几种写法

  • 原生态类型 如 List。 移植兼容性 促成了支持原生态类型的决定
  • List< Object>是个参数化类型,表示可以包含任何对象类型的一个集合
  • 无限制通配符类型如List< ?> 读作‘某个类型的集合’
  • 类型限制< T extends Comparable< T>> 读作‘针对可以与自身进行比较的每个类型T’
  • 有限制的通配符类型< ? extends E>和< ? super E>

泛型方法

一个基本的原则是:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛化,那么应该有限采用泛型方法。下面来看一个简单的泛型方法的定义:

public class Main {    public static <T> void out(T t) {        System.out.println(t);    }    public static void main(String[] args) {        out("findingsea");        out(123);        out(11.11);        out(true);    }}

  
使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。
  
需要注意,一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。

类型推导

泛型方法的一个显著特征是,无需明确指定类型参数的值,不像调用泛型构造器的时候是必须指定的。编译器通过检查方法参数的类型来计算类型参数的值。

利用泛型方法调用所提供的类型推导,使创建参数化类型实例的过程变得更加轻松。

public static <K,V> HashMap<K,V> newHashMap(){    return new HashMap<K,V>();}

可以用下面的简介代码来取代重复的声明:

Map<String,List<String>> anagrams = newHashMap();

类型擦除

public class GenericTest {    public static void main(String[] args) {        Class c1 = new ArrayList<String>().getClass();        Class c2 = new ArrayList<Integer>().getClass();        System.out.println(c1 == c2);//true    }}

ArrayList< String>和ArrayList< Integer>很容易被认为是不同的类型。但上面的程序会认为它们是相同的类型。

在泛型代码内部,无法获得任何有关泛型参数类型的信息。

Java泛型是使用擦除来实现的,这意味着在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此ArrayList< String>和ArrayList< Integer>在运行时事实上是相同的类型。这两种形式都被擦除成它们的“原生”类型 – List。

边界

边界使得你可以在用于泛型的类型参数上设置限制条件,但是其潜在的重要的效果是你可以按照自己的边界类型来调用方法。这点在使用框架的时候,设计的模板类中应用较多。

public class ServiceImpl<M extends BaseMapper<T,I>, T, I> implements BaseService<T,I>{    @Autowired    protected M baseMapper;    public int insert(T t) {        return baseMapper.insert(t);    }    public int deleteById(I id) {        return baseMapper.deleteById(id);    }    public int update(T t) {        return baseMapper.update(t);    }    public T selectById(I id) {        return baseMapper.selectById(id);    }    public List<T> selectList() {        return baseMapper.selectList();    }}

有了这个边界之后,可以调用边界类型里面定义的方法。

PECS

Producer Extends Consumer Super:
频繁往外读取内容的,相当于生产者,适合用上界Extends.
经常往里插入的,相当于消费者,适合用下界Super.

0 0