从哲学上来说,很难描述一个具体的人,你可以描述它的长相、性格、工作等,但是人都是有多重身份的,估计只有使用多个And(与操作)将所有的描述串联起来才能描述一个完整的人,比如我,上班时我是一个职员,下班了坐公交车我是一个乘客,回家了我是父母的孩子,是儿子的父亲……角色时刻在变换。那如果我们要使用Java程序来对一类人进行管理,该如何做呢?比如在公交车费优惠系统中,对部分人员(如工资低于2500元的上班族并且是站立着的乘客)车费打8折,该如何实现呢?
注意这里的类型参数有两个限制条件:一为上班族;二为是乘客。具体到我们的程序中就应该是一个泛型参数具有两个上界(Upper Bound),首先定义两个接口及实现类,代码如下:
//职员
interface Staff{
//工资
public int getSalary();
}
//乘客
interface Passenger{
//是否是站立状态
public boolean isStanding();
}
//定义“我”这个类型的人
class Me implements Staff, Passenger{
public boolean isStanding(){
return true;
}
public int getSalary(){
return 2000;
}
}
"Me"这种类型的人物有很多,比如做系统分析师也是一个职员,也坐公交车,但他的工资实现就和我不同,再比如Boss级的人物,偶尔也坐公交车,对大老板来说他也只是一个职员,他的实现类也不同,也就是说如果我们使用"T extends Me"是限定不了需求对象的,那该怎么办呢?可以考虑使用多重限定,代码如下:
//工资低于2500元的上班族并且站立的乘客车票打8折
public static<T extends Staff&Passenger>void discount(T t){
if(t.getSalary()<2500&&t.isStanding()){
System.out.println("恭喜你!您的车票打八折!");
}
}
public static void main(Stringargs){
discount(new Me());
}
使用“&”符号设定多重边界(Multi Bounds),指定泛型类型T必须是Staff和Passenger的共有子类型,此时变量t就具有了所有限定的方法和属性,要再进行判断就易如反掌了。
在Java的泛型中,可以使用“&”符号关联多个上界并实现多个边界限定,而且只有上界才有此限定,下界没有多重限定的情况。想想你就会明白:多个下界,编码者可自行推断出具体的类型,比如"?super Integer"和"?extends Double",可以更细化为Number类型了,或者Object类型了,无须编译器推断了。
为什么要说明多重边界?是因为编码者太少使用它了,比如一个判断用户权限的方法,使用的是策略模式(Strategy Pattern),示意代码如下:
public class UserHandler<T extends User>{
//判断用户是否有权限执行操作
public boolean permit(T user, List<Job>jobs){
List<Class<?>>iList=Arrays.asList(user.getClass().getInterfaces());
//判断是否是管理员
if(iList.indexOf(Admin.class)>-1){
Admin admin=(Admin)user;
/*判断管理员是否有此权限*/
}else{
/*判断普通用户是否有此权限*/
}
return false;
}
}
此处进行了一次泛型参数类别判断,这里不仅仅违背了单一职责原则(Single Responsibility Principle),而且让“泛型”很汗颜:已经使用泛型限定参数的边界了,还要进行泛型类型判断。事实上,使用多重边界可以很方便地解决问题,而且非常优雅,建议读者在开发中考虑使用多重限定。