一泛型
编译时类型安全
运行时更小抛出ClassCastException的可能
以下为详细叙述:
1、先看两个类
public class BooleanFoo
{
private Boolean foo;
public void setFoo(Boolean foo)
{
this.foo = foo;
}
public Boolean getFoo()
{
return foo;
}
}
public class IntegerFoo
{
private Integer foo;
public void setFoo(Integer foo)
{
this.foo = foo;
}
public Integer getFoo()
{
return foo;
}
}
以上两个类,类别定义时逻辑完全一样,不同的只是变量的类别
2、没有jdk1.5泛型前的处理方法
public class ObjectFoo
{
private Object foo;
public void setFoo(Object foo)
{
this.foo = foo;
}
public Object getFoo()
{
return foo;
}
public static void main(String[] args)
{
ObjectFoo foo1 = new ObjectFoo();
ObjectFoo foo2 = new ObjectFoo();
foo1.setFoo(new Boolean(true));
// 类型转换
Boolean b = (Boolean) foo1.getFoo();
// 类型转换
foo2.setFoo(new Integer(10));
Integer i = (Integer) foo2.getFoo();
ObjectFoo foo3 = new ObjectFoo();
foo3.setFoo(new Boolean(true));
String s = (String) foo1.getFoo();
//若没有转换准确,此处编译器不会知道,但是运行时就会报错了public class ObjectFoo
3、利用泛型后的处理
package com.langsin.jdk5;
public class GenericFoo<T>
{
private T foo;
public void setFoo(T foo)
{
this.foo = foo;
}
public T getFoo()
{
return foo;
}
public static void main(String[] args)
{
GenericFoo<Boolean> foo1 = new GenericFoo<Boolean>();
GenericFoo<Integer> foo2 = new GenericFoo<Integer>();
foo1.setFoo(new Boolean(true));
Boolean b = foo1.getFoo();
foo2.setFoo(new Integer(10));
Integer i = foo2.getFoo();
GenericFoo foo5 = new GenericFoo();
// foo5.setFoo("hello world");
// Integer str = (Integer)foo5.getFoo();
// System.out.println(str);
/**
* 如果使用泛型类別,但声明时不指定类型呢? 那麼预设会使用Object,不过需要自己进行类型转换了,
* 但编译器会发出警告,告诉您这可能是不安全的操作
*
*/
// GenericFoo a = new GenericFoo();
// a.setFoo("aa");
// foo1与foo2不是同一个类型了,不能进行赋值
// foo1 = foo2;
}
}
4、泛型举例
public class Generic<T1, T2>
{
private T1 foo1;
private T2 foo2;
public void setFoo1(T1 foo1)
{
this.foo1 = foo1;
}
public T1 getFoo1()
{
return foo1;
}
public void setFoo2(T2 foo2)
{
this.foo2 = foo2;
}
public T2 getFoo2()
{
return foo2;
}
public static void main(String[] args)
{
Generic<Integer, Boolean> foo = new Generic<Integer, Boolean>();
foo.setFoo1(new Integer(1));
foo.setFoo2(new Boolean(false));
System.out.println(foo.getFoo1());
System.out.println(foo.getFoo2());
}
}
public class Generic2<T>
{
private T[] fooArray;
public void setFooArray(T[] fooArray)
{
this.fooArray = fooArray;
}
public T[] getFooArray()
{
return fooArray;
}
public static void main(String[] args)
{
String[] strs = { "hello", "world", "welcome" };
String[] strs2 = null;
Generic2<String> foo = new Generic2<String>();
foo.setFooArray(strs);
strs2 = foo.getFooArray();
for (int i = 0; i < strs2.length; i++)
{
System.out.println(strs2[i]);
}
5、限制泛型可用类型
在定义泛型类别时,预设可以使用任何的类型来实例化泛型类型中的类型,但是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义
类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口
参见程序 ListGenericFoo.java
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ListGenericFoo<T extends List>
{
private T[] fooArray;
public void setFooArray(T[] fooArray)
{
this.fooArray = fooArray;
}
public T[] getFooArray()
{
return fooArray;
}
public static void main(String[] args)
{
ListGenericFoo<LinkedList> foo1 = new ListGenericFoo<LinkedList>();
ListGenericFoo<ArrayList> foo2 = new ListGenericFoo<ArrayList>();
LinkedList[] linkedList = new LinkedList[10];
foo1.setFooArray(linkedList);
ArrayList[] arrayList = new ArrayList[10];
foo2.setFooArray(arrayList);
// ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>();//此处就会报错
}
}
6、类型通配声明
使用<?>或是<? extends SomeClass>的声明方式,意味著您只能通过该名称來取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class GenericTest<T>
{
private T foo;
public T getFoo()
{
return foo;
}
public void setFoo(T foo)
{
this.foo = foo;
}
public static void main(String[] args)
{
GenericTest<? extends List> ge = null;
ge = new GenericTest<ArrayList>();
ge = new GenericTest<LinkedList>();
//ge = new GenericTest<HashMap>();
GenericTest<? super List> ge2 = null;
ge2 = new GenericTest<Object>();
GenericTest<String> ge3 = new GenericTest<String>();
ge3.setFoo("hello world");
GenericTest<? extends Object> ge4 = ge3;
System.out.println(ge4.getFoo());
ge4.setFoo(null);
System.out.println(ge4.getFoo());
//ge4.setFoo("welcome");
}
}
7、继承泛型类别 实现泛型接口
参见程序 Parent.java
参见程序 Child.java
参见程序 ParentInterface.java
参见程序 ChildClass.java
public interface ParentInterface<T1, T2>
{
public void setFoo1(T1 foo1);
public void setFoo2(T2 foo2);
public T1 getFoo1();
public T2 getFoo2();
}
public class Parent<T1, T2>
{
private T1 foo1;
private T2 foo2;
public void setFoo1(T1 foo1)
{
this.foo1 = foo1;
}
public T1 getFoo1()
{
return foo1;
}
public void setFoo2(T2 foo2)
{
this.foo2 = foo2;
}
public T2 getFoo2()
{
return foo2;
}
}
public class ChildClass<T1, T2> implements ParentInterface<T1, T2>
{
private T1 foo1;
private T2 foo2;
public void setFoo1(T1 foo1)
{
this.foo1 = foo1;
}
public T1 getFoo1()
{
return foo1;
}
public void setFoo2(T2 foo2)
{
this.foo2 = foo2;
}
public T2 getFoo2()
{
return foo2;
}
}
public class Child<T1, T2, T3> extends Parent<T1, T2>
{
private T3 foo3;
public void setFoo3(T3 foo3)
{
this.foo3 = foo3;
}
public T3 getFoo3()
{
return foo3;
}
}
二、for-each
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class ForTest
{
public static void main(String[] args)
{
int[] arr = { 1, 2, 3, 4, 5 };
/**
* 新式写法
*/
for (int element : arr)
{
System.out.println(element);
}
System.out.println();
/**
* 旧式写法
*/
for (int i = 0; i < arr.length; i++)
{
System.out.println(arr[i]);
}
String[] names = { "hello", "world", "welcome" };
for (String name : names)
{
System.out.println(name);
}
/**
* 数组本身就是对象
*/
int[][] arr2 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
for (int[] row : arr2)
{
for (int element : row)
{
System.out.println(element);
}
}
Collection<String> collection = new ArrayList<String>();
collection.add("one");
collection.add("two");
collection.add("three");
for(String str : collection)
{
System.out.println(str);
}
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
for(int i = 0 ; i < list.size() ; i++)
{
System.out.println(list.get(i));
}
for(Iterator i = list.iterator(); i.hasNext();)
{
System.out.println(i.next());
}
for(String str : list)
{
System.out.println(str);
}
}
}
三、自动装包/拆包(Autoboxing/unboxing)
自动装包:基本类型自动转为包装类.(int >> Integer)
自动拆包:包装类自动转为基本类型.(Integer >> int)
参见程序 BoxTest.java
参见程序 Frequency.java
参加程序 BoxTest2.java
import java.util.ArrayList;
import java.util.Collection;
public class BoxTest
{
public static void main(String[] args)
{
int a = 3;
Collection<Integer> c = new ArrayList<Integer>();
c.add(a);
c.add(a + 3);
for(Integer i : c)
{
System.out.println(i);
}
}
}
注意:如果值在-127-128之内,将比较原始类型int的value
所以有了以下奇怪的例子
public class BoxTest2
{
public static void main(String[] args)
{
Integer i1 = 100;
Integer i2 = 100;
if (i1 == i2)
System.out.println("i1 == i2");
else
System.out.println("i1 != i2");
}
}
//输出i1 == i2
public class BoxTest2
{
public static void main(String[] args)
{
Integer i1 = 200;
Integer i2 = 200;
if (i1 == i2)
System.out.println("i1 == i2");
else
System.out.println("i1 != i2");
}
}
//输出i1! == i2
四、枚举(Enums)
1、JDK1.5加入了一个全新类型的“类”-枚举类型。为此JDK1.5引入了一个新关键字enum. 我们可以这样来定义一个枚举类型
public enum Color{Red, White, Blue}
然后可以这样来使用Color myColor = Color.Red
2、枚举类型还提供了两个有用的静态方法values()和valueOf(). 我们可以很方便地使用它们,例如
for (Color c : Color.values()) System.out.println(c);
3、例子
public enum Color
{
Red, White, Blue;
public static void main(String[] args)
{
for(Color color : Color.values())
{
System.out.println(color);
}
}
}
public class EnumTest
{
public static void doOp(OpConstant opConstant)
{
switch (opConstant) {
case TURN_LEFT:
System.out.println("向左转");
break;
case TURN_RIGHT:
System.out.println("向右转");
break;
case SHOOT:
System.out.println("射击");
break;
}
}
public static void main(String[] args)
{
doOp(OpConstant.SHOOT);
}
}
enum OpConstant
{
TURN_LEFT, TURN_RIGHT, SHOOT
}
//输出扑克牌
import java.util.*;
public class Card
{
public enum Rank
{
DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE
}
public enum Suit
{
CLUBS, DIAMONDS, HEARTS, SPADES
}
private final Rank rank;
private final Suit suit;
private Card(Rank rank, Suit suit)
{
this.rank = rank;
this.suit = suit;
}
public Rank rank()
{
return rank;
}
public Suit suit()
{
return suit;
}
public String toString()
{
return rank + " of " + suit;
}
private static final List<Card> protoDeck = new ArrayList<Card>();
// Initialize prototype deck
static
{
for (Suit suit : Suit.values())
for (Rank rank : Rank.values())
protoDeck.add(new Card(rank, suit));
}
public static ArrayList<Card> newDeck()
{
return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
}
public static void main(String[] args)
{
for(Card card : protoDeck)
{
System.out.println(card);
}
}
}
//获得枚举代表的值
public enum Coin
{
penny("hello"), nickel("world"), dime("welcome"), quarter("nihao");
private String value;
public String getValue()
{
return value;
}
Coin(String value)
{
this.value = value;
}
public static void main(String[] args)
{
Coin coin = Coin.quarter;
System.out.println(coin.getValue());
}
}
定义枚举类型时本质上就是在定义一個类别,只不过很多细节由编译器帮您完成了,所以某些程度上,enum关键字的作用就像是class或interface。
当您使用“enum”定义 枚举类型时,实质上您定义出來的类型继承自 java.lang.Enum 类型,而每个枚举的成员其实就是您定义的枚举类型的一個实例(Instance),他们都被预
设为 final,所以您无法改变他们,他们也是 static 成員,所以您可以通过类型名称直接使用他们,当然最重要的,它們都是公开的(public)。
枚举的比较
参见程序 ShowEnum.java
枚举的顺序
参见程序 ShowEnum2.java
枚举的方法
参见程序 ShowEnum3.java
public class ShowEnum2
{
public static void main(String[] args)
{
for (OpConstant c : OpConstant.values())
{
System.out.printf("%d, %s %n", c.ordinal(), c);
}
}
}
public class ShowEnum
{
public static void main(String[] args)
{
// valueOf()方法可以让您将指定的字串尝试转换为枚举类型
enumCompareTo(OpConstant.valueOf(args[0]));
}
public static void enumCompareTo(OpConstant constant)
{
System.out.println(constant);
for (OpConstant c : OpConstant.values())
{
System.out.println(constant.compareTo(c));
}
}
}
public class ShowEnum3
{
public static void main(String[] args)
{
for (OpConstants c : OpConstants.values())
{
System.out.printf("%s%n\t%s%n", c, c.getDescription());
}
}
}
enum OpConstants
{
TURN_LEFT, TURN_RIGHT, SHOOT;
public String getDescription()
{
switch (this.ordinal()) {
case 0:
return "向左转";
case 1:
return "向右转";
case 2:
return "射击";
default:
return null;
}
}
}
以下两个类型的例子见附件:
EnumSet的名称说明了其作用,它是在J2SE 5.0后加入的新类别,可以协助您建立枚举值的集合,它提供了一系列的静态方法,可以让您指定不同的集合建立方式
参见程序 EnumSetDemo.java
参见程序 EnumSetDemo2.java
参见程序 EnumSetDemo3.java
EnumMap是个专为枚举类型设计的类别,方便您使用枚举类型及Map对象
参见程序 EnumMapDemo.java
与单纯的使用HashMap比较起來的差別是,在上面的程序中,EnumMap將根据枚举的順序來维护对象的排列顺序
参见程序 EnumMapDemo2.java
从遍访的结果可以看出,对象的順序是根据枚举順序來排列的。
五、静态导入(Static import)
1、要使用静态成员(方法和变量)我们必须给出提供这个静态成员的类。使用静态导入可以使被导入类的所有静态变量和静态方法在当前类直接可见,使用这些静态成员无需再给
出他们的类名
参见程序 Common.java
参见程序 StaticImport.java
package com.common;
public class Common
{
public static final String COUNTRY = "China";
public static int add(int a, int b)
{
return a + b;
}
}
package com.jdk5;
import static com.common.Common.add;
import static com.common.Common.COUNTRY;
public class StaticImport
{
public static void main(String[] args)
{
System.out.println(add(1,2));
System.out.println(COUNTRY);
}
}
六、可变参数(Varargs)
可变参数使程序员可以声明一个接受可变数目参数的方法。注意,可变参数必须是方法声明中的最后一个参数
参见程序 TestVarargs.java
package com.langsin.jdk5;
public class TestVarargs
{
private static int sum(String a ,int... nums)
{
System.out.println(a);
int sum = 0;
for (int num : nums)
{
sum += num;
}
return sum;
}
public static void main(String[] args)
{
int sum = 0 ;
sum = sum("hello",1,2,3,4,5,6);
System.out.println(sum);
}
}
七、Annotation (将在单独博客中总结)