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 ...
随机推荐
- Spring(一)Spring的第一滴血
前言 开始工作了,但是一进来公司本来是做爬虫和数据分析的,但是走了一个后端的,导致我必须要去顶替他的工作.因为这个项目使用的是Spring. SpringMVC.Hibernate所以我又要去回忆一下 ...
- js面向对象学习笔记(五):tab切换
重点是this指向问题 <style> .hide{display: none;} #box div,#box1 div{display: none;} .hover{background ...
- 【Java学习笔记之二】java标识符命名规范
什么是标识符 就是程序员在定义java程序时,自定义的一些名字.标识符可以应用在类名.变量.函数名.包名上. 标识符必须遵循以下规则 标识符由26个英文字符大小写(a~zA~Z).数字(0~9).下划 ...
- “玲珑杯”ACM比赛 Round #19题解&源码【A,规律,B,二分,C,牛顿迭代法,D,平衡树,E,概率dp】
A -- simple math problem Time Limit:2s Memory Limit:128MByte Submissions:1599Solved:270 SAMPLE INPUT ...
- hdu_1041(Computer Transformation) 大数加法模板+找规律
Computer Transformation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/ ...
- 来说说datatype
今天敲代码一直卡在一个问题上面好久那就是--datatype的未定义,起初不晓得datatype的含义,遇到这种情况首先想到的就是自己又忘记加上面头文件了.随即写了个stdlib.h上去.可是问题并没 ...
- JS使用循环按指定倍数分割数组组成新的数组的方法
今天一个新人同事问了我一个问题,就是有一个像下边这种不知道具体长度的数组,想以每4个为一组,重新组合为一个二维数组,很简单的需求只需要用到一个循环再去取余数就可以了,写了一个小demo在这里把代码包括 ...
- 再起航,我的学习笔记之JavaScript设计模式29(节流模式)
节流模式 概念介绍 节流模式(Throttler): 对重复的业务逻辑进行节流控制,执行最后一次操作并取消其他操作,以提高性能. 优化滚动事件 有的时候我们再为滚动条添加动画的时候,会发现滚动条不停的 ...
- [20160711][在Windows下调用neven链接库]
相关说明 这篇文档是接前篇[20160711][neven代码移植Windows]和[20160711][VS2012配置OpenCV2.4.9]下完成,首先需要通过篇文档编译出neven动态链接库和 ...
- 利用PHPExcel导出Excel并设置Excel格式以及数据源
浏览:23969 发布日期:2013/07/24 分类:技术分享 代码有点长,读起来有点累.先来个截图 导出的Excel太宽了,所以将后面的列宽重新调整了再截的图 功能包括: 1.设置单元格格式,包括 ...