【from:】
JDK1.5增加的新特性里面有一个就是泛型。对于泛型的评价,褒贬不一,废话不多说,先来看看他的原理。
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器拦截源程序中的非法输入,
编译器编译 带类型说明的集合 时会去掉类型信息,对于参数化得泛型类型,getClass()方法的返回值和原始类型完全一样。
对于下面这个源程序:
<span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> Oliver {
public static void main(String[] args) {
ArrayList<String> list = <span style="color: rgb(0, 0, 255);">new</span> ArrayList<String>();
list.add("str1");
list.add(<span style="color: rgb(0, 96, 128);">"str2"</span>);
String str = list.get(0);
}
}
编译成Oliver.class后反编译的内容:
<span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> Oliver {
public Oliver() {
}
public static void main(String[] args) {
ArrayList list = <span style="color: rgb(0, 0, 255);">new</span> ArrayList();
list.add("str1");
list.add(<span style="color: rgb(0, 96, 128);">"str2"</span>);
String str = (String) list.get(0);
}
}
也就是说java的泛型只是在编译器做了参数限制,其实对性能并没有什么优化!
由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它的类型数据。
下面代码展示利用反射机制跳过编译器检查:
<span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> Oliver {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = <span style="color: rgb(0, 0, 255);">new</span> ArrayList<Integer>();
list.getClass().getMethod("add", Object.class).invoke(list, "ssss");
System.<span style="color: rgb(0, 0, 255);">out</span>.println(<span style="color: rgb(0, 96, 128);">"list:"</span> + list.get(0));
}
}
输出结果:
list:ssss
对于java泛型,Bruce Ecke(Thinking in Java作者)曾经给出这样的评论:
Guess what. I really don't care. You want to call it "generics," fine, implement something that looks like C++ or Ada, that actually produces a latent typing mechanism like they do. But don't implement something whose sole purpose is to solve the casting problem in containers, and then insist that on calling it "Generics." Of course, Java has long precedence in arrogantly mangling well- accepted meanings for things: one that particularly stuck in my craw was the use of "design pattern" to describe getters and setters. In JDK 1.4 we were told some lame way to use assertions which was a backward justification for them being disabled by default. JDK 1.4 also had to invent its own inferior logging system rather than using the openly created, well-tested and well-liked Log4J. And we've also been told many times about how Java has been as fast or faster than C++, or about how one or another feature is great and flawless. I point to the threads implementation which has had major changes quietly made from version to version with not so much as a peep of apology or admission that "hey, we really screwed up here." Or maybe I was just not on that particular announcement list.
===================================================================================
【from :】
java 泛型详解
普通泛型
1. class Point<T>{ // 此处可以随便写标识符号,T是type的简称
2. private T var ; // var的类型由T指定,即:由外部指定
3. public T getVar(){ // 返回值的类型由外部决定
4. return var ;
5. }
6. public void setVar(T var){ // 设置的类型也由外部决定
7. this.var = var ;
8. }
9. };
10. public class GenericsDemo06{
11. public static void main(String args[]){
12. new Point<String>() ; // 里面的var类型为String类型
13. "it") ; // 设置字符串
14. // 取得字符串的长度
15. }
16. };
17. ----------------------------------------------------------
18. class Notepad<K,V>{ // 此处指定了两个泛型类型
19. private K key ; // 此变量的类型由外部决定
20. private V value ; // 此变量的类型由外部决定
21. public K getKey(){
22. return this.key ;
23. }
24. public V getValue(){
25. return this.value ;
26. }
27. public void setKey(K key){
28. this.key = key ;
29. }
30. public void setValue(V value){
31. this.value = value ;
32. }
33. };
34. public class GenericsDemo09{
35. public static void main(String args[]){
36. null ; // 定义两个泛型类型的对象
37. new Notepad<String,Integer>() ; // 里面的key为String,value为Integer
38. "汤姆") ; // 设置第一个内容
39. 20) ; // 设置第二个内容
40. "姓名;" + t.getKey()) ; // 取得信息
41. ",年龄;" + t.getValue()) ; // 取得信息
42.
43. }
44. };
通配符
1. class Info<T>{
2. private T var ; // 定义泛型变量
3. public void setVar(T var){
4. this.var = var ;
5. }
6. public T getVar(){
7. return this.var ;
8. }
9. public String toString(){ // 直接打印
10. return this.var.toString() ;
11. }
12. };
13. public class GenericsDemo14{
14. public static void main(String args[]){
15. new Info<String>() ; // 使用String为泛型类型
16. "it") ; // 设置内容
17. fun(i) ;
18. }
19. public static void fun(Info<?> temp){ // 可以接收任意的泛型对象
20. "内容:" + temp) ;
21. }
22. };
受限泛型
1. class Info<T>{
2. private T var ; // 定义泛型变量
3. public void setVar(T var){
4. this.var = var ;
5. }
6. public T getVar(){
7. return this.var ;
8. }
9. public String toString(){ // 直接打印
10. return this.var.toString() ;
11. }
12. };
13. public class GenericsDemo17{
14. public static void main(String args[]){
15. new Info<Integer>() ; // 声明Integer的泛型对象
16. new Info<Float>() ; // 声明Float的泛型对象
17. 30) ; // 设置整数,自动装箱
18. 30.1f) ; // 设置小数,自动装箱
19. fun(i1) ;
20. fun(i2) ;
21. }
22. public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子类
23. "、") ;
24. }
25. };
26. ----------------------------------------------------------
27. class Info<T>{
28. private T var ; // 定义泛型变量
29. public void setVar(T var){
30. this.var = var ;
31. }
32. public T getVar(){
33. return this.var ;
34. }
35. public String toString(){ // 直接打印
36. return this.var.toString() ;
37. }
38. };
39. public class GenericsDemo21{
40. public static void main(String args[]){
41. new Info<String>() ; // 声明String的泛型对象
42. new Info<Object>() ; // 声明Object的泛型对象
43. "hello") ;
44. new Object()) ;
45. fun(i1) ;
46. fun(i2) ;
47. }
48. public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型
49. "、") ;
50. }
51. };
泛型无法向上转型
1. class Info<T>{
2. private T var ; // 定义泛型变量
3. public void setVar(T var){
4. this.var = var ;
5. }
6. public T getVar(){
7. return this.var ;
8. }
9. public String toString(){ // 直接打印
10. return this.var.toString() ;
11. }
12. };
13. public class GenericsDemo23{
14. public static void main(String args[]){
15. new Info<String>() ; // 泛型类型为String
16. null ;
17. //这句会出错 incompatible types
18. }
19. };
泛型接口
1. interface Info<T>{ // 在接口上定义泛型
2. public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型
3. }
4. class InfoImpl<T> implements Info<T>{ // 定义泛型接口的子类
5. private T var ; // 定义属性
6. public InfoImpl(T var){ // 通过构造方法设置属性内容
7. this.setVar(var) ;
8. }
9. public void setVar(T var){
10. this.var = var ;
11. }
12. public T getVar(){
13. return this.var ;
14. }
15. };
16. public class GenericsDemo24{
17. public static void main(String arsg[]){
18. null; // 声明接口对象
19. new InfoImpl<String>("汤姆") ; // 通过子类实例化对象
20. "内容:" + i.getVar()) ;
21. }
22. };
23. ----------------------------------------------------------
24. interface Info<T>{ // 在接口上定义泛型
25. public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型
26. }
27. class InfoImpl implements Info<String>{ // 定义泛型接口的子类
28. private String var ; // 定义属性
29. public InfoImpl(String var){ // 通过构造方法设置属性内容
30. this.setVar(var) ;
31. }
32. public void setVar(String var){
33. this.var = var ;
34. }
35. public String getVar(){
36. return this.var ;
37. }
38. };
39. public class GenericsDemo25{
40. public static void main(String arsg[]){
41. null; // 声明接口对象
42. new InfoImpl("汤姆") ; // 通过子类实例化对象
43. "内容:" + i.getVar()) ;
44. }
45. };
泛型方法
1. class Demo{
2. public <T> T fun(T t){ // 可以接收任意类型的数据
3. return t ; // 直接把参数返回
4. }
5. };
6. public class GenericsDemo26{
7. public static void main(String args[]){
8. new Demo() ; // 实例化Demo对象
9. "汤姆") ; // 传递字符串
10. int i = d.fun(30) ; // 传递数字,自动装箱
11. // 输出内容
12. // 输出内容
13. }
14. };
通过泛型方法返回泛型类型实例
1. class Info<T extends Number>{ // 指定上限,只能是数字类型
2. private T var ; // 此类型由外部决定
3. public T getVar(){
4. return this.var ;
5. }
6. public void setVar(T var){
7. this.var = var ;
8. }
9. public String toString(){ // 覆写Object类中的toString()方法
10. return this.var.toString() ;
11. }
12. };
13. public class GenericsDemo27{
14. public static void main(String args[]){
15. 30) ;
16. System.out.println(i.getVar()) ;
17. }
18. public static <T extends Number> Info<T> fun(T param){//方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定
19. new Info<T>() ; // 根据传入的数据类型实例化Info
20. // 将传递的内容设置到Info对象的var属性之中
21. return temp ; // 返回实例化对象
22. }
23. };
使用泛型统一传入的参数类型
1. class Info<T>{ // 指定上限,只能是数字类型
2. private T var ; // 此类型由外部决定
3. public T getVar(){
4. return this.var ;
5. }
6. public void setVar(T var){
7. this.var = var ;
8. }
9. public String toString(){ // 覆写Object类中的toString()方法
10. return this.var.toString() ;
11. }
12. };
13. public class GenericsDemo28{
14. public static void main(String args[]){
15. new Info<String>() ;
16. new Info<String>() ;
17. "HELLO") ; // 设置内容
18. "汤姆") ; // 设置内容
19. add(i1,i2) ;
20. }
21. public static <T> void add(Info<T> i1,Info<T> i2){
22. " " + i2.getVar()) ;
23. }
24. };
泛型数组
1. public class GenericsDemo30{
2. public static void main(String args[]){
3. 1,2,3,4,5,6) ; // 返回泛型数组
4. fun2(i) ;
5. }
6. public static <T> T[] fun1(T...arg){ // 接收可变参数
7. return arg ; // 返回泛型数组
8. }
9. public static <T> void fun2(T param[]){ // 输出
10. "接收泛型数组:") ;
11. for(T t:param){
12. "、") ;
13. }
14. }
15. };
泛型的嵌套设置
1. class Info<T,V>{ // 接收两个泛型类型
2. private T var ;
3. private V value ;
4. public Info(T var,V value){
5. this.setVar(var) ;
6. this.setValue(value) ;
7. }
8. public void setVar(T var){
9. this.var = var ;
10. }
11. public void setValue(V value){
12. this.value = value ;
13. }
14. public T getVar(){
15. return this.var ;
16. }
17. public V getValue(){
18. return this.value ;
19. }
20. };
21. class Demo<S>{
22. private S info ;
23. public Demo(S info){
24. this.setInfo(info) ;
25. }
26. public void setInfo(S info){
27. this.info = info ;
28. }
29. public S getInfo(){
30. return this.info ;
31. }
32. };
33. public class GenericsDemo31{
34. public static void main(String args[]){
35. null ; // 将Info作为Demo的泛型类型
36. null ; // Info指定两个泛型类型
37. new Info<String,Integer>("汤姆",30) ; // 实例化Info对象
38. new Demo<Info<String,Integer>>(i) ; // 在Demo类中设置Info类的对象
39. "内容一:" + d.getInfo().getVar()) ;
40. "内容二:" + d.getInfo().getValue()) ;
41. }
42. };
泛型方法不一定要通过参数来确定泛型准确类型,可以只通过返回值,比如:
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<E>();
}
public List<PrepaidHistory> queryHistories(Long skyid,PrepaidHistoryType type, Date from, Date end) {
。。。
return Lists.newArrayList();
}
这样Lists.newArrayList();
智能的知道返回类型为PrepaidHistory