编写高质量代码:改善Java程序的151个建议(91~100)

建议九十一:枚举和注解结合使用威力更大

例子:实现一个访问控制

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的共有子类型

建议一百:数组的真实类型必须是泛型类型的子类型

当一个泛型类(特别是泛型集合)转变为泛型数组时,泛型数组的真实类型不能是泛型类型的父类型,只能是子类型或自身类型,否则会出现类型转换异常。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值