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泛型使用方法总结的更多相关文章

  1. java 泛型--桥方法

    因为 java 在编译源码时, 会进行 类型擦除, 导致泛型类型被替换限定类型(无限定类型就使用 Object). 因此为保持继承和重载的多态特性, 编译器会生成 桥方法. 本文最后附录所有源码. P ...

  2. 使用java泛型设计通用方法

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...

  3. 初识Java泛型以及桥接方法

    泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...

  4. java泛型编译时被擦除引起多态的破坏,用 桥方法解决此类问题。(java 桥方法)

    在JVM虚拟机中泛型编译的时候,会出现类型擦除.但是,在多态场景中,编译时,擦除方式会出现多态被破坏的可能. 举个栗子: A.java public class A<T> { void g ...

  5. java泛型应用实例 - 自定义泛型类,方法

    近 短时间需要使用泛型,就研究了下,发现网上的问关于泛型的文章都是讲原理的, 很少有提到那里用泛型比较合适, 本文就泛型类和泛型方法的使用给出两 个典型应用场景. 例如一个toString的泛型方法, ...

  6. java 泛型的类型擦除与桥方法

    泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...

  7. 浅析Java 泛型

    泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...

  8. Java:泛型基础

    泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...

  9. java泛型基础

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Ja ...

随机推荐

  1. 洛谷 P1967 货车运输

    洛谷 P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在 ...

  2. isdigit函数

    isdigit是计算机应用C语言中的一个函数,主要用于检查参数c是否为阿拉伯数字0到9. 相关函数 isdigit 表头文件 #include <ctype.h>(C语言),#includ ...

  3. HDU 2296:Ring

    Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a ...

  4. Codeforces 626F Group Projects(滚动数组+差分dp)

    F. Group Projects time limit per test:2 seconds memory limit per test:256 megabytes input:standard i ...

  5. 关于python 2.7要求输出汉字问题

    对于python 2.7,使用print u'好好学习'会出现异常.可用以下作为汉字输出,获取数据(字符串)时,用unicode(str, "utf8")生成unicode对象 p ...

  6. SG 函数 S-Nim

    http://poj.org/problem?id=2960 S-Nim Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 34 ...

  7. Entity Framework Core 懒加载

    众所周知在EF 6 及以前的版本中,是支持懒加载(Lazy Loading)的,可惜在EF Core 并不支持,必须使用Include方法来支持导航属性的数据加载.不过现在EF Core的开发团队打算 ...

  8. 织梦DedeCms获取当前页面URL地址的调用方法

    织梦内容页如何调用当前页面url?相信很多对织梦感兴趣的朋友都会去考虑这个问题:在文章内容中加入本文链接,除了 保护自己版权外还可以增加网站的外链收录.网上这方面的帖子一搜一大堆,但多数都只能调用相对 ...

  9. tree conflict svn 怎么解决

    如果自己和其他人修改了同一个文件,而他已经更新到SVN,你commit时就会出现冲突,如何解决呢? 方法/步骤 使用SVN时,更新一个自己修改的文件到服务器,出现冲突,因为其他同事也修改了这个文件并且 ...

  10. 【问题解决】Eclipse中 ctrl+空格 content assist

    改一下你的快捷键设置:window->perferences-->keys--->查找 content assist--->把这个地方改成你想要的就可以了.!