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 ...
随机推荐
- notpad++ 搭配 gcc
notpad++ 搭配 gcc GCC 是 GNU 编译器套装的简称(GNU Compiler Collection),一套编程语言编译器,以 GPL 及 LGPL 许可证所发行的自由软件,也是 GN ...
- go基础语法-函数
1.基础定义 golang的函数很'纯粹',只有可变参数列表的概念,没有默认参数.可选参数.函数重载.操作符重载这些难以把控的概念 语法:'func'声明,而后函数名在前,中间的括号内定义参数,返回值 ...
- go基础语法-常量与枚举
1.常量定义 用const关键字修饰常量名并赋值,常量命名不同于java等语言,golang中一般用小写,因为在golang中首字母大写表示public权限 const a = 3 2.常量使用 使用 ...
- [BZOJ4552][Tjoi2016&Heoi2016]排序(二分答案+线段树)
二分答案mid,将>=mid的设为1,<mid的设为0,这样排序就变成了区间修改的操作,维护一下区间和即可 然后询问第q个位置的值,为1说明>=mid,以上 时间复杂度O(nlog2 ...
- 【普及】NOIP2011 瑞士轮
用sort会超时,显而易见. 然后想到了归并.至于为什么把运动员分成输与赢两组,我也不是很清楚,也许换种方式分组也行,但是分成输与赢两组更容易分组与合并. #include<iostream&g ...
- CodeChef BIBOARD: Binary Board 命题报告
这道题当时有了一点模糊的想法之后,构思了一整天-- 题意: 有一\(N \times M\)网格,每一格可以是白色或黑色.令\(B_i\)表示\(i \times i\)的纯黑子网格数量(子网格是指原 ...
- vue cli3超详细创建多页面配置
1.首先按照vue cli3 给的入门文档下载个vue cli3 如果之前下载了vue cli2的要先卸载之前的 2.检查安装是否成功 3.ok,现在环境搭建好了,新建项目 vue create he ...
- JavaScript’s “this”: how it works, where it can trip you up
JavaScript’s “this”: how it works, where it can trip you up http://speakingjs.com/es5/ch23.html#_ind ...
- Java设计模式(3)——创建型模式之抽象工厂模式(Abstract Factory)
一.概述 抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式.抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象. UML图: 其他的过多概念不再 ...
- C#使用API屏蔽系统热键和任务管理器
最近做的一个winform类型的项目中需要屏蔽系统热键,在网上搜索了一下,基本上都是调用api来进行hook操作,下面的代码就可以完成功能 using System; using System.IO; ...