建议九十一:枚举和注解结合使用威力更大
例子:实现一个访问控制
public class Client {
public static void main(String[] args) {
// 初始化商业逻辑
Foo foo = new Foo();
// 获得注释
Access access = foo.getClass().getAnnotation(Access.class);
// 没有Access注解或鉴权失败
if (access == null || !access.level().identifity()) {
System.out.println(access.level().REFUSE_WORD);
}
}
}
//控制器,控制不同级别访问不用资源
interface Identifier {
// 无权访问时的礼貌用语
String REFUSE_WORD = "您无权访问";
// 鉴权
public boolean identifity();
}
enum CommonIdentifier implements Identifier {
// 权限级别
Reader, Author, Admin;
// 实现鉴权
@Override
public boolean identifity() {
return false;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Access {
// 什么级别可以访问,默认是管理员
CommonIdentifier level() default CommonIdentifier.Admin;
}
//资源设置为作者能访问
@Access(level = CommonIdentifier.Author)
class Foo {
}
建议九十二:注意@Override不同版本的区别
建议九十三:Java的泛型是类型擦除的
Java的泛型在编译期有效,在运行期被清除掉,在编译后所有的泛型类型都会做相应转换
List<String>,List<Integer>,List<T>擦出后的类型是List
List<String>[]擦出后的类型是List[]
List<? extends E>,List<? super E>擦出后的类型是List<E>
List<T extends Serializable & Cloneable>擦出后的类型是List<Serializable>
(1)泛型的class对象是相同的
(2)泛型数组初始化时不能声明泛型类型
(3)instanceOf不允许存在泛型参数
建议九十四:不能初始化泛型参数和数组
建议九十五:强制声明泛型的实际类型
无法从代码中推断出泛型类型的情况下,可强制声明泛型类型
建议九十六:不同场景下使用不同的泛型通配符
Java泛型支持通配符,可以单独使用一个“?”表示任意类,也可以使用extends关键字表示某一个类(接口)的子类型,还可以使用super关键字表示某一个类(接口)的父类型。
如果期望从List集合中读取数据需要使用extends关键字,即界定泛型上界
如果只参与写操作使用super关键字,即界定泛型下界
建议九十七:警惕泛型是不可能协变和逆变的
协变是用一个窄类型替换宽类型,逆变是用宽类型覆盖窄类型
子类的doStuff方法返回值类型比父类方法要窄,此时的doStuff方法是一个协变方法,如下所示:
class Base {
public Number doStuff() {
return 0;
}
}
class Sub extends Base {
@Override
public Integer doStuff() {
return 0;
}
}
子类的doStuff方法的参数类型比父类要宽,此时就是一个逆变方法,如下所示:
class Base {
public void doStuff(Integer i) {
}
}
class Sub extends Base {
public void doStuff(Number n) {
}
}
建议九十八:建议采用的顺序是List<T>,List<?>,List<Object>
(1)List<T>是确定的某一类型,可以进行读写操作
(2)List<?>是只读类型,可以删除元素,
(3)List<Object>可以进行读写操作,但写入时向上转型,读取时向下转型
建议九十九:严格限定泛型类型采用多重界限
public class Client {
public static void main(String[] args) {
discount(new Me());
}
// 工资低于2500的上班族并且站立的乘客的车票打八折
public static <T extends Staff & Passenger> void discount(T t) {
if (t.getSalary() < 2500 && t.isStanding()) {
System.out.println("你的车票打八折");
}
}
}
//职员
interface Staff {
// 工资
public int getSalary();
}
//乘客
interface Passenger {
// 是否是站立状态
public boolean isStanding();
}
//定义我这个类型的人
class Me implements Staff, Passenger {
@Override
public int getSalary() {
return 2000;
}
@Override
public boolean isStanding() {
return true;
}
}
使用“&”符号设定多重界限,指定泛型类型T必须是Staff和Passenger的共有子类型
建议一百:数组的真实类型必须是泛型类型的子类型
当一个泛型类(特别是泛型集合)转变为泛型数组时,泛型数组的真实类型不能是泛型类型的父类型,只能是子类型或自身类型,否则会出现类型转换异常。