java劣质代码 java恶意代码( 四 )


影响
在初始化时验证对象确保了数据的完整性 。
例如,请想象为客户创建新帐户的 Account 对象 。只有在 Account 期初余额大于 0 时,才可以开设新帐户 。可以在构造器里执行这样的验证 。有些人未执行构造器而创建 Account 对象 , 他可能创建了一个具有一些负值的新帐户,这样会使系统不一致,容易受到进一步的干预 。
建议
在使用对象之前,请检查对象的初始化过程 。要做到这一点,每个类都应该有一个在构造器中设置的私有布尔标志,如清单 9 中的类所示 。在每个非 static 方法中,代码在任何进一步执行之前都应该检查该标志的值 。如果该标志的值为 true,那么控制应该进一步继续;否则,控制应该抛出一个例外并停止执行 。那些从构造器调用的方法将不会检查初始化的变量,因为在调用方法时没有设置标志 。因为这些方法并不检查标志,所以应该将它们声明为 private 以防止用户直接访问它们 。
清单 9. 使用布尔标志以检查初始化过程
public class MyClass{
private boolean initialized = false;
//Other variables
public MyClass (){
//variable initialization
method1();
initialized = true;
}
private void method1(){ //no need to check for initialization variable
//code
}
public void method2(){
try{
if(initialized==true){
//proceed with the business logic
}
else{
throw new Exception("Illegal State Of the object");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
如果对象由逆序列化进行初始化,那么上面讨论的验证机制将难以奏效,因为在该过程中并不调用构造器 。在这种情况下,类应该实现 ObjectInputValidation 接口:
清单 10. 实现 ObjectInputValidation
interface java.io.ObjectInputValidation {
public void validateObject() throws InvalidObjectException;
}
所有验证都应该在 validateObject() 方法中执行 。对象还必须调用 ObjectInputStream.RegisterValidation() 方法以为逆序列化对象之后的验证进行注册 。RegisterValidation() 的第一个参数是实现 validateObject() 的对象,通常是对对象自身的引用 。注:任何实现 validateObject() 的对象都可能充当对象验证器,但对象通常验证它自己对其它对象的引用 。RegisterValidation() 的第二个参数是一个确定回调顺序的整数优先级,优先级数字大的比优先级数字小的先回调 。同一优先级内的回调顺序则不确定 。
当对象已逆序列化时,ObjectInputStream 按照从高到低的优先级顺序调用每个已注册对象上的 validateObject() 。
不要通过名称来比较类
有时候,您可能需要比较两个对象的类,以确定它们是否相同;或者,您可能想看看某个对象是否是某个特定类的实例 。因为 JVM 可能包括多个具有相同名称的类(具有相同名称但却在不同包内的类) , 所以您不应该根据名称来比较类 。
影响
如果根据名称来比较类,您可能无意中将您不希望授予别人的权利授予了闯入者的类,因为闯入者可以定义与您的类同名的类 。
例如 , 请假设您想确定某个对象是否是类 com.bar.Foo 的实例 。清单 11 演示了完成这一任务的错误方法:
清单 11. 比较类的错误方法
if(obj.getClass().getName().equals("Foo"))// Wrong!
// objects class is named Foo
}else{
// object's class has some other name
}
建议
在那些非得根据名称来比较类的情况下,您必须格外小心,必须确保使用了当前类的 ClassLoader 的当前名称空间,如清单 12 中所示:
清单 12. 比较类的更好方法

推荐阅读