JAVA泛型使用方法总结
1. 基本概念:
(1)什么是泛型?
泛型,即“参数化类型”。即将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用或调用时传入具体的类型(类型实参)。
(2)为什么要使用泛型?
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。
也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
2. 特性:
参考如下代码:
public class GenericTest {
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>(); Class class1 = list1.getClass();
Class class2 = list2.getClass(); System.out.println(class1.equals(class2)); // 返回true
}
}
在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦除,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
因此,泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。
3. 使用:
(1)泛型类:
public class Generic<T> {
private T key; public Generic(T key) {
this.key = key;
} public T getKey() {
return key;
} public void setKey(T key) {
this.key = key;
}
} public static void main(String[] args) {
Generic gInteger = new Generic(123);
Generic gString = new Generic("abc"); System.out.println(gInteger.getKey()); // 123
System.out.println(gString.getKey()); // "abc"
}
(2)泛型接口:
public interface Generator<T> {
T getName();
} public class IntegerGenerator implements Generator {
@Override
public Object getName() {
return 123; //返回Integer类型
}
} public class StringGenerator implements Generator {
@Override
public Object getName() {
return "apple"; //返回String类型
}
} StringGenerator sGenerator1 = new StringGenerator();
IntegerGenerator iGenerator1 = new IntegerGenerator();
System.out.println(sGenerator1.getName()); // "apple"
System.out.println(iGenerator1.getName()); // 123
(3)泛型方法:
public class GenericMethod {
static class Fruit{
@Override
public String toString() {
return "fruit";
}
} static class Apple extends Fruit{
@Override
public String toString() {
return "apple";
}
} static class Person{
@Override
public String toString() {
return "Person";
}
} static class GenerateMethodTest<T>{
public void show_1(T t){
System.out.println(t.toString());
} //在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。
//由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。
public <E> void show_3(E t){
System.out.println(t.toString());
} //在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。
public <T> void show_2(T t){
System.out.println(t.toString());
}
} public static void main(String[] args) {
Apple apple = new Apple();
Person person = new Person(); GenerateMethodTest<Fruit> generateTest = new GenerateMethodTest<Fruit>(); generateTest.show_1(apple);//apple是Fruit的子类,所以这里可以
//generateTest.show_1(person);//编译器会报错,因为泛型类型实参指定的是Fruit,而传入的实参类是Person //使用这两个方法都可以成功
generateTest.show_2(apple);
generateTest.show_2(person); //使用这两个方法也都可以成功
generateTest.show_3(apple);
generateTest.show_3(person);
}
}
(4)泛型通配符:
Integer 是Number的子类,在使用Generic<Number>作为形参的方法中,能否传入Generic<Integer>的实参?逻辑上能否认为Generic<Number>和Generic<Ingeter>是否是父子关系的泛型类型呢?
public class GenericWildcard {
static void showValue(Generic<Number> number){
System.out.println(number.getKey());
} public static void main(String[] args) {
Generic<Integer> iGeneric = new Generic<Integer>(10);
Generic<Number> nGeneric = new Generic<Number>(21); //showValue(iGeneric);//编译报错:Generic<java.lang.Integer> cannot be applied to Generic<java.lang.Number>
showValue(nGeneric);
}
}
上述示例可以看出,Generic<Integer>不能被看做是Generic<Number>的子类,即同一泛型可以对应多个版本,不同版本的泛型实例是不兼容的。那么这时就需要引入通配符的概念来解决这一问题,如下:
public class GenericWildcard1 { static void showValue1(Generic<?> obj){
System.out.println(obj.getKey());
} public static void main(String[] args) {
Generic iGeneric1 = new Generic(10);
Generic nGeneric1 = new Generic(21); showValue1(iGeneric1);
showValue1(nGeneric1);
}
}
(5)泛型的上下边界:
public class GenericWildcard {
static void showValue2(Generic<? extends Number> obj){
System.out.println(obj.getKey());
} public static void main(String[] args) {
Generic<Integer> gInteger = new Generic(100);
Generic<Double> gDouble = new Generic(10.0);
Generic<Float> gFloat = new Generic(1.1f);
Generic<String> gString = new Generic("abc"); showValue2(gInteger);
showValue2(gDouble);
showValue2(gFloat);
showValue2(gString); //这一行代码编译器会提示错误,因为String类型并不是Number类型的子类
}
}
总结:泛型的上下边界添加,必须与泛型的声明在一起 。
(6)泛型数组:
java中不能创建一个确切的泛型类型的数组,结合如下示例:
List<String>[] list1 = new ArrayList<String>[10]; // 编译不通过
Object[] obj = (Object[]) list1;
List<Integer> list2 = new ArrayList<Integer>();
list2.add(new Integer(10));
obj[1] = list2;
Integer str1 = list1[0].get(1); // Run-time error: ClassCastException.
这时由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给obj[1]赋上一个ArrayList而不会出现异常,但在取数据时未做类型转换,所以就会出现Run-time error: ClassCastException。如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,如下:
List<?>[] list11 = new ArrayList<?>[10];
Object[] obj1 = (Object[]) list11;
List<Integer> list22 = new ArrayList<Integer>();
list22.add(new Integer(10));
obj1[1] = list22;
Integer integer = (Integer)list11[1].get(0);
参考:http://blog.csdn.net/myself8202/article/details/74911227
JAVA泛型使用方法总结的更多相关文章
- java 泛型--桥方法
因为 java 在编译源码时, 会进行 类型擦除, 导致泛型类型被替换限定类型(无限定类型就使用 Object). 因此为保持继承和重载的多态特性, 编译器会生成 桥方法. 本文最后附录所有源码. P ...
- 使用java泛型设计通用方法
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...
- 初识Java泛型以及桥接方法
泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...
- java泛型编译时被擦除引起多态的破坏,用 桥方法解决此类问题。(java 桥方法)
在JVM虚拟机中泛型编译的时候,会出现类型擦除.但是,在多态场景中,编译时,擦除方式会出现多态被破坏的可能. 举个栗子: A.java public class A<T> { void g ...
- java泛型应用实例 - 自定义泛型类,方法
近 短时间需要使用泛型,就研究了下,发现网上的问关于泛型的文章都是讲原理的, 很少有提到那里用泛型比较合适, 本文就泛型类和泛型方法的使用给出两 个典型应用场景. 例如一个toString的泛型方法, ...
- java 泛型的类型擦除与桥方法
泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...
- 浅析Java 泛型
泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...
- Java:泛型基础
泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...
- java泛型基础
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法. Ja ...
随机推荐
- 51 NOD 1238 最小公倍数之和 V3
原题链接 最近被51NOD的数论题各种刷……(NOI快到了我在干什么啊! 然后发现这题在网上找不到题解……那么既然A了就来骗一波访问量吧…… (然而并不怎么会用什么公式编辑器,写得丑也凑合着看吧…… ...
- bzoj:1723: [Usaco2009 Feb]The Leprechaun 寻宝
Description 你难以想象贝茜看到一只妖精在牧场出现时是多么的惊讶.她不是傻瓜,立即猛扑过去,用她那灵活的牛蹄抓住了那只妖精. “你可以许一个愿望,傻大个儿!”妖精说. “财富 ...
- CF 610E. Alphabet Permutations
题目:http://codeforces.com/problemset/problem/610/E 如果存在c1,c2在原串相邻且在询问串中c1在c2前面的话,把它们在原串出现次数加起来记作sum,那 ...
- 如何让低版本IE浏览器支持HTML5标签并为其设置样式
现代的浏览器都支持HTML5,HTML5定义了 8 个新的 HTML 语义元素.所有这些元素都是 块级 元素. 为了能让旧版本的浏览器正确显示这些元素,你可以设置 CSS 的 display 属性值为 ...
- N的N次方
题目描述 现给你一个正整数N,请问N^N的最左边的数字是什么? 输入 输入包含多组测试数据.每组输入一个正整数N(N<=1000000). 输出 对于每组输入,输出N^N的最左边的数字. 样例输 ...
- Oracle_基本函数查询综合
Oracle_基本函数查询综合 --[1]查询出每各月倒数第三天受雇的所有员工 select; --[2]找出早于30年前受雇的员工 select>; select; select; ...
- java中类的加载过程和对象的创建过程
1.类加载过程 首先,jvm在执行时,遇到一个新的类,会先去内存的方法区中去寻找该类的.class文件,如果找到了就直接运行,如果没有找到,则会去硬盘中去寻找该类的.class文件,并将该类文件加载到 ...
- 怎么用Sublime查找替换整个文件夹下的所有文件内容?
https://segmentfault.com/q/1010000003946095 工程目录下有很多图片路径要修改,很多散落在各个文件夹. 2015年11月03日提问 评论 邀请回答 编辑 4个回 ...
- dedecms v5.7 图片集“图集内容”无法调用的解决办法
在dedecms的图片集模型或者基于图片集模型修改的自定义模型中 内容页模板使用 {dede:field.body/} 方式来调用body字段是没有输出的(原因不明,未继续深入) 但有些时候当需要在内 ...
- [SinGuLaRiTy] 复习模板-数学
[SinGuLaRiTy-1047] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 质因数分解 void solve(int n) { == ...