泛型
定义
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
兼容版本
java 1.5
解决什么问题
Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的几个特点
泛型的好处是在编译的时候检查类型安全。
List<Integer> li = new ArrayList<Integer>(); li.put(“123”);
这行代码在编译时期就会报错。
- 所有的强制转换都是自动和隐式的。
该代码不使用泛型:
List li = new ArrayList();
li.put(new Integer(3));
Integer i = (Integer) li.get(0);
该代码使用泛型:
List<Integer> li = new ArrayList<Integer>();
li.put(new Integer(3));
Integer i = li.get(0);
可以看出,在使用泛型的地方,省去了类型强制转换的麻烦
- 泛型不是协变的
关于泛型的混淆,一个常见的来源就是假设它们像数组一样是协变的。其实它们不是协变的。List 不是 List 的父类型。
泛型的使用
泛型类
这时Stack的源码,我们这里仅看和繁星相关的两个操作
public class Stack<E> extends Vector<E> {
@SuppressWarnings("unchecked")
public synchronized E pop() {
if (elementCount == 0) {
throw new EmptyStackException();
}
final int index = --elementCount;
final E obj = (E) elementData[index];
elementData[index] = null;
modCount++;
return obj;
}
public E push(E object) {
addElement(object);
return object;
}
}
泛型接口
public interface HasComponent<C> {
C getComponent();
}
接口实现
public class BusHistoryDetailActivity implements HasComponent<HistoryMissionDetailComponent> {
@Override
public HistoryMissionDetailComponent getComponent() {
return component;
}
}
在实现类中,具体指定了泛型的具体类型。
泛型方法
protected <C> C getComponent(Class<C> componentType) {
return componentType.cast(((HasComponent<C>) getActivity()).getComponent());
}
这个方法是我们fragment中,获取在 activity里面初始化的Component,如果没有泛型的话,我们需要根据具体的需要,写好多方法去获取Component。从这个角度看,泛型提高了代码的重用性。
枚举
定义
枚举在C/C++/c#中,是一个被命名的整型常数的集合。
仿照上述定义,那么在java中枚举是一个被命名的实例对象的集合。
用于表示属于某一组的几个选择。
兼容版本
java 1.5
解决什么问题
- 类型安全
当程序遇到几个不同选择而进行不同的逻辑控制的时候。在1.5之前的版本中,一般采用定义一些常量来解决。虽然采用常量也能解决问题,但容易出错。采用枚举解决问题,在编译时就能解决非法赋值得问题,代码更不容易出错。
举个例子
比如我们安排一周的任务,用常量是这样的
public String getTask(int dayInWeek){
switch (dayInWeek){
case 1:
return "休息";
case 2:
return "上班";
case 3:
return "上班";
case 4:
return "上班";
case 5:
return "上班";
case 6:
return "上班";
case 7:
return "休息";
}
return "诸事不宜";
}
或许你会觉得这样有点怪怪的,毕竟谜之数字,让读程序的人产生迷惑,然后你就采用了下面的方式
public interface DayInWeekInterFace{
int SUNDAY = 1;
int MONDAY = 2;
int TUESDAY = 3;
int WEDNESDAY = 4;
int THURSDAY = 5;
int FRIDAY = 6;
int SATURDAY = 7;
}
public String getTaskByContract(int dayInWeek){
switch (dayInWeek){
case DayInWeekInterFace.SUNDAY:
return "休息";
case DayInWeekInterFace.MONDAY:
return "上班";
case DayInWeekInterFace.TUESDAY:
return "上班";
case DayInWeekInterFace.WEDNESDAY:
return "上班";
case DayInWeekInterFace.THURSDAY:
return "上班";
case DayInWeekInterFace.FRIDAY:
return "上班";
case DayInWeekInterFace.SATURDAY:
return "休息";
}
return "诸事不宜";
}
这样看上去舒服多了,但是,我们调用的时候,不小心传错了数据,getTaskByContract(18)获取到的结果是,今天诸事不宜,所以你就决定去山里躲一下晦气,这是一种很迷信的做法
为了防止你在不该爬山的时候跑到山上去,我们采用了这样的做法
public enum DayInWeek {
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY;
}
public String getTaskByEnum(DayInWeek dayInWeek){
switch (dayInWeek){
case SUNDAY:
return "休息";
case MONDAY:
return "上班";
case TUESDAY:
return "上班";
case WEDNESDAY:
return "上班";
case THURSDAY:
return "上班";
case FRIDAY:
return "上班";
case SATURDAY:
return "休息";
}
return "诸事不宜";
}
这样就再也不用担心诸事不宜的问题了
关于枚举的争议
在Dalvik虚拟机还没JIT编译器优化代码的时候,不建议android平台使用枚举类型,因为和使用整形常量相比,这种设计带来的内存和性能损失更大。这就是为什么在一些老版本的Android API中还存在如此多的整形常量的原因。如今有了更强大的JIT编译器以及不断改进的Dalvik虚拟机,开发者不必担心这个问题,放心大胆地使用类型安全枚举即可。(摘自android编程实战)
java语言特性
支持构造方法传值(建议使用,而非默认整型值 value)
可以定义方法
来个��
public enum ZMTaskType {
ZOUME_BUS_ORIGIN(1, "定点巴士任务",""), //
ZOUME_BU_CUSTOM(5, "巴士任务",""), //
SHUTTLE(2, "接驳任务",""), //
SPECIAL_CAR_SHARE(3, "快车任务(拼车)",""), //
SPECIAL_CAR_CHARTERED(4, "快车任务(包车)",""), //
OFFICIAL_CAR_MILEAGE(6, "公务用车任务","单程用车"), //
OFFICIAL_CAR_TIMING(7, "公务用车任务","分时租车"),
EXCLUSIVE_CAR_WAY(8, "专车任务","单程"), //
EXCLUSIVE_CAR_TIME(9, "专车任务","分时"); //
private int type;
private String title;
private String subTitle;
ZMTaskType(int type, String title,String subTitle) {
this.type = type;
this.title = title;
this.subTitle = subTitle;
}
/**
* 根据任务类型编号获取任务字符串
*
* @param type
* @return
*/
public static String getTaskTypeStrByType(int type) {
String taskTypeStr = "";
for (ZMTaskType taskType : ZMTaskType.values()) {
if (type == taskType.type) {
taskTypeStr = taskType.title;
}
}
return taskTypeStr;
}
/**
* 根据类型获取枚举
*
* @param type
* @return
*/
public static ZMTaskType getEnumByType(int type) {
ZMTaskType zmTaskType = null;
for (ZMTaskType taskType : ZMTaskType.values()) {
if (type == taskType.type) {
zmTaskType = taskType;
}
}
return zmTaskType;
}
public String getTypeStr() {
return title;
}
public String getSubTitle(){
return subTitle;
}
}
在这个例子中,我们采用了枚举来表示不同类型的业务类型。
可以看到,我们的业务类型,没有0这个类型。
所以构造方法传值,可以给枚举赋值任何数值(不必向c那样必须是从0开始的连续整型)。
另外,我们还可以在枚举中定义业务类型的相关描述,通过一个方法可以很方便的获取与业务类型对应的业务描述。
总结
泛形和枚举,主要的作用就是在编译时期执行类型安全检查,让我们的错误出在编译时期而非运行时期,提高开发效率。