第二十一章 泛型(generic)

(1)引言

泛型:是指参数化类型的能力。

例如:有这样一个类:这是一个比较简单并且是很常用的带有泛型的方法。

package com.lidd.generic;

public class GenericTestSecond {

public <T>void one(T t){

}

}

下面是几个类,分别是一般类、抽象类、接口(接口也是特殊的类)。

package com.lidd.generic;

public class A {

}

package com.lidd.generic;

public abstract class B {

}

package com.lidd.generic;

public interface C {

}

接下里是主函数:

package com.lidd.generic;

public class MainTest {

public static void main(String[] args) {

GenericTestSecond o = new GenericTestSecond();

o.one(new C(){});   //C

o.one(new A());     // A

o.one(new B(){});   // B

o.one("bbbb");      // String

o.one(1);           // Integer

}

}

可以看到main方法中实例化了一个GenericTestSecond对象。方法one中传的参数类型可以是C、A、B、String、Integer等等,也就是说方法one中的泛型并不是指代某一种具体的类型

而实在具体类型的基础上又进行了一层参数化。这就是定义中所说的参数化类型的能力。

(2)泛型的优点。

在jdk 1.5之前

package java,lang;

public interface Comparable{

public int compareTo(Object o);

}

在jdk1.5开始及其以后

package java.lang;

public interface Comparable<T>{

public int compareTo(T t);

}

1、泛型使得程序更加可靠。

Comparable c = new Date();

System.out.println(c.compareTo("red"));

Comparable<Date> c = new Date();

System.out.println(c.compareTo("red"));

62 中一个时间和一个String字符串去做比较,但是在编译期不会有任何问题。但是在运行时会报错。

65 中在编译的时候就会报错,因为Comparable中使用了泛型,并且在64行指定为Date类型。

注意:

泛型类型必须是应用类型,不能用像int double或char这样的基本类型来替换泛型类型。例如下面的语句是错误的:

ArrayList<int> list = new ArrayList<int>();

必须是ArrayList<Integer> list = new ArrayList<Integer>();

2、无需类型转换。

例如:

ArrayList<String> strList = new ArrayList<String>();

strList.add("one");

strList.add("two");

String str = strList.get(0);

91 行不需要这样 String str = (String)strList.get(0);

(3) 泛型的几种常见形式。

1、泛型类(抽象类):

public class GenericStack<E>{

private java.util.ArrayList<E> list = new java.util.ArrayList<E>();

public int getSize(){

return list.size();

}

public E peek(){

return list.get(getSize()-1);

}

public void push(E e){

list.add(e);

}

public E pop(){

E o = list.get(getSize()-1);

list.remove(getSize()-1);

return o;

}

public boolean isEmpty(){

return list.isEmpty();

}

}

或者是:

public class GenericStack<E extends A>{

private java.util.ArrayList<E> list = new java.util.ArrayList<E>();

public int getSize(){

return list.size();

}

public E peek(){

return list.get(getSize()-1);

}

public void push(E e){

list.add(e);

}

public E pop(){

E o = list.get(getSize()-1);

list.remove(getSize()-1);

return o;

}

public boolean isEmpty(){

return list.isEmpty();

}

}

其中A为一个类。

2、泛型接口:

public interface Comparable<T>{

public int compareTo(T t);

}

或者是:

public interface Comparable<T extends A>{

public int compareTo(T t);

}

其中A为一个类。

3、泛型方法:

public class MyTest{

// 注意<T>在方法的返回值类型之前

public <T>void one(T t){

}

}

或者:

public class MyTest{

// 注意<T>在方法的返回值类型之前

public <T extends A>void one(T t){

}

}

其中A为一个类。

(4)通配泛型:

以95行的类做前置准备。

为啥需要通配泛型?

pulic class demo1{

public static void main(String[] args){

GenericStack<Integer> stack = new GenericStack<Integer>();

stack.add(1);

stack.add(2);

stack.add(3);

System.out.println("The max number is"+max(stack));

}

public static double max(GenericStack<Number> stack){

double max = stack.pop().doubleValue();

while(!stack.isEmpty()){

double value = stack.pop().doubleValue();

if(max < value){

max = value;

}

}

return max;

}

}

其中208会出现编译错误,虽然Integer是Number的子类,但是GenericStack<Integer> 不是GenericStack<Number>的子类.

这个时候通配泛型登场了。

上面的代码稍加改动就可以消除208的编译错误。

修改:211-221

public static double max(GenericStack<? extends Number> stack){

double max = stack.pop().doubleValue();

while(!stack.isEmpty()){

double value = stack.pop().doubleValue();

if(max < value){

max = value;

}

}

return max;

}

1、通配泛型的分类:

第一类:?(非受限通配) 相当于 ?extends Object。

例子:

pulic class demo2{

public static void main(String[] args){

GenericStack<Integer> stack = new GenericStack<Integer>();

stack.add(1);

stack.add(2);

stack.add(3);

print(stack);

}

public static double print(GenericStack<?> stack){

while(!stack.isEmpty()){

System.out.println(stack.pop()+"");

}

}

}

注意253行-259行

虽然GenericStack<?>相当于GenericStack<? extends Object>,但是不能是

public static double print(GenericStack<Object> stack){

while(!stack.isEmpty()){

System.out.println(stack.pop()+"");

}

}

否则的话250行编译不能通过。这是因为GenericStack<Integer> 不是GenericStack<Object>的子类。此处有体现的通配泛型的

必要性。

第二类:?extends T (受限通配) // 其中的T是某个泛型类型。

参考228-239行。

第三类:?super T (下限通配)// 其中的T是某个泛型类型。

public class demo3{

public static void main(String[] args){

GenericStack<String> stack1 = new GenericStack<String>();

GenericStack<Object> stack2 = new GenericStack<Object>();

stack1.add("java");

stack1.add("love");

stack2.add(1);

stack2.add(2);

add(stack1,stack2);

}

public static <T>void add(GenericSatck<T> stackTo,GenericStack<? super T> destStack){

while(!stackTo.isEmpty()){

destStack.push(stack1.pop());

}

}

}

296行如果使用<T>代替<? super T> ,那么293就会编译异常。

(5)泛型消除:

泛型是使用一种称为类型消除的方法来实现的。编译器使用泛型类型信息来编译代码,

但是随后就会消除它。因此,泛型信息在运行时是不可用的。

//===========================================读java语言程序设计进阶篇笔记====================================================

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-07 18:24:28

第二十一章 泛型(generic)的相关文章

第十一章 泛型算法 C++ PRIMER

vector<int>::const_iterator result = find(vector.begin(). vector.end(),search_value); 如果查找失败,分会end()  如果有两个,会返回哪一个的迭代器? int *reauslt = find(ia,ia+6,search_value); 也可以同样处理字符串 算法要以<algorithm><numeric>,依赖于迭代器和迭代器的算法实现,算法可能改变值,可能移动元素,单从不直接添加

2017.2.15 开涛shiro教程-第二十一章-授予身份与切换身份(一) table、entity、service、dao

原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第二十一章 授予身份与切换身份(一) 1.使用场景 某个领导因为某些原因不能访问一些网站,他想把这个网站上的工作委托给秘书,但是他又不想提供账户.密码.此时可以使用shiro的 RunAs 功能. RunAs:允许一个用户假装为另一个用户(如果获得了允许)的身份进行访问. 注意,本章代码基于<第十六章 综合实例>,详细的数据模型及基本流程见该章. 2.表及数据

从零开始的linux 第二十一章(Inode以及Block详解其二与软链接)

从零开始的linux 第二十一章 在紧张的学习中,又迎来了新的一周~~小编也在同学们的迫切要求下继续来更新博客咯~~ 同学们:"我们才没要求你!" 唉??同学们一点都不配合呢~~别不好意思嘛~~ 好啦~不逗你们了,小编就节省大家的时间,赶快开始这章的课程吧~~ 在上一章中,小编给同学们讲了 Inode号 和 Block,不过还没有给同学们讲完哦~所以上一章的题目是 其一 ,那么毫无疑问这一章就是其二的内容咯~从上一章同学们已经了解了什么是Inode和Block,以及Inode中包含哪些

第二十一章

孔德之容,唯道是从.道之为物,唯望唯沕.沕呵望呵,中有象呵:望呵沕呵,中有物呵:幽呵冥呵,中有精呵:其精甚真,其中有信.自今及古,其名不去,以顺众父.吾何以知众父之然也?以此. “   孔德之容”,大德的这种运动“唯道是从”,它只是去追随道的运转,或者是按照道的这个运转规律去运转,所以老子在这讲出来道是德的内在动力,德是道的外在体现,大德,德行的这种运动完全是按照道的规律去运转的,叫唯道是从.您如果懂得了道的原理,您就能够从容的去做这个德了 沕是深远的意思,那个望是辽阔辽远的意思,没有边界,这个

C#高级编程第11版 - 第二十一章

导航 C# 全版本特性一览 全书目录 第二十一章 Tasks and Parallel Programming 21.1 概述 459 21.2 Parallel 类 460 21.2.1 使用Parallel.For()方法循环 460 21.2.2 提前中断Parallel.For 462 21.2.3 Parallel.For()方法的初始化 462 21.2.4 使用Parallel.ForEach()方法循环 463 21.2.5 通过Parallel.Invoke()方法调用多个方法

第二十一章、使用查询表达式来查询内存中的数据

什么是语言集成查询(LINQ) 对从应用程序代码中查询数据的机制进行了“抽象”.这个功能称为“语言集成查询”(Language Integrated Query). LINQ的设计者大量借鉴了关系数据库管理系统(例如Microsoft SQL Server)的处理方式,将“数据库查询语句”与“数据在数据库中的内部格式”分隔开.LINQ的语法和语义和SQL很像,具有许多相同的优势.要查询的数据的内部结构发生改变后,不必修改查询代码.注意,虽然LINQ和SQL看起来很像,但LINQ更加灵活,而且能处

第二十一章 命名空间和程序集

命名空间和程序集引用其他程序集mscorlib库命名空间命名空间名称命名空间的补充命名空间跨文件伸展嵌套命名空间using 指令using命名空间指令using别名指令程序集的结构程序集标识符强命名程序集创建强命名程序集程序集的私有方式部署共享程序集和GAC把程序集安装到GACGAC内的并肩执行配置文件延迟签名 命名空间和程序集 引用其他程序集 在第1章中,我们在高层次上观察了编译过程.编译器接受源代码文件并生称名称为程序集的输出文件.这一章中,我们将详细阐述程序集以及它们是如何生成和部署的.你

C++primer第十一章 泛型算法

标准库容器定义的操作非常少.标准库没有给容器添加大量的功能函数,而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是“泛型”的,可作用在不同类型的容器和不同类型的元素上. 因为它们实现共同的操作,所以称之为“算法”:而“泛型”指的是它们可以操作在多种容器类型上——不但可作用于 vector 或 list 这些标准库类型,还可用在内置数组类型.甚至其他类型的序列上. 11.1. 概述 假设有一个 int 的 vector 对象,名为 vec,我们想知道其中包含某个特定值.解决这个问题最简单的

【读书笔记】C#高级编程 第二十一章 任务、线程和同步

(一)概述 所有需要等待的操作,例如,因为文件.数据库或网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务. 线程是程序中独立的指令流. (二)Paraller类 Paraller类是对线程的一个很好的抽象,该类位于System.Threading.Tasks名称空间中,提供了数据和任务并行性. Paraller.For()和Paraller.ForEach()方法在每次迭代中调用相同的代码,二Parallel.Invoke()方法允许同时调用不同的方法.Paraller.I