关于泛型

简介:

泛型:

泛型是JDK1.5中一个最重要的特性,通过引入泛型,我们将获得编译时类型的安全,和运行时更小的抛出ClassCastexceptions的可能.在JDK1.5中,你可以声明一个集合接收或者返回的对象的类型.

 泛型之前:

类别定义时的逻辑完全一样,只是里面成员变量的类型不同.

如果需要多个相似的类,需要定义多个文件,不同的只是变量的类别,而逻辑是完全一样的.

IntergerFoo.java

复制代码
 1 public class IntegerFoo{
 2     private Integer foo;
 3 
 4     public Integer getFoo(){
 5         return foo;
 6     }
 7 
 8     public void setFoo(Integer foo){
 9         this.foo = foo;
10     }
11 }
复制代码

BooleanFoo.java

复制代码
 1 public class BooleanFoo{
 2     private Boolean foo;
 3 
 4     public Boolean getFoo()    {
 5         return foo;
 6     }
 7 
 8     public void setFoo(Boolean foo){
 9         this.foo = foo;
10     }
11 }
复制代码

如果有很多类型的话想用一个类型来替代以上等的类型怎么办,只能用Object类.

ObjectFoo.java

复制代码
 1 public class ObjectFoo{
 2     private Object foo;
 3 
 4     public Object getFoo(){
 5         return foo;
 6     }
 7 
 8     public void setFoo(Object foo){
 9         this.foo = foo;
10     }
11     
12     public static void main(String[] args){
13         ObjectFoo foo1 = new ObjectFoo();
14         ObjectFoo foo2 = new ObjectFoo();
15         
16         foo1.setFoo(new Boolean(false));
17         Boolean b = (Boolean)foo1.getFoo();
18         
19         foo2.setFoo(new Integer(10));
20         Integer i = (Integer)foo2.getFoo();
21         
22         ObjectFoo foo3 = new ObjectFoo();
23         foo3.setFoo(new Boolean(false));
24         
25         String str = (String)foo3.getFoo();
26         //这个时候编译不会报错,但是运行的时候Object不能转换成String类型的,一定会出错
27         //java.lang.ClassCastException: java.lang.Boolean cannot be caast to java.lang.String
28     }
29 }
复制代码

定义泛型类别:

如果使用泛型,只要代码在编译时没有出现警告,就不会遇到运行时ClassCastException

所谓泛型就是变量的类型参数化(不是变量本身,是变量的类型).

GenericFoo.java

复制代码
 1 public class GenericFoo<T>{
 2     private T foo;
 3     
 4     public T getFoo(){
 5         return foo;
 6     }
 7 
 8     public void setFoo(T foo){
 9         this.foo = foo;
10     }
11 
12     public static void main(String[] args){
13         GenericFoo<Boolean> foo1 = new GenericFoo<Boolean>();
14         GenericFoo<Integer> foo2 = new GenericFoo<Integer>();
15         
16         foo1.setFoo(new Boolean(false));
17         foo2.setFoo(new Integer(3));
18         
19         Boolean b = foo1.getFoo();
20         Integer i = foo2.getFoo();
21         
22         System.out.println(b);//打印输出:false
23         System.out.println(i);//打印输出:3
24         
25         //foo1 = foo2;
26         //报错Type mismatch: cannot convert from GenericFoo<Integer> to GenericFoo<Boolean>
27         
28         GenericFoo a = new GenericFoo();
29         a.setFoo("hello");
30         
31         String str = (String)a.getFoo();
32         System.out.println(str);//输出:hello
33     }
34 }
复制代码

 Generic.java

复制代码
 1 public class Generic<T1, T2>{
 2     private T1 foo1;
 3     
 4     private T2 foo2;
 5 
 6     public T1 getFoo1(){
 7         return foo1;
 8     }
 9 
10     public void setFoo1(T1 foo1){
11         this.foo1 = foo1;
12     }
13 
14     public T2 getFoo2(){
15         return foo2;
16     }
17 
18     public void setFoo2(T2 foo2){
19         this.foo2 = foo2;
20     }
21     
22     public static void main(String[] args){
23         Generic<Integer, Boolean> foo = new Generic<Integer, Boolean>();
24         
25         foo.setFoo1(new Integer(-20));
26         foo.setFoo2(new Boolean(false));
27         
28         System.out.println(foo.getFoo1());
29         System.out.println(foo.getFoo2());
30     }
31 }
复制代码

 

打印输出:

-20
false

Generic2.java

复制代码
 1 public class Generic2<T>{
 2     private T[] fooArray;
 3     //泛型数组
 4 
 5     public T[] getFooArray(){
 6         return fooArray;
 7     }
 8 
 9     public void setFooArray(T[] fooArray){
10         this.fooArray = fooArray;
11     }
12     
13     public static void main(String[] args){
14         Generic2<String> foo = new Generic2<String>();
15         
16         String[] str1 = {"hello", "world", "welcome"};
17         String[] str2 = null;
18         
19         foo.setFooArray(str1);
20         
21         str2 = foo.getFooArray();
22         
23         for(int i = 0; i < str2.length; i++){
24             System.out.println(str2[i]);
25         }
26     }
27 }
复制代码

 

打印输出:

hello
world
welcome

SimpleCollection.java

复制代码
 1 public class SimpleCollection<T>{
 2     private T[] objArr;
 3     
 4     private int index = 0;
 5     
 6     public SimpleCollection(){
 7         objArr = (T[])new Object[10];
 8         //这个时候编译器会有一个警告:
 9         //Type safety: Unchecked cast from Object[] to T[]
10         //这个时候老师领着看的ArrayList的源码中的get()方法
11         
12         //objArr = new T[10];
13         //报错:Cannot create a generic array of T
14         //语法上不允许这样创建一个泛型数组.这个时候怎么办?
15         //只能用Object类型.
16         
17     }
18     
19     public SimpleCollection(int capacity){
20         objArr = (T[])new Object[capacity];
21     }
22     
23     public void add(T t){
24         objArr[index++] = t;
25     }
26     
27     public int getLength(){
28         return this.index;
29     }
30     
31     public T get(int i){
32         return objArr[i];
33     }
34     
35     public static void main(String[] args){
36         SimpleCollection<Integer> c = new SimpleCollection<Integer>();
37         
38         for(int i = 0; i < 10; i++){
39             c.add(new Integer(i));
40         }
41         
42         for(int i = 0; i < 10; i++){
43             Integer in = c.get(i);
44             
45             System.out.println(in);
46         }
47     }
48 }
复制代码

 

打印输出:1~9

ArrayListTest.java

复制代码
 1 public class ArrayListTest{
 2     public static void main(String[] args){
 3         List<String> list = new ArrayList<String>();
 4         
 5         list.add("a");
 6         list.add("b");
 7         list.add("c");
 8         list.add("d");
 9         //第一种遍历
10         for(int i = 0; i < list.size(); i++){
11             String value = list.get(i);
12             System.out.println(value);
13         }
14         
15         //第二种:使用迭代器
16         for(Iterator<String> iter = list.iterator(); iter.hasNext();){
17             String value = iter.next();
18             System.out.println(value);
19         }
20     }
21 }
复制代码

 

 

打印输出:两次a b c d

SetTest.java

复制代码
  1 package cn.shengsiyuan.jdk5;
  2 
  3 import java.util.HashSet;
  4 import java.util.Iterator;
  5 import java.util.Set;
  6 
  7 public class SetTest{
  8     public static void main(String[] args){
  9         Set<String> set = new HashSet<String>();
 10 
 11         set.add("aa");
 12         set.add("bb");
 13         set.add("cc");
 14 
 15         for (Iterator<String> iter = set.iterator(); iter.hasNext();){
 16             String value = iter.next();
 17             System.out.println(value);
 18         }
 19         
 20         System.out.println("----------------");
 21         
 22         Set<People> set2 = new HashSet<People>();
 23         
 24         set2.add(new People("zhangsan", 20, "beijing"));
 25         set2.add(new People("lisi", 30, "shanghai"));
 26         set2.add(new People("wangwu", 40, "tianjin"));
 27         
 28         for(Iterator<People> iter = set2.iterator(); iter.hasNext();){
 29             People people = iter.next();
 30             
 31             String name = people.getName();
 32             int age = people.getAge();
 33             String address = people.getAddress();
 34             
 35             System.out.println(name + "," + age + "," + address);
 36         }
 37     }
 38 }
 39 
 40 class People{
 41     private String name;
 42 
 43     private int age;
 44 
 45     private String address;
 46 
 47     public People(String name, int age, String address){
 48         this.name = name;
 49         this.age = age;
 50         this.address = address;
 51 
 52     }
 53 
 54     public int hashCode(){
 55         final int prime = 31;
 56         int result = 1;
 57         result = prime * result + ((address == null) ? 0 : address.hashCode());
 58         result = prime * result + age;
 59         result = prime * result + ((name == null) ? 0 : name.hashCode());
 60         return result;
 61     }
 62 
 63     public boolean equals(Object obj){
 64         if (this == obj)
 65             return true;
 66         if (obj == null)
 67             return false;
 68         if (getClass() != obj.getClass())
 69             return false;
 70         People other = (People) obj;
 71         if (address == null){
 72             if (other.address != null)
 73                 return false;
 74         }
 75         else if (!address.equals(other.address)){
 76             return false;
 77         }
 78         if (age != other.age){
 79             return false;
 80         }
 81         if (name == null){
 82             if (other.name != null){
 83                 return false;
 84             }
 85         }
 86         else if (!name.equals(other.name)){
 87             return false;
 88         }
 89         return true;
 90     }
 91 
 92     public String getName(){
 93         return name;
 94     }
 95 
 96     public void setName(String name){
 97         this.name = name;
 98     }
 99 
100     public int getAge(){
101         return age;
102     }
103 
104     public void setAge(int age){
105         this.age = age;
106     }
107 
108     public String getAddress(){
109         return address;
110     }
111 
112     public void setAddress(String address){
113         this.address = address;
114     }
115 }
复制代码

aa
bb
cc
----------------
wangwu,40,tianjin
zhangsan,20,beijing
lisi,30,shanghai

MapTest.java

复制代码
 1 public class MapTest{
 2     public static void main(String[] args){
 3         Map<String, String> map = new HashMap<String, String>();
 4 
 5         map.put("a", "aa");
 6         map.put("b", "bb");
 7         map.put("c", "cc");
 8         map.put("d", "dd");
 9 
10         Set<String> set = map.keySet();
11 
12         for (Iterator<String> iter = set.iterator(); iter.hasNext();){
13             String key = iter.next();
14             String value = map.get(key);
15 
16             System.out.println(key + ":" + value);
17         }
18 
19         System.out.println("----------------------------------");
20 
21         Set<Map.Entry<String, String>> set2 = map.entrySet();
22 
23         for (Iterator<Map.Entry<String, String>> iter = set2.iterator(); iter
24                 .hasNext();){
25             Map.Entry<String, String> entry = iter.next();
26 
27             String key = entry.getKey();
28             String value = entry.getValue();
29 
30             System.out.println(key + ":" + value);
31         }
32     }
33 }
复制代码

d:dd
b:bb
c:cc
a:aa
----------------------------------
d:dd
b:bb
c:cc
a:aa

限制泛型可用类型:

在定义泛型类别时,预设可以使用任何的类型来实例化泛型类型中的类型,但是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类才能实例化该类型时,可以再定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口.

当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入.

 ListGenericFoo.java

复制代码
 1 public class ListGenericFoo<T extends List> {
 2     // 虽然这个地方List也是一个接口,但是在泛型中仍然要用extends.不能用implements.
 3     // 不管面是类还是接口都要用extends
 4     private T[] fooArray;
 5 
 6     public T[] getFooArray() {
 7         return fooArray;
 8     }
 9 
10     public void setFooArray(T[] fooArray) {
11         this.fooArray = fooArray;
12     }
13 
14     public static void main(String[] args) {
15         ListGenericFoo<LinkedList> foo1 = new ListGenericFoo<LinkedList>();
16         ListGenericFoo<ArrayList> foo2 = new ListGenericFoo<ArrayList>();
17 
18         LinkedList[] linkedList = new LinkedList[10];
19 
20         foo1.setFooArray(linkedList);
21 
22         ArrayList[] arrayList = new ArrayList[10];
23 
24         foo2.setFooArray(arrayList);
25 
26         // ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>();
27         // 报错,HashMap和List没有关系.
28         // Bound mismatch: The type HashMap is not a valid substitute for
29         // the bounded parameter <T extends List> of the type ListGenericFoo<T>
30     }
31 }
复制代码

 

类型通配声明:

现在有这么一个需求,你希望哟u一个参考名称foo可以接受所有下面的实例:

foo = new Generic Foo<ArrayList>();
foo = new Generic Foo<LinkedList>();

 

简单的说,实例化类型持有者时,它必须是实现List的类别或其子类别,要定义这样一个名称,你可以使用"?"通配字符,并使用extends关键字限定类型持有者的形态.

GenericFoo<? extends List> foo = null;
foo = new GenericFoo<ArrayList>();
foo = new GenericFoo<LinkedList>();

 

GenericTest.java

复制代码
 1 public class GenericTest<T>{
 2     private T foo;
 3 
 4     public T getFoo(){
 5         return foo;
 6     }
 7 
 8     public void setFoo(T foo){
 9         this.foo = foo;
10     }
11     
12     public static void main(String[] args){
13         GenericTest<? extends List> ge = null;
14         
15         ge = new GenericTest<ArrayList>();
16         ge = new GenericTest<LinkedList>();
17         
18         //ge = new GenericTest<HashMap>();
19         
20         GenericTest<? super List> ge2 = null;
21         //这种super的非常少用,传递的值的类型必须是List的父类....
22         ge2 = new GenericTest<Object>();
23         
24         //ge2 = new GenericTest<ArrayList>();
25         //Type mismatch: cannot convert from GenericTest<ArrayList> to GenericTest<? super List>
26         
27         GenericTest<String> ge3 = new GenericTest<String>();
28         ge3.setFoo("hello world");
29         //GenericTest<? extends Object> ge4 = ge3;
30         //如果后面是Object的话可以简写成一个问号"?"
31         GenericTest<?> ge4 = ge3;
32         System.out.println(ge4.getFoo());//打印输出:null
33         
34         
35         ge4.setFoo(null);
36         System.out.println(ge4.getFoo());//打印输出:null
37         //ge4.setFoo("welcome");
38         //eclipse的提示错误信息:The method setFoo(capture#7-of ?) 
39         //in the type GenericTest<capture#7-of ?> is not applicable for the arguments (String)
40         //这个错误信息不好理解.老师的解释是,当你上面GenericTest<? extends Object> ge4 的时候,编译器知道ge4的类型是
41         //Object或者其子类.但是当你进行ge4.setFoo("welcome");时候,当进行get的时候必须是一个String类型的,这个和泛型的
42         //的初衷想违背,所以是错误的.
43         
复制代码

 

 

使用<?>或是<? extends SomeClass>的声明方式,意味著您只能通过该名称來取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例,编译器不让您加入信息,理由是,如果可以加入信息的話,那么您就得記得取回的实例是什么类型,然后转换为原來的类型方可进行操作,这就失去了使用泛型的意义。

 



本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/4216818.html,如需转载请自行联系原作者
相关文章
|
6月前
|
Java
|
6月前
|
安全 编译器 Scala
何时需要指定泛型:Scala编程指南
本文是Scala编程指南,介绍了何时需要指定泛型类型参数。泛型提供代码重用和类型安全性,但在编译器无法推断类型、需要提高代码清晰度、调用泛型方法或创建泛型集合时,应明确指定类型参数。通过示例展示了泛型在避免类型错误和增强编译时检查方面的作用,强调了理解泛型使用时机对编写高效Scala代码的重要性。
45 1
何时需要指定泛型:Scala编程指南
|
6月前
|
Java 编译器 语音技术
泛型的理解
泛型的理解
29 0
|
6月前
什么是泛型,泛型的具体使用?
什么是泛型,泛型的具体使用?
33 0
|
6月前
|
Java
什么是泛型, 泛型的具体使用
什么是泛型, 泛型的具体使用
34 0
|
6月前
|
存储 安全 Java
这还是你认识的泛型吗???!
这还是你认识的泛型吗???!
46 0
|
6月前
|
存储 Java
什么是泛型, 泛型的具体使用?
什么是泛型, 泛型的具体使用?
|
存储 算法 编译器
泛型的讲解
泛型的讲解
58 0
|
Java
泛型讲解
本章讲解了什么是泛型以及泛型擦除相关的知识点
82 1
|
Java 编译器 API
泛型-详解
泛型-详解
124 0
泛型-详解