码迷,mamicode.com
首页 > 编程语言 > 详细

十、java泛型

时间:2015-09-11 00:00:58      阅读:342      评论:0      收藏:0      [点我收藏+]

标签:

一、泛型的基本知识

泛型的语义上理解是“适合许多种类型”, 设计出来的最初目的是希望类或者方法拥有最广泛的表达能力。

1.简单泛型

对于泛型来说最常用也是最简单的应用就是创造容器类

 1 package com;
 2 
 3 public class Holder<T> {
 4     private T a ;
 5     public Holder() {
 6     }
 7     
 8     public Holder(T a ) {
 9         this.a = a;
10     }
11     
12     public static void main(String[]args) {
13         Holder<Integer> holder = new Holder<Integer>(1);
14         System.out.println(holder.a);
15                         // holder.a = "1";  //这就报错,因为规定了泛型要接受Integer类型        
16         Holder<String> holder2 = new Holder<String>("hello");
17                         //holder2.a = 1; //这也报错,因为规定了泛型只能够接收 String        
18         Holder holder3 = new Holder();
19         holder3.a = 1;
20         holder3.a = "1"; //这里就不报错,因为没给holder3声明泛型。这里就相当于里面存放的Object
21     }
22 }

 

泛型T处,可以代之任何类型,声明时候指定T为哪个类型(比如上面main函数中指定为Integer)那这个容器就只能装哪种类型,这就在两个方面给出了适用泛型的理由: 未指定之前,它足够“广泛”,可以指代任何类型; 指定之后,它会提供编译器校验,更加安全。

2.复杂泛型--元组

1)什么是元组?

来看看这样一种情景:一个复杂页面中,有A,B两个(甚至更多)模块, 其中A模块对应t_a表, B模块对应t_b表, 那么在同时获取两种数据对象返回的时候,常见的做法是两种:使用List<?> 来接收, 另一种方式是创建一个新的对象C, C对象里面有A,B , 用List<C>来接收。

元组,给了我们在处理这种情景的第三种选择,见下例:

 1 package com;
 2 
 3 public class ThreeCouple <A,B,C> {
 4     public final A a ;
 5     public final B b ;
 6     public final C c ;
 7     
 8     public ThreeCouple(A a, B b, C c) {//这里写代码的时候犯下一个小错误,不能够构造方法也用<>包起来。。
 9         this.a = a;
10         this.b = b;
11         this.c = c;
12     }
13     
14     public String toString() {
15         return a.toString() +","+b.toString()+","+c.toString();
16     }
17     
18     public static void main(String[]args) {
19         ThreeCouple<Integer, Boolean,String>  th = new ThreeCouple<Integer, Boolean, String>(1,true,"hello world");
20         System.out.println(th.toString());
21     }
22 }

 

结果如下:

技术分享

可以看到,元组对于同时传递几个对象来说是个不错的选择。

2)元组的继承

 1 package com;
 2 
 3 class TwoCouple<A,B> {
 4     public final A a;
 5     public final B b;
 6     
 7     public TwoCouple(A a ,B b) {
 8         this.a = a;
 9         this.b = b;
10     }
11     
12     public String toString() {
13         return a.toString()+","+b.toString();
14     }
15 }
16 public class ThreeCouple <A,B,C> extends TwoCouple<A, B>{
17     public C c ;
18     
19     public ThreeCouple(A a, B b, C c) {//这里写代码的时候犯下一个小错误,不能够构造方法也用<>包起来。。
20         super(a,b);
21         this.c = c;
22     }
23     
24     public String toString() {
25         return super.toString()+","+c.toString();
26     }
27     
28     public static void main(String[]args) {
29         ThreeCouple<Integer, Boolean,String>  th = new ThreeCouple<Integer, Boolean, String>(1,true,"hello world");
30         System.out.println(th.toString());
31     }
32 }

 

结果如下:

技术分享

注意一点,元组这里使用public final来修饰成员变量, 这么写在传递多个对象的时候的有点事“格式更简洁”, 并且因为由public final修饰, 元组中的元素在提供给外部使用的时候也不必担心元素值被篡改。

3.泛型接口--泛型可以用于接口

泛型接口应用的例子, 最常见的就是“生成器”,生成器 (generator)是一种专门负责创建对象的类,类似于工厂模式。见下例:

 1 package com;
 2 
 3 import java.util.Iterator;
 4 import java.util.Random;
 5 
 6 interface GeneratorIntf<T> {
 7     T next();
 8 }
 9 
10 //创建一个咖啡类
11 class Coffee {
12     private static long counter = 0;
13     private final long id = counter++;
14     
15     public String toString() {
16         return this.getClass().getSimpleName()+" "+id;
17     }
18 }
19 
20 //创建拿铁类,它继承咖啡
21 class Latte extends Coffee{
22     
23 }
24 
25 //创建摩卡类 ,它继承咖啡
26 class Mocha extends Coffee {
27     
28 }
29 
30 //创建卡帕奇诺,它继承咖啡
31 class Cappuccino extends Coffee {
32     
33 }
34 
35 
36 //下面创建一个生成器
37 class CoffeeGenerator<Coffee> implements GeneratorIntf<Coffee>,Iterable<Coffee> {
38     private Class[] types = {Latte.class,Mocha.class,Cappuccino.class};//生成器里面,包含具体产品的类名
39     
40     private static Random rd = new Random(47);
41     
42     public CoffeeGenerator() {
43         
44     }
45     
46     private int size = 0;//大小默认为0
47     
48     public CoffeeGenerator(int sz) {
49         this.size = sz;
50     }
51     
52     @Override
53     public Coffee next() {
54         Coffee coffee = null;
55         try {
56             coffee =  (Coffee)types[rd.nextInt(types.length)].newInstance(); //这里,通过类型信息来直接newInstance() 创建对象
57         } catch(Exception e) {
58             e.printStackTrace();
59         }
60         return coffee;
61     }
62     
63     class CoffeeIterator<Coffee> implements Iterator<Coffee>{//创建咖啡迭代器类
64         int count = size;
65         
66         public boolean hasNext() {
67             return count>0;
68         }
69         
70         public void remove() {
71             throw new UnsupportedOperationException("暂不考虑");
72         }
73 
74         @Override
75         public Coffee next() {
76             count--;
77             return (Coffee) CoffeeGenerator.this.next();
78         }
79     }
80 
81     @Override
82     public Iterator<Coffee> iterator() {
83         return new CoffeeIterator();
84     }
85 }
86 
87 public class GeneratorTest {
88     public static void main(String[]args) {
89         CoffeeGenerator gen = new CoffeeGenerator<>();
90         for(int i=0;i<5;i++) {
91             System.out.println(gen.next());
92         }
93         
94         for(Object c : new CoffeeGenerator(5)) {
95             Coffee c2 = (Coffee)c;
96             System.out.println(c2);
97         }
98     }
99 }

 

结果如下:

技术分享

4.泛型方法--泛型应用于方法之上

泛型方法使得方法能够独立于类而产生变化, 基于公共的代码里面的方法,如果能够使用泛型,则推荐使用泛型方法, 下面是泛型方法的例子:

 1 package com;
 2 
 3 public class Test {
 4     public void f(int i) {
 5         System.out.println(i);
 6     }
 7     
 8     public <T> void m(T t) {
 9         System.out.println(t);
10     }
11      public <T> T n(T t) {
12         return t;
13     }    
14 
15     public static void main(String[]args) {
16         Test t = new Test();
17         t.f(1);
18         
19         t.m(1);
20         t.m("abc");
21     }
22 }

结果如下:

技术分享

注意泛型方法在返回值位置前面要加<T>

5.匿名内部类中使用泛型

 1 package com;
 2 
 3 interface Generator<T> {
 4     T next();
 5 }
 6 
 7 public class Customer {
 8     private static long counter = 1;
 9     private final long id = counter++;
10     private Customer() {
11     }
12     
13     public String toString() {
14         return "Customer "+id;
15     }
16     
17     public static Generator<Customer> generator() {
18         return new Generator<Customer>() {
19             @Override
20             public Customer next() {
21                 return new Customer();
22             }
23         }; 
24     }
25     
26     public static void main(String[]args) {
27         Generator<Customer> gen = Customer.generator();
28         Customer c = (Customer) gen.next();
29         System.out.println(c);
30     }
31 }

 

结果如下:

技术分享

 

二、泛型中的擦出现象

1.什么是擦出现象?见下例:

 1 import java.util.ArrayList;
 2 
 3 
 4 public class EraseTypeEquivalence {
 5     public static void main(String[]args) {
 6         Class c1 = new ArrayList<String>().getClass();
 7         Class c2 = new ArrayList<Integer>().getClass();
 8         
 9         System.out.println(c1 == c2);
10     }
11 }

 

结果如下:

技术分享

居然是true, 首先联系一点,每种对象Class,都只会在java虚拟机中创建其类型的一个Class类,用于创建其他对象,
而这里虽然泛型用的参数类型不同,但是它本质上面还是ArrayList的Class对象,所以两个是一样的。 所以是true
上面这种情况,就是所谓的泛型擦除现象。
泛型内部,无法获得任何有关泛型参数的信息。也就是虽然对象传递的时候有差别,但是进入到泛型容器中后对容器来说他们的类型信息就没有了, 都被认为是“无类型之分”了。 

 

十、java泛型

标签:

原文地址:http://www.cnblogs.com/kaiguoguo/p/4799638.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!