java泛型指导手册(part1)

index

  1. 大致了解一下

  2. java中的泛型List(Generic List in Java)

  3. Java中的泛型集合(Generic Set in Java)

  4. java中的泛型Map(Generic Map in Java)

  5. java的泛型化类

1.大致了解一下

从java5开始,泛型就被加入了java。泛型的意义在于:在你操作object之前,提供了一种指定特定类型为更加通用目的的类或方法的手段。听起来很抽象吧?来点例子看看。

注:泛型当然可以用在不是collection的其他类上,但是呢,用collection来展示泛型的基本概念是很好的。

泛型的例子

List这个接口代表一列表object实例,这意味着我们可以在List里放任何Object,比如:

List list = new ArrayList();
list.add(new Integer(2));
list.add("a String");

因为任何object都可能被加入进来,所以你不得不进行类型转换。比如:

Integer integer = (Integer) list.get(0);
String string   = (String) list.get(1);

很经常的一个情况是,你在一个List里仅添加一种类型数据进去,比如String或其他东西,而不是像我在上面做的一样,把integer和String混在一起。

于是,你使用泛型这一特性,可以限制放在List里的object。除此之外,你省去了类型转换的烦恼。看一下用泛型的真正例子:


List<String> strings = new ArrayList<String>();
strings.add("a String");
String aString = strings.get(0);

牛逼吧?

java7里的类型猜测

泛型特性在java7里做了升级。从7开始,java编译器可以从你赋值给的那个变量的信息知道collection的类型,这里是java7里的泛型例子:

List<String> strings = new ArrayList<>();

注意看,ArrayList的泛型类型已经被省略了,仅有<>留了下来。有时候,这东西也叫做菱形操作符。当你写一个菱形操作符作为一个泛型类型,java的编译器会假设这个被初始化的类和它赋值给的那个变量(i.e.左边的变量)有相同的类型。在上面的例子,String就是泛型的类型,应为List变量把String设置为了它的类型。

循环里的泛型

java5有一个新的for循环,叫做for-each, 这东西对于制定泛型的collection处理的很好。来个例子:


List<String> strings = new ArrayList<String>();

//... add String instances to the strings list...

for(String aString : strings){
  System.out.println(aString);
}

这个for-each循环迭代在strings列表里的所有String实例。

每次迭代,下一个String实例就赋值给aString变量。这个for-loop循环比原来的while循环更加精小,在while里你不得不迭代地使用collection的迭代器(Iterator)的Iterator.next()方法去获得下个实例,这导致代码臃肿。

泛型之于非collection的其他类型

你当然可以将泛型用于其他class,而非仅仅是collection。你可以将你自己的class泛型化。这个以后再说细节。

2. java中的泛型List(Generic List in Java)

java的List接口(java.util.List)能够被泛型化。这就是说,List的一个实例能够被给定一个类型,所以只有那种类型的实例能插入List中和从List中被读取,这里就是一个例子:

List<String> list = new ArrayList<String>;

这个list现在仅仅和String类型的实例联系,这意味着你只能把String放进这个list。不要放别的进list,编译器会抱怨。

泛型的类型检查,仅仅在编译期检查。在运行时你可以调整代码,使字符串列表具有字符串插入的其他对象。不过这是个坏主意。(At runtime it is possible to tweak your code so that a String List has other objects that String’s inserted. This is a bad idea, though.)

进入一个泛型的列表

如下,你能get和insert泛型list的元素:

List<String> list = new ArrayList<String>;

String string1 = "a string";
list.add(string1);

String string2 = list.get(0);

注意,没必要对List.get()方法中得到的对象进行转型,虽然平常需要。

编译器已经知道这个List只包含String的实例,所以转型(cast)是没有必要的。

在泛型化的列表中的迭代

你可以使用迭代器迭代泛型列表,如下所示:

List<String> list = new ArrayList<String>;

Iterator<String> iterator = list.iterator();

while(iterator.hasNext()){
  String aString = iterator.next();
}

跟上面的进入一个泛型的列表里一样,不必转型,在while的跌代器里,你也不必转型。

你也可以使用新的for-loop,如下:


List<String> list = new ArrayList<String>;

for(String aString : list) {
    System.out.println(aString);
}

注意,现在有一个String对象,aString,在for-loop的括号里被声明。

每一次的迭代,这个aString都获得了list的当前元素。

3. Java中的泛型集合(Generic Set in Java)

Java的Set接口(java.util.Set)可以被泛型化。也就是说,Set的实例能够被给定一个类型,所以仅有那种类型的实例能在Set中插入,读取。例子如下:

Set<String> set = new HashSet<String>;

这个集合现在仅仅与String类型联系起来了,意味着,只有String类型的实例能够放入这个set里,不要放别的进set,编译器会抱怨。

泛型的类型检查,仅仅在编译期检查。在运行时你可以调整代码,使字符串集合(Set)具有字符串插入的其他对象。不过这是个坏主意。(At runtime it is possible to tweak your code so that a String Set has other objects that String’s inserted. This is a bad idea, though.)

为泛型化的集合添加元素

通常使用add(),一如你平常也常用的


Set<String> set = new HashSet<String>;

String string1 = "a string";
set.add(string1);

那么最大的差别是什么呢?好吧,就是你尝试添加非String的实例进入上述Set,编译器会抱怨。这是个很好的额外的类型检查特性,你值得拥有。

迭代一个泛型化的Set

使用一个iterator(迭代器)吧,如下:

Set<String> set = new HashSet<String>;

Iterator<String> iterator = set.iterator();

while(iterator.hasNext()){
  String aString = iterator.next();
}

请注意,就像之前在List那一节所说一样,不必为interator.next()去转型。

因为Set已经被泛型化了(泛型化的意思是有了一个指定的type),编译器知道为你打理一切,不论你使用iterator还是for-loop.

下面就为你展示使用for-loop


Set<String> set = new HashSet<String>;

for(String aString : set) {
    System.out.println(aString);
}

4. java中的泛型Map(Generic Map in Java)

Map这个接口(java.util.Map)也是能够被泛型化的,这就是说,在一个泛型化的Map中,你可以指定为key-value指定特定的类型,这里是例子:

Map<Integer, String> set = new HashMap<Integer, String>;

这个Map实例set,现在只能接受Integer作为keys,接受String作为values

一样地,泛型的类型检查仅仅发生在编译期。你可以在运行期调整你的代码,这样你的其他实例就能插入了(我翻译时这段话总是不太确定,是能够动态改变key-value对应的原来的Integer-String类型吗?)。尽管这是一个坏主意。

进入(读取)一个泛型化的Map

添加和获得一个泛型化的Map的元素,一如往常,你可以使用put(),get()

Map<Integer, String> map = new HashMap<Integer, String>;

Integer key1   = new Integer(123);
String  value1 = "value 1";

map.put(key1, value1);

String value1_1 = map.get(key1);

所以大的改变在哪呢?(作者应该是在将新的java7特性羞辱旧版java4,我说可能啊)。

在于一个很nice的类型检查:对于上诉例子,当你的key-value对不是Integer-String时,编译器会抱怨。

java5的auto boxing特性能给我们带来很大方便(使得我们的代码叙述更加人性化):

Map<Integer, String> map = new HashMap<Integer, String>;

Integer key1   = 123;
String  value1 = "value 1";

map.put(key1, value1);

//or

map.put(123, value1);


String value1_1 = map.get(123);

迭代一个泛型化的Map

一个Map,有两个collection可以被迭代: key Setvalue Set

通常情况下,你迭代key Set,然后通过Map.get(key)来获取value。

来,给你两个例子:


Map<Integer, String> map = new HashMap<Integer, String>;

//... add key, value pairs to the Map

// iterate keys.
Iterator<Integer> keyIterator   = map.keySet().iterator();

while(keyIterator.hasNext()){
  Integer aKey   = keyIterator.next();
  String  aValue = map.get(aKey);
}


Iterator<String>  valueIterator = map.values().iterator();

while(valueIterator.hasNext()){
  String aString = valueIterator.next();
}

第二个例子


Map<Integer, String> map = new HashMap<Integer, String>;

//... add key, value pairs to the Map

for(Integer aKey : map.keySet()) {
    String aValue = map.get(aKey);
    System.out.println("" + aKey + ":" + aValue);
}

for(String aValue : map.values()) {
    System.out.println(aValue);
}

同理,不必进行类型检查,编译器知道key的类型一定是Integer,value的值一定是String.

5.java的泛型化类

猜你喜欢

转载自blog.csdn.net/paulkg12/article/details/76013082