Java泛型学习一
Java泛型
所谓泛型,就是变量类型的参数化。泛型是java1.5中引入的一个重要特征,通过引入泛型,可以使编译时类型安全,运行时更少抛出ClassCastException的可能。一提到参数化,最熟悉的就是定义方法是由形参,然后调用此方法时传递实参。那么参数化该怎么理解,顾名思义,就是将类型由原来的具体类型参数化,类似于方法中的变量参数,此是类型也可定义成参数形式,然后在使用,调用时传入具体类型。使用泛型是如果不提供参数类型,即泛型类没有参数化,系统会警告,此时类型为Object。
为什么使用泛型
首先看一段代码:
List list=new ArrayList();
list.add("asd");
list.add("qwe");
list.add(123);
for(int i=0;i<list.size();i++){
String name=(String) list.get(i);//1
System.out.println("name: "+name);
}
在循环当中,由于忘记了之前的list中加入了Integer类型的值或者是其他原因,很容易出现类似于//1中的错误,因为在编译阶段正常,但是在运行时会出现ClassCastException异常。当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型变成了Object类型,但其运行时类型仍然为其本身类型,因此//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现转化异常。
泛型可以限制加入集合当中的元素类型,是编译时不出现问题,运行时就不会抛出ClassCastException异常。使用泛型的典型例子,是在集合中的泛型使用。
在使用泛型前,存入集合中的元素可以是任何类型的,当从集合中取出时,所有的元素都是Object类型,需要进行向下的强制类型转换,转换到特定的类型。
比如:
List myIntList = new LinkedList(); // 1 myIntList.add(new Integer(0)); // 2 Integer x = (Integer) myIntList.iterator().next(); // 3
第三行的这个强制类型转换可能会引起运行时的错误。
泛型的思想就是由程序员指定类型,这样集合就只能容纳该类型的元素。
使用泛型:
List<Integer> myIntList = new LinkedList<Integer>(); // 1' myIntList.add(new Integer(0)); // 2' Integer x = myIntList.iterator().next(); // 3'
将第三行的强制类型转换变为了第一行的List类型说明,编译器会为我们检查类型的正确性。这样,代码的可读性和健壮性也会增强。
自定义泛型类,泛型接口,泛型方法
先简单定义一个类:
1 public class GenericTest {
2
3 public static void main(String[] args) {
4
5 Box<String> name = new Box<String>("corn");
6 System.out.println("name:" + name.getData());
7 }
8
9 }
10
11 class Box<T> {
12
13 private T data;
14
15 public Box() {
16
17 }
18
19 public Box(T data) {
20 this.data = data;
21 }
22
23 public T getData() {
24 return data;
25 }
26
27 }

在泛型接口、泛型类和泛型方法的定义过程中,我们常见的如T、E、K、V等形式的参数常用于表示泛型形参,由于接收来自外部使用时候传入的类型实参。那么对于不同传入的类型实参,生成的相应对象实例的类型是不是一样的呢?

1 public class GenericTest {
2
3 public static void main(String[] args) {
4
5 Box<String> name = new Box<String>("corn");
6 Box<Integer> age = new Box<Integer>(712);
7
8 System.out.println("name class:" + name.getClass()); // com.qqyumidi.Box
9 System.out.println("age class:" + age.getClass()); // com.qqyumidi.Box
10 System.out.println(name.getClass() == age.getClass()); // true
11
12 }
13
14 }

由此,我们发现,在使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存上只有一个,即还是原来的最基本的类型(本实例中为Box),当然,在逻辑上我们可以理解成多个不同的泛型类型。
究其原因,在于Java中的泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。
泛型和子类:
List<String> ls = new ArrayList<String>(); // 1 List<Object> lo = ls; // 2
一个String类型的List是一个Object类的List吗?
不可以,Java编译器将会在第二行产生一个编译错误,因为它们的类型不匹配。
这样就避免了如果lo引入加入Object类型的对象,而ls引用试图将其转换为String类型而引发错误。所以编译器阻止了这种可能。
继承泛型类别:
父类:

public class Parent<T1,T2>
{
private T1 foo1;
private T2 foo2; public T1 getFoo1()
{
return foo1;
}
public void setFoo1(T1 foo1)
{
this.foo1 = foo1;
}
public T2 getFoo2()
{
return foo2;
}
public void setFoo2(T2 foo2)
{
this.foo2 = foo2;
} }

子类继承父类:

public class Child<T1, T2, T3> extends Parent<T1, T2>
{
private T3 foo3; public T3 getFoo3()
{
return foo3;
} public void setFoo3(T3 foo3)
{
this.foo3 = foo3;
} }
实现泛型接口:
泛型接口:

public interface ParentInterface<T1,T2>
{
public void setFoo1(T1 foo1);
public void setFoo2(T2 foo2);
public T1 getFoo1();
public T2 getFoo2(); }

子类实现泛型接口:

public class ChildClass<T1,T2> implements ParentInterface<T1, T2>
{
private T1 foo1;
private T2 foo2; @Override
public void setFoo1(T1 foo1)
{
this.foo1 = foo1; }
@Override
public void setFoo2(T2 foo2)
{
this.foo2 = foo2;
}
@Override
public T1 getFoo1()
{
return this.foo1;
}
@Override
public T2 getFoo2()
{
return this.foo2;
} }

调用泛型方法语法格式如下:
定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。
Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。
为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。
泛型方法要求的参数是Class<T>类型,而Class.forName()方法的返回值也是Class<T>,因此可以用Class.forName()作为参数。其中,forName()方法中的参数是何种类型,返回的Class<T>就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,因此返回的是Class<User>类型的对象,因此调用泛型方法时,变量c的类型就是Class<User>,因此泛型方法中的泛型T就被指明为User,因此变量obj的类型为User。
当然,泛型方法不是仅仅可以有一个参数Class<T>,可以根据需要添加其他参数。
为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。
泛型的继承规则:
public void fun(){
System.out.println("A.fun()");
}
}
public class BSub extends B{
@Override
public void fun(){
System.out.println("BSub.fun()");
}
public static void main(String[] args) {
Pair<BSub> p1 = new Pair<BSub>();
Pair p2 = p1;
p2.setFirst(new Date());
BSub b = p1.getFirst();
b.fun();
}
}
Pair<BSub> p1 = new Pair<BSub>();
// Pair<B> p = p1;//不合法,类型不兼容
Pair p2 = p1;
p2.setFirst(new Date());
BSub b = p1.getFirst();
b.fun();
Pair<B> p3 = new Pair<B>();
// Pair<BSub> p4 = p3;//不合法,同样类型不兼容
参考资料:
http://www.cnblogs.com/mengdd/archive/2013/01/21/2869778.html
http://www.cnblogs.com/lwbqqyumidi/p/3837629.html
http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html
http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845938.html
http://www.cnblogs.com/Fskjb/archive/2009/08/23/1552506.html
http://www.cnblogs.com/yinhaiming/articles/1749738.html
http://www.cnblogs.com/nerxious/archive/2012/12/21/2828121.html
http://www.cnblogs.com/anrainie/archive/2012/03/09/2387177.html
http://blog.sina.com.cn/s/blog_44c1e6da0100cus8.html
Java泛型学习一的更多相关文章
- Java泛型学习笔记 - (七)浅析泛型中通配符的使用
一.基本概念:在学习Java泛型的过程中, 通配符是较难理解的一部分. 主要有以下三类:1. 无边界的通配符(Unbounded Wildcards), 就是<?>, 比如List< ...
- Java泛型学习笔记--Java泛型和C#泛型比较学习(一)
总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图.C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型 ...
- java泛型学习(2)
一:深入泛型使用.主要是父类和子类存在泛型的demo /** * 父类为泛型类 * @author 尚晓飞 * @date 2014-7-15 下午7:31:25 * * * 父类和子类的泛型. * ...
- Java泛型学习---第二篇
泛型学习第一篇 1.泛型之擦拭法 泛型是一种类似"模板代码"的技术,不同语言的泛型实现方式不一定相同. Java语言的泛型实现方式是擦拭法(Type Erasure). 所谓擦拭法 ...
- java泛型学习(1)
java泛型(Generices Type) --->概念:泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和 ...
- Java 泛型学习总结
前言 Java 5 添加了泛型,提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,可以为以前处理通用对象的类和方法,指定具体的对象类型.听起来有点抽象, ...
- java 泛型学习随笔
对于java 泛型 编译时处理,运行时擦除的特点理解 对于编译时处理 在使用泛型相关的类或方法时,如果声明时的类型和具体使用时的类型不一致则直接会编译不通过 对于运行时擦除 当在运行时对两个相同类型但 ...
- Java泛型学习笔记 - (六)泛型的继承
在学习继承的时候, 我们已经知道可以将一个子类的对象赋值给其父类的对象, 也就是父类引用指向子类对象, 如: Object obj = new Integer(10); 这其实就是面向对象编程中的is ...
- java 泛型学习
http://blog.csdn.net/archie2010/article/details/6232228 学习集合框架的时候经常用hasmap<Integer,Integer>就是泛 ...
随机推荐
- Redis 学习资料目录(Important)
redis学习路线: 以下是整理的学习redis优秀博客和优秀网站 一.原理: 1. redis命令在线操作 http://try.redis.io/ 2. 中文命令解释: Redis 命令参考 - ...
- 清除浮动以及:after元素
http://www.iyunlu.com/demo/enclosing-float-and-clearing-float/index.html 以上这篇示意图把清除浮动的几种方法讲的非常清楚了,其中 ...
- call aplly笔记
<script> /*1.每个函数都包含两个非继承而来的方法:apply()和call(). 2.他们的用途相同,都是在特定的作用域中调用函数. 3.接收参数方面不同,apply()接收两 ...
- Python入门与基本概念
简介:本学习笔记基于ubuntu,Ubuntu已经内置了python2.7,python2.7既包含老版本的属性,有含有新版本的一些特性,用于对3.x版本的过渡,可以拿来入门学习,入门之后可以再学习p ...
- 重装系统,打开VS进行程序调试运行的时候 Unable to find manifest signing certificate in the certificate store
重装系统,打开VS进行程序调试运行的时候 Unable to find manifest signing certificate in the certificate store. 项目的属性-> ...
- 180328_gVim设置tab为4个空格
找到gVim安装目录 C:\Program Files (x86)\Vim\ 更改目录下的 _vimrc 文件,这是一个只读文件,需要管理员权限进行修改和保存. 在文件末尾添加下列内容: set ts ...
- okhttp3带cookie请求
Request经常都要携带Cookie,上面说过request创建时可以通过header设置参数,Cookie也是参数之一.就像下面这样: Request request = new Request. ...
- node(4)express 框架 EJS模板,cookie, session的学习
一.EJS 概述:前端咱们使用过的一个模板套路,是underscore的套路.接下来EJS它属于后台工程师人的模板. https://www.npmjs.com/package/ejs 官网地址 特点 ...
- numpy meshgrid 和 mgrid 的两个简单实例和解析
numpy.meshgrid 和 numpy.mgrid 用于返回包含坐标向量的坐标矩阵. 当坐标矩阵为二维时, 可用于在图像变形时构建网格. 实例一 from __future__ import p ...
- python modules and packages
https://realpython.com/python-modules-packages/ 在软件开发中,一个module是具有一些相关功能的软件集合,比如,当你在开发一个游戏时,可能会有一个模块 ...