JAVA学习之泛型
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及的术语:
1、整个ArrayList<E>称为泛型类型
2、ArrayList<E>中E称为类型变量或类型参数
3、整个ArrayList<Integer>称为参数化的类型
4、ArrayList<Integer>中的Integer叫类型参数的实例或实际类型参数
5、ArrayList<Integer>中的<>念typeof
6、ArrayList称为原始类型
一、泛型是什么能做什么
泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。
JDK1.5 之前使用集合的问题
public static void testJDK5Befor(){
List list=new ArrayList();
list.add(1);
list.add(2);
list.add("abc");
int a1=(int) list.get(1);
int a2=(int) list.get(2);
}
执行代码在第7行出现错误 Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
JDK1.5 对集合加入了泛型的概念,直接在编译阶段验证数据类型。
public static void testJDK5After(){
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add("abc");
}
第5行在编写时直接报错,提醒你:The method add(Integer) in the type List<Integer> is not applicable for the arguments (String)
泛型的作用:泛型在编译时期进行严格的类型检查,消除了绝大多数的类型转换。泛型在集合中使用广泛,在JDK1.5之后集合框架就全部加入了泛型支持。在没有使用泛型之前,我们可以往List集合中添加任何类型的元素数据,因为此时List集合默认的元素类型为Object,而在我们使用的时候需要进行强制类型转换,这个时候如果我们往List中加入了不同类型的元素,很容易导致类型转换异常。
二、泛型擦除
泛型只作用于编译阶段,在编译阶段严格检查类型是否匹配,类型检查通过后,JVM会将泛型的相关信息擦出掉(即泛型擦除),也就是说,成功编译过后的class文件中是不包含任何泛型信息的,泛型信息不会进入到运行时阶段。
public static void testMain01(){
ArrayList <String> listStr=new ArrayList<String>();
ArrayList <Integer> listInt=new ArrayList<Integer>();
System.out.println(listInt.getClass()==ArrayList.class);//true
System.out.println(listStr.getClass()==listInt.getClass());//true
}
通过该例子我们可以看出泛型在编译为.class文件,加载到内存中后是没有泛型概念的。
1、通过泛型的该特性我们可以使用反射绕过泛型检查向集合中添加任意类型的数据
public static void testMain02() throws Exception{
ArrayList <Integer> listInt=new ArrayList<Integer>();
listInt.add(123);
//我们要往该集合内添加其他类型的数据
listInt.getClass().getMethod("add", Object.class).invoke(listInt, "string");
System.out.println(listInt.size());//
System.out.println(listInt.get(1));//string
}
三、泛型使用中出现的问题
//参数化类型与原始类型的兼容性-编译警告
Collection<String> = new Vector();
//原始类型可以引用一个参数化类型的对象。
Collection = new Vector<String >();
//参数化类型不考虑类型参数的继承关系
Vector<String> v = new Vector<Object>(); //错!
Vector<Object> v = new Vector<String>();//错!
//在创建数组实例时,数组的元素不能使用参数化的类型
Vector<Integer> v[] = new Vector<Integer>[10];
//编译可以通过!因为编译器只会按行解释
Vector v1 = new Vector<Integer>();
Vector<Object> v = v1;
四、泛型的?通配符及扩展
<?>可以引用各种参数化的类型,可以调用与参数无关的方法,不能调用与参数有关的方法
/**
* 遍历任意集合
* @param collection
*/
public static void printCollection(Collection<?> collection){
//System.out.println(collection.add("aa"));
System.out.println(collection.size());
for(Object obj:collection){
System.out.println(obj);
}
}
限定通配符的上边界
正确:Vector<? extends Number> v=new Vector<Integer>();表示 该泛型类型必须是number类型或者其子类类型
错误:Vector<? extends Number> v=new Vector<String>();
限定通配符的下边界
正确:Vector<? super Integer> v=new Vector<Number>();表示 该泛型类型必须是Integer类型或者Integer的父类类型
错误:Vector<? extends Integer > v=new Vector<Byte>();
五、定义泛型的方法
//采用自定义泛型的方式打印出任意参数类型中的所有元素
private static<T> void printCollection(Collection<T> collection,T obj2 ){
for(T obj : collection){
System.out.println(obj);
}
collection.add(obj2);
} //定义一个 方法,可以将任意类型的某个数组填充为相应类型的某个对象
private static<T> void fillArray(T[] a,T obj){
for(int i=0;i<a.length;i++){
a[i] = obj;
}
}
//定义一个 方法,自动将Object类型的对象转换成其它类型
private static<T> T autoConvert(Object obj){
return (T)obj;
}
六、自定义泛型类
package com.jalja.org.base.test; import java.util.Date; public class GenericDao {
public <T> void add(T t){ }
public <T> T findById(int id){
return null;
} public static void main(String[] args) {
GenericDao gd=new GenericDao();
gd.add(new Date());
String str=gd.findById(12);
}
}
一般在DAO中,每个DAO操作的是同一个数据类型,而在本例的15行添加date类型,在16行确返回了一个string类型,我们如何控制我们的dao操作的是同一类型呢,使用泛型类
package com.jalja.org.base.test; import java.util.Date; public class GenericDao <T>{
public void add(T t){
System.out.println(t.getClass());
}
public T findById(int id){
return null;
} public static void main(String[] args) {
GenericDao<Date> gd=new GenericDao<Date>();
gd.add(new Date());
String str=(String) gd.findById(12);
}
}
在这里会发现16行出错,Cannot cast from Date to String 。应为你必须操作同一类型 date
泛型类中的静态方法:
package com.jalja.org.base.test; import java.util.Date; public class GenericDao <T>{
public void add(T t){
System.out.println(t.getClass());
}
public T findById(int id){
return null;
}
//泛型中不能出现与泛型类相关的静态方法,应为静态方法是作用于类级别的,与具体类的实例对象没有关系。
//如果使用类名调用,泛型类型参数T是无法确定具体类型的所以,这样不可以。
public static void update(T t){ }
//可以定义与泛型类的泛型类型参数无关的静态方法
public static <E> void update(E e){ }
}
JAVA学习之泛型的更多相关文章
- Java学习之——泛型
1.概要 generics enable types (classes and interfaces) to be parameters when defining classes, interfac ...
- 5 Java学习之 泛型
1. 基本概念 泛型是Java SE 1.5的新特性,泛型的本质是 参数化类型 ,也就是说所操作的 数据类型 被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为 ...
- Java学习笔记--泛型
一个泛型类就是具有一个或者多个类型变量的类. 我们可以只关注泛型,而不会为数据存储的细节而烦恼 . java泛型(一).泛型的基本介绍和使用 http://blog.csdn.net/lonelyro ...
- Java学习笔记——泛型
假定T不仅要指定接口的类继承.使用下面的方式: public class some<T extends Iterable<T> & Comparable<T>&g ...
- Java学习点滴——泛型
基于<Java编程思想>第四版 前言 虽然Java的泛型在语法上和C++相比是类似的,但在实现上两者是全然不同的. 语法 Java只需要一个<>就可定义泛型.在<> ...
- Java学习之泛型和异常
泛型 1,设计原则或目的:只要代码在编译的时候没有错误,就不会抛异常. 2,泛型通配符 :类型通配符一般是使用 ? 代替具体的类型实参.注意了,此处是类型实参,而不是类型形参!相当于(父类作用)L ...
- Java学习之==>泛型
一.什么是泛型 泛型,即“参数化类型”,在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型.也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类.接口 ...
- Java学习_泛型
什么是泛型. Java标准库提供的ArrayList内部就是一个Object[]数组,配合存储一个当前分配的长度,就可以充当"可变数组". public class ArrayLi ...
- Thinking in Java学习笔记-泛型和类型安全的容器
示例: public class Apple { private static long counter; private final long id = counter++; public long ...
随机推荐
- Leecode刷题之旅-C语言/python-206反转链表
/* * @lc app=leetcode.cn id=206 lang=c * * [206] 反转链表 * * https://leetcode-cn.com/problems/reverse-l ...
- 常用代码c#
当使用 HttpContext.Current用到不是当前线程会出null的情况,可使用 System.Web.HttpRuntime.AppDomainAppPath获取程序的根路 string p ...
- 19-21Consent Page页实现
1-在授权服务端建立相应的显示ViewModel namespace MvcCookieAuthSample.Models { public class ConsentViewModel { publ ...
- python中将datetime对象转化为时间戳
从mongodb中读取出来的记录中,时间存储在datetime对象里,返回给客户端的却要求是时间戳格式,因此需要将对应的datetime时间转化为时间戳,从stackoverflow上找到同样的问题和 ...
- P1199 三国游戏
题目描述 小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏. 在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有 N 位武将(N为偶数且不小于 4),任意两个武将之 ...
- HTML5 离线应用程序
离线Web应用:当客户端本地与Web应用程序的服务器没有建立连接时,也能正常在客户端本地使用该Web应用. Web应用程序的本地缓存与浏览器的网页缓存的区别 1. 本地缓存为整个Web应用程序服务,网 ...
- LiteOS创建任务的一个BUG
在任务创建的时候,参数无法传递,第二个参数本来是用来做参数传递的,但是却没用到,很尴尬啊,缺少了这个功能,很多无法写了? osThreadId_t osThreadNew (osThreadFunc_ ...
- hdu1907John(反nim博弈)
John Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submis ...
- python3 爬虫爬取深圳公租房轮候库(深圳房网)
深圳公租房轮候库已经朝着几十万人的规模前进了,这是截至16年10月之前的数据了,贴上来大家体会下 所以17年已更新妥妥的10W+ 今天就拿这个作为爬虫的练手项目 1.环境准备: 操作系统:win10 ...
- MySQL连接本地数据库时报1045错误的解决方法
navicat for MySQL 连接本地数据库出现1045错误 如下图: 说明连接mysql时数据库密码错误,需要修改密码后才可解决问题: 解决步骤如下: .首先打开命令行:开始->运行 ...