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

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

例子:实现一个访问控制

建议九十二:注意@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的共有子类型

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

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

经验分享 程序员 微信小程序 职场和发展