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 ...
随机推荐
-
myeclipse给项目改了名字,但部署tomcat的项目名还是原来的
如标题所示: 在myeclipse中按F2改了项目名称,之前在tomcat中部署的名称是另一个,再次重新部署,永远是上一个的旧名称 解决办法: 项目点右键-properties-左上角搜索框输入web ...
-
iOS 之 Cocoapods安装
进入正题前,先来点前奏:了解cocoapods是某天看一个博客,那时才明白原来写项目不用一个个将三方库拷进项目里啊,惊讶的我是一塌糊涂的啊...(原谅我那时还没进入过正规的IT公司....好多你们自然 ...
-
mysql中更新或者删除语句中子语句不能操作同一个表You can&#39;t specify target table &#39;test&#39; for update in FROM clause
问题描述:有个数据表test,有个字段value,如下 mysql> select * from test;+----+------------------------------------+ ...
-
JDBC的应用实例
首先要添加一个引用的库 在项目上右键--构建路径--配置构建路径--在(库)中选择添加外部JAR--选择jar包添加 jar文件是驱动包 添加后包资源管理器中显示一个引用的库会有jar包 加载数据访问 ...
-
Dev WPF使用总结
1.换肤 ThemeManager.ApplicationThemeName = Theme.DXStyle.Name this.UpdateLayout(); //重新布局
-
Unity3d 内置图形界面系统(Editor GUI)
一.说在前面的 1.unity内置的ui系统,无论是在性能的表现上.功能的强大性上.制作复杂ui的便捷性上,还是其它的一些方面都不如一些第三方的插件来的好,如:NGUI和DF-GUI(PS: 后者比前 ...
-
转载 WebBrowser介绍——Javascript与C++互操作
注:本文来自于 http://www.cnblogs.com/lucc/archive/2010/11/24/1886087.html WebBrowser控件是Microsoft提供的一个用于网页浏 ...
-
C# 将datatable 转换json
public static string DataTableToJson(DataTable dt) { StringBuilder jsonBuilder = new StringBuilder() ...
-
Java多线程同步代码块
/*多线程的安全问题1.为什么会出现安全问题?因为程序在运行时,会出现一个线程在判断条件满足后,具备了执行资格,但没有运行代码后一个线程也判断了条件,也具备了执行资格,后一个线程运行了代码,但这时候, ...
-
C#博文搜集
1. abstract (抽象类) 参考1 2. interface (接口) 参考1 3. 委托 C#委托学习