[Java]《编写高质量代码》笔记(1/2)

《编写高质量代码》笔记(2/2)

通用的方法和准则

尽量显示声明UID

在编写一个可序列化的类(implements Serializable)时,尽量要显式声明serialVersionUID。当我们把一个对象序列化后储存或通过网络传输后,若想要将其反序列化,Java会检测其UID是否相同,如果不同,就会抛出InvalidClassException的异常。如果我们不显示指定serialVersionUID,编译器在编译时会根据包名、类名等属性生成一个独一无二的UID,那么当我们的类改变不大,却又想让JVM反序列化时,就遇到麻烦了。显示声明UID可以“骗过”JVM,告诉它我这还是一个类,可以方便地做到向下兼容,当出现巨大改变的时候,我们仍可以手动修改UID

附: 显式声明的格式

1
private static final long serialVersionUID = XXXXXXXXXL;

在序列化类中,不使用构造函数为final变量赋值

反序列化时构造函数不会执行!!

在发布应用时不要只替换一个类

对于final修饰的基本类型和String类型,编译器会认为它是稳定态,所以在编译时直接把值编译到字节码中了。但这个问题在当前主流的IDE中都不存在,它们都默认编译所有的引用类。

基本类型

用偶判断,不用奇判断

-1 % 2 == 1返回false

模拟取余计算:

1
2
3
public static int remainder(int dividend, int divisor) {
return dividend - dividend / divisor * divisor;
}

由此也可知 -1 mod 2 的值为 -1

优先选择基本类型

自动装箱(拆箱)虽然很方便,但引起的问题往往很隐蔽,比如int无法被转换成Long,出现NPE等等。

若非必要,不要设置随机数种子

系统会默认帮你做的。设置了反而会让随机数不那么随机。

类、对象及方法

使用构造代码块精练程序

构造代码指的是没有任何前缀或后缀,并使用{}括起来的代码片段。编译器会把构造代码块插入到每个构造函数的最前端。

让工具类不可实例化

1
2
3
4
5
6
7
8
9
10
11
public final class Math {
private Math() {}
}

// 使用反射也可以使得Math通过实例访问,可以通过抛出异常来达到更好的限制

public final class UtilsClass {
private UtilsClass() {
throw new Error("This class is not allowed to be instantiated.")
}
}

字符串

推荐使用String直接量赋值

使用String s = "xxxx"的方法赋值而不是String s("xxxx")可以最大限度地利用对象池,达到更好的性能。

正确使用String、StringBuffer、StringBuilder

String:字符串不经常变化

StringBuffer:进行频繁的字符串运算,且运行在多线程环境中

StringBuilder:进行频繁的字符串运算,且运行在单线程环境中