泛型学习笔记

定义:参数化类型。使程序具有更好的可读性和安全性。

优点:

(泛型类,比如用于集合等容器类型时)

1.编译器进行类型检查,避免插入错误类型的对象;

2.输出时不需要类型的强制转换。

1.泛型类

可以有多个类型变量。

例:

public class Pair<T>{...}

public class Pair<K,V>{...}

2.泛型方法

既可以定义在普通类中,也可以定义在泛型类中。

例:

public static <T> T getMiddle(T[] a){

  return a[a.length/2];

}

调用时,可省略<T>类型参数。

3.类型变量的限定

实现方法:<T extends BoundingType>

表示T使绑定类型的子类型。其中,T和BoundingType可以是类,也可以是接口。且绑定类型可以有多个,中间用&连接,如<T extends Comparable & Serializable>。因为Java只能单继承,因此限定类型中至多只能有一个类,并且必须位于限定列表中的第一个。

4.泛型代码和虚拟机

虚拟机没有泛型类型对象——所有对象都属于普通类。即编译器生成的字节码是不包含泛型信息的,泛型类型信息在编译处理时被擦出——类型擦除

类型擦除

--定义:通过类型参数和并,将泛型类型实例关联到一份字节码上。

--原因:Java为引用类型系统,引用类型集合中的元素本质上都是一个个指针,没必要为每个类型都产生一份执行代码(浪费空间)。

--实现方法:

(1)将所有的泛型参数用最左边界(最顶级的父类型)类型替换;

(2)移除所有类型参数。

4.1 翻译泛型表达式

当程序调用泛型方法时,如果擦除返回类型,编译器将进行强制类型转换。

4.2 翻译泛型方法

例:

class DateInterval extends Pair<Date>{

  public void getSecond(Date second){

    if(second.compareTo(getFirst())>=0)

      super.setSecond(second);

  }

}

类型擦除后,变成

class DateInterval extends Pair{

  public void getSecond(Date second){

    if(second.compareTo(getFirst())>=0)

      super.setSecond(second);

  }

}

那么,DateInterval类中存在一个从Pair类中继承的方法:public void getSecond(Object date){...}。存在问题。

考虑:

DateInterval interval=new DateInterval();

Pair<Date> pair=interval;

pair.setSecond(aDate);

希望对于setSecond的调用具有多态性,因为pair引用DateInterval的对象,故应调用DateInterval中的setSecond方法。问题在于类型擦除与多态发生了冲突。因此,编译器会在DateInterval类中生成一个桥方法(用来保持多态):

public void setSecond(Object aDate){

  setSecond((Date) aDate);

}

5.Java泛型的约束与局限性

(1)不能用基本类型实例化参数类型

  例:Pair<double>//error;应为Pair<Double>

(2)运行时类型查询只适用于原始类型

  例:

A)if(a instanceof Pair<T>)//error;只能测试a是否是任意类型的Pair

B)Pair<String> p=(Pair<String>) a//warning; 只能测试a是否是任意类型的Pair

C)getClass也总是返回原始类型

    Pair<String> sPair=...

    Pair<Employee> ePair=...

    if(sPair.getClass()==ePair.getClass())//true

(3)不能创建参数化类型的数组

  不能创建,如Pair<String>[] pArr=new Pair<String>[10];//error

但是可以声明,如Pair<String>[] pArr;

一种安全有效地方法是使用ArrayList,即ArrayList<Pair<String>>。

(4)不能实例化类型变量

(5)泛型类的静态上下文中类型变量无效

(6)不能抛出或捕获泛型类的实例

(7)注意擦除后的冲突

6.泛型类型的继承规则

注意泛型与数组的区别。

例如:

一个ArrayList<Manager>可转换为一个List<Manager>;

但是,一个ArrayList<Manager>不能转换为ArrayList<Employee>或List<Employee>。

7.通配符类型

7.1 子类型限定

Pair<? extends Employee>

? extends Employee getFirst()//合法,可赋值给Manager对象

void setFirst(? extends Employee)//不合法,编译器不能判断具体是什么类型

7.2 超类型限定

Pair<? super Manager>

? super Manager getFirst()//不合法,只能赋值给一个Object类型对象

void setFirst(? super Manager)//合法,编译器不知道具体类型,但是可以用任何Manager对象或子类型对象调用,但不能用Employee对象

小结:带有超类型限定通配符的可以向泛型对象写入,带有子类型限定通配符的可以从泛型对象读出。

7.3 无限定通配符

Pair<?>

? getFirst()//只能赋值给一个Object

void setFirst(?)//不能被调用,甚至不能被Object调用

Pair<?>与Pair的本质不同在于:可以用任意Object对象调用原始Pair类的setFirst方法。

时间: 2024-08-08 12:22:43

泛型学习笔记的相关文章

Java泛型学习笔记--Java泛型和C#泛型比较学习(一)

总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图.C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型区别的最大原因,后面会介绍).C#泛型在.NET CLR支持为.NET框架引入参数化变量支持.C#泛型更类似C++模板,可以理解,C#泛型实际上可以理解为类的模板类.我们通过代码实例来看C# 2.0泛型解决的问题,首先,我们通过一个没有泛型的迭代器的代码示例说起,代码实现如下: interface

Java泛型学习笔记 - (七)浅析泛型中通配符的使用

一.基本概念:在学习Java泛型的过程中, 通配符是较难理解的一部分. 主要有以下三类:1. 无边界的通配符(Unbounded Wildcards), 就是<?>, 比如List<?>. 无边界的通配符的主要作用就是让泛型能够接受未知类型的数据. 2. 固定上边界的通配符(Upper Bounded Wildcards): 使用固定上边界的通配符的泛型, 就能够接受指定类及其子类类型的数据. 要声明使用该类通配符, 采用<? extends E>的形式, 这里的E就是

Java泛型学习笔记 - (六)泛型的继承

在学习继承的时候, 我们已经知道可以将一个子类的对象赋值给其父类的对象, 也就是父类引用指向子类对象, 如: 1 Object obj = new Integer(10); 这其实就是面向对象编程中的is-a关系. 既然上面的代码正确, 那么在泛型中, 也可以使用如下代码: 1 public class Box<T> { 2 private T obj; 3 4 public Box() {} 5 6 public T getObj() { 7 return obj; 8 } 9 10 pub

Java泛型学习笔记 - (一)泛型的介绍

一.什么是泛型:泛型的作用是用来规定一个类, 接口或方法所能接受的数据的类型. 就像在声明方法时指定参数一样, 我们在声明一个类, 接口或方法时, 也可以指定其"类型参数", 也就是泛型. 不同的是, 声明方法时我们给其参数指定一个值, 而给其泛型指定一个数据类型.二.基本使用方式: 上面的概念啰嗦了许多, 其实我自己写的都累. 最简单有效的学习方法就是用一用嘛: 1 List<String> list = new ArrayList<String>(); 这就

Java泛型学习笔记 - (二)泛型类

1. 我们先写一个没有泛型的类Box: 1 public class Box { 2 3 private Object obj; 4 5 public Box() {} 6 7 public Object getObj() { 8 return obj; 9 } 10 11 public void setObj(Object obj) { 12 this.obj = obj; 13 } 14 15 public Box(Object obj) { 16 super(); 17 this.obj

Java泛型学习笔记 - (四)有界类型参数

1. 当我们希望对泛型的类型参数的类型进行限制的时候(好拗口), 我们就应该使用有界类型参数(Bounded Type Parameters). 有界类型参数使用extends关键字后面接上边界类型来表示, 注意: 这里虽然用的是extends关键字, 却不仅限于继承了父类E的子类, 也可以代指显现了接口E的类. 仍以Box类为例: 1 public class Box<T> { 2 3 private T obj; 4 5 public Box() {} 6 7 public T getOb

Java泛型学习笔记 - (三)泛型方法

泛型方法其实和泛型类差不多, 就是把泛型定义在方法上, 格式大概就是: public <类型参数> 返回类型 方法名(泛型类型 变量名) {...}泛型方法又分为动态方法和静态方法,:1. 动态泛型方法其实在前一篇博文中我已经用到了, 1 public class Box<T> { 2 3 private T obj; 4 5 public Box() {} 6 7 public T getObj() { 8 return obj; 9 } 10 11 public void se

Java泛型学习笔记 - (五)泛型接口

所谓泛型接口, 类似于泛型类, 就是将泛型定义在接口上, 其格式如下: public interface 接口名<类型参数>如: 1 interface Inter<T> { 2 public void show(T t); 3 } 其实现方式有两种:1.在实现时指定泛型: 1 class A implements Inter<String> { 2 3 @Override 4 public void show(String t) { 5 System.out.prin

《C#高级编程》【第五章】泛型 -- 学习笔记

 泛型是高级程序设计语言的一种特性.泛型的引入使得程序开发的效率得到提高,代码的重用性大大的提升.有了泛型,我们可以创建独立于被包含类型的类和方法,我们不必给不同的类编写功能相同的很多方法或者类,只创建一个方法或类就可以了.现在我们看看泛型的优点 性能上,泛型不需要进行类型转换(也就是拆箱和装箱). 类型安全,和Object类相比,Object类属于非类型安全的,而泛型使用泛型类型,可以根据需要用特定的类型替换泛型类型,这样就保证了类型安全类.在编译时,只有与泛型类型T定义的允许使用的类型不