枚举作用是限定某个类成员变量取值是某些固定值,如生活中交通灯抽象成类、颜色为成员变量,则该成员变量就应该有且只有红、黄、绿三个颜色。如果把一周这个事物抽象成类,Day为成员变量,那么成员也是有且只有周一到周日。无论是交通灯还是一周,用户对他们的实例的颜色和Day成员都不能随便赋值,只能赋予其合理合法的值。枚举就能够满足这个要求。
在JDK1.5以前,普通类通过修饰符的限定可以使其具有这样的功能,1.5以后JDK追加了枚举类。
下面是普通类方式来实现交通灯:
public abstract class Lamp {
private int time;
public int getTime() {
return time;
}
private Lamp(int time) { // 私有其构造方法
this.time = time;
}
public abstract Lamp nextLight();// 抽象方法 返回下一个交通灯
public final static Lamp RED = new Lamp(30) {
@Override
public String toString() {
return "红灯";
}
@Override
public Lamp nextLight() {
return GREEN;
}
};
public final static Lamp GREEN = new Lamp(45) {
@Override
public String toString() {
return "绿灯";
}
@Override
public Lamp nextLight() {
return YELLOW;
}
};
public final static Lamp YELLOW = new Lamp(5) {
@Override
public String toString() {
return "黄灯";
}
@Override
public Lamp nextLight() {
return RED;
}
};
}
测试:
public class MTest {
public static void main(String[] args) {
Lamp green=Lamp.GREEN;
System.out.println(green+":"+green.getTime()+" 下一个-->"+green.nextLight());
Lamp red=Lamp.RED;
System.out.println(red+":"+red.getTime()+" 下一个-->"+red.nextLight());
Lamp yellow=Lamp.YELLOW;
System.out.println(yellow+":"+yellow.getTime()+" 下一个-->"+yellow.nextLight());
}
}
结果: 绿灯:45 下一个-->黄灯
红灯:30 下一个-->绿灯
黄灯:5 下一个-->红灯
下面是Enum类方式:
public enum Lamp {
RED(30) {
@Override
public String toString() {
// TODO Auto-generated method stub
return "红灯";
}
@Override
public Lamp nextLamp() {
// TODO Auto-generated method stub
return GREEN;
}
},
GREEN(40) {
@Override
public String toString() {
// TODO Auto-generated method stub
return "绿灯";
}
@Override
public Lamp nextLamp() {
// TODO Auto-generated method stub
return YELLOW;
}
},
YELLOW(5) {
@Override
public String toString() {
// TODO Auto-generated method stub
return "黄灯";
}
@Override
public Lamp nextLamp() {
// TODO Auto-generated method stub
return RED;
}
};
private int time;
public int getTime() {
return time;
}
public abstract Lamp nextLamp();
private Lamp(int time) {
this.time = time;
}
}
测试结果同样是: 绿灯:45 下一个-->黄灯
红灯:30 下一个-->绿灯
黄灯:5 下一个-->红灯
二、泛型
一个工厂可以生产冰箱和空调,使用一模一样的包装箱子。当空调和冰箱装进箱子后外观一模一样,别人也无法分辨里面装的到底是什么东西,假如客户本来想买空调使用其调节空气功能,结果到家打开盒子通上电发现是冰箱,没有调节空气的功能,客户疯了。但是如果厂家再生产包装箱时,包装箱都贴上冰箱和空调的标签,工人们装箱时只限定空调装进空调包装箱,冰箱装进冰箱箱子。装错了,流水线上的负责监督的领导就批评他扣他工资。这样就保证客户到手的东西一定是想要的,也一定有其对应的功能。
把上边的例子抽象到Java里,容器就是java里的容器类比如集合List,空调或冰箱就是要装进集合内的对象IceBox和Aircon,那么箱子的标签就是泛型,比如给装IceBox和Aircon的箱子打上标签就是List<IceBox>和List<Aircon> ,流水线上负责监督的领导就是Java编译器,他能够保证List<IceBox>和List<Aircon>引用的对象只能装入IceBox和Aircon。这样既能够保证调用者拿到标签上(泛型)上的东西也免去了类型转换这一过程。
如下:
public static void main(String[] args) {
// TODO Auto-generated method stub
List<IceBox> list=new ArrayList<IceBox>();
IceBox icebox1=new IceBox();
IceBox icebox2=new IceBox();
IceBox icebox3=new IceBox();
IceBox icebox4=new IceBox();
list.add(icebox1);
list.add(icebox2);
list.add(icebox3);
list.add(icebox4);
}
除了上面一种跟在容器后面作为“标签”的作用以外,还有另一种用法,一个类的成员变量的类型如果需求有多种,则该成员变量类型不固定,如果没有泛型就只能有多少种需求写多少种“可能”,泛型出现后可以跟在类后面作为不固定成员类的“通配符”
public class MTest {
public static void main(String[] args) {
List<String> strs = new ArrayList<String>();
strs.add("aaa");
strs.add("bbb");
strs.add("ccc");
printCollecrion(strs);
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
printCollecrion(nums);
}
private static void printCollecrion(Collection<?> collection) {
// TODO Auto-generated method stub
for (Object iterable_element : collection) {
System.out.println(iterable_element);
}
}
/**
* @param collection
* 自定义泛型T 用以接收任意类型对象
*/
private static <T> void printCollecrion1(Collection<T> collection) {
// TODO Auto-generated method stub
for (T t : collection) {
System.out.println(t);
}
}
}
以上?表示代表任何类型,而T是自定义用以接收对象的类型,并且可以用对象。
泛型限定:
设置泛型对象的上限使用extends,表示参数类型只能是该类型或该类型的子类
public class MTest {
public static void main(String[] args) {
List<Animal> list=new ArrayList<Animal>();
printName(list);
//错:The method printName(Collection<? extends Person>) in the type MTest is not applicable for the arguments (List<Animal>)
}
// 泛型限制该方法只能接受Person和其子类的集合参数
public static void printName(Collection<? extends Person> collection) {
}
}
class Person {
}
class Student extends Person {
}
class Teacher extends Person {
}
class Animal {
}
设置泛型对象的下限使用super,表示参数类型只能是该类型或该类型的父类:
public class MTest {
public static void main(String[] args) {
List<Student> list=new ArrayList<Student>();
printName(list);
//错:The method printName(Collection<? super Teacher>) in the type MTest is not applicable for the arguments (List<Student>)
}
// 泛型限制该方法只能接受Teacher和其父类的集合参数
public static void printName(Collection<? super Teacher> collection) {
}
}
class Person {
}
class Student extends Person {
}
class Teacher extends Person {
}
class Animal {
}
此外反省还允许嵌套使用,如用常见的Map取出的操作
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("name", "zhangshan");
map.put("age","15" );
map.put("add", "beijing");
Set<Map.Entry<String, String>> set=map.entrySet();
for(Map.Entry<String, String> ob:set){
System.out.println(ob.getKey());
System.out.println(ob.getValue());
}
}
自定义泛型
class MyMap<K, V> {
private K k;// 模拟key
private V v;// 模拟value
// 用list存储Key和Value
List<K> klist = new ArrayList<K>();
List<V> vlist = new ArrayList<V>();
public <K, V> MyMap() {
// TODO Auto-generated constructor stub
}
// 模拟put方法
public void put(K k, V v) {
klist.add(k);
vlist.add(v);
}
// 模拟get方法 根据传入的key所在klist的index 获取在vlist的value
public V get(K k) {
for (int i = 0; i < klist.size(); i++) {
if (klist.get(i).equals(k))
return vlist.get(i);
}
return null;
}
}
测试:
public class MyMapTest {
public static void main(String[] args) {
MyMap<String, String> map = new MyMap<String, String>();
map.put("aaa", "你好");
map.put("bbb", "黑马");
map.put("ccc", "程序");
map.put("ddd", "员");
System.out.println(map.get("ccc"));
}
}
打印结果: 程序
null
自定义泛型除了可以定义到类上,还可以定义到方法上,比如要写一个方法在任何类型数组,给定两个索引位置就能够交换,如下:
public class MTest {
public static void main(String[] args) {
Integer[] arr1 = { 1, 2, 3 };
String[] arr2 = { "aaa", "bbb", "ccc" };
swap(arr1, 0, 2);
swap(arr2, 0, 2);
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
}
public static <T> void swap(T[] arr, int index1, int index2) {
T temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
}
结果:
[3, 2, 1]
[ccc, bbb, aaa]
注意:上面用的是integer而不是int,因为泛型限定不能使用基本数据类型,如果使用int编译器不会通过。