欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java安全编程规范标准

程序员文章站 2022-06-21 13:42:22
java安全编程规范标准一、方法规范1. 确保使用正确的类型来自动封装数值简介问题说明修正办法2、确保构造函数不会调用可覆写的方法简介问题说明修正办法二、方法规范1.确保比较等同的对象能得到相等的结果简介错误示例一问题说明修正办法错误示例二修正办法方法一方法二一、方法规范1. 确保使用正确的类型来自动封装数值简介问题说明修正办法2、确保构造函数不会调用可覆写的方法简介问题说明修正办法二、方法规范1.确保比较等同的对象能得到相等的结果简介错误示例一问题说明修...



一、方法规范

1. 实现compareTo()方法时遵守常规合约

简介

选择实现了Comparable接口展示了一种责任,那就是对compareTo()方法的实现维持了该方法的合约。库中的类,例如TreeSetTreeMap,接受Comparabled对象,并使用对应的compareTo()方法来整理对象。然而,一个实现了compareTo()方法的类可能会以一种意外的方式生成非期望的结果。
Java SE 6 API 规定了compareTo()方法的使用合约(以下的叙述中,符号sgn代表数学中的signum函数,根据表达式的数值是负数、0或正数,这个函数返回-1、0 或 1):

  1. 必须确保对于所有的xysgn(x.compareTo(y)) == -sgn(y.compareTo(x))成立。(这意味着当y.compareTo(x)抛出异常时,x.compareTo(y)也必须抛出异常。)
  2. 必须确保关联是可传递的:(x.compareTo(y) > 0 && y.compareTo(z) >0)意味着x.compareTo(z)> 0;
  3. 必须确保x.compareTo(y)==0暗示对所有的z,存在sgn(x.compareTo(z))==sgn(y.compareTo(z))
  4. 强烈建议(x.compareTo(y)==0)==x.equals(y)。即是compareTo()函数返回的两个对象相当,其equals()方法返回的这两个对象也应该相等。一般来说,任何实现了comparable接口并违反了这个条件的类应该明确指出这一点。建议使用这样的说法:“注意:此类有着和equals不一致的自身次序。”

需要说明的是,compareTo()方法的实现一定不能违反前三个条件中的任何一条。实现应该尽可能的遵守第四个条件。

违反规则代码示例

public class Solution2 implements Comparable{
    public enum Roshambo {ROCK,PAPER,SCISSORS};
    private Roshambo value;

    Solution2(Roshambo val){
        this.value = val;
    }

    @Override
    public int compareTo(Object o) {
        if (!(o instanceof Solution2)) {
            throw new ClassCastException();
        }
        Solution2 t = (Solution2)o;
        return (value == t.value) ? 0 
                : (value == Roshambo.ROCK && t.value == Roshambo.PAPER) ? -1 
                : (value == Roshambo.PAPER && t.value == Roshambo.SCISSORS) ? -1
                : (value == Roshambo.SCISSORS && t.value ==Roshambo.ROCK) ? -1
                : 1;
    }
} 

问题说明

上面示例中,因为石头赢了剪刀,剪刀赢了布,而是石头确输给了布,所以这个游戏违反了要求中的传递特性。

修正办法

定义成非compare()方法即可,此方法不需要满足既定的规则

2、确保比较中的关键码是可不变的

简介

用于有序集合和映射中关键码的对象应该是不可变的。当一些字段必须是可变的时候,equals(),hashcode()compareTo()方法在比较对象时必须只考虑不变的状态。违反了这条规则会造成集合有不一致的次序。java.util.Interface Set<E>java.util.Interface Map<K,V>的文档中对此提出了警告

不符合规则的示例一

equals()方法中用于比较的字段是可被外界输入改变的。

修正办法

在比较的方法中使用定义为final 字段的声明,此声明在初始化后不会改变,符合规则。

不符合规则的实例二

许多程序员对由序列化引起的散列码易变性会感到惊讶。hashCode()方法的合约没有要求散列码在应用程序的不同执行中保持不变。同样,当序列化一个对象并随后将其反序列化时,该对象反序列化后的散列码可能会和最初的散列码不一致。
如下的不符合规则的代码示例使用MyeKey类作为Hashtable的关键码。Mykey类覆写了object.equals(),但是使用了默认的hashCode()方法。根据Java API中的描述:
为了成功的在散列表中存储和读取对象,作为关键码的对象必须实现hashCodeequals方法。

public class Solution1 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Hashtable<Key,String> ht = new Hashtable<Key,String>();
        Key key = new Key();
        ht.put(key,"value");
        System.out.println("Entry:" + ht.get(key));

        FileOutputStream fos = new FileOutputStream(new File("hashtabel.ser"));
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        oos.writeObject(ht);
        oos.flush();
        oos.close();

        FileInputStream fis = new FileInputStream(new File("hashtabel.ser"));
        ObjectInputStream ois = new ObjectInputStream(fis);
        Hashtable<Key,String> ht_in = (Hashtable<Key,String>)ois.readObject();
        ois.close();
        if(ht_in.contains("value")) {
            System.out.println("value is fand in");
        }
        System.out.println("---------" );
        System.out.println("object is found" + ht_in.get(key));
        System.out.println("-----------" );
        if(ht_in.get(key) == null) {
            System.out.println("object is not found"); //正常输出
        } else {
            System.out.println("object is found" + ht_in.get(key)); //未输出
        }
    }
}
class Key implements Serializable {
    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
} 

修正办法

在Key类中覆写hashcode()方法,即可解决这个问题。

public class Solution1 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Hashtable<Key,String> ht = new Hashtable<Key,String>();
        Key key = new Key(5);
        ht.put(key,"value");
        System.out.println("Entry:" + ht.get(key));

        FileOutputStream fos = new FileOutputStream(new File("hashtabel.ser"));
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        oos.writeObject(ht);
        oos.flush();
        oos.close();

        FileInputStream fis = new FileInputStream(new File("hashtabel.ser"));
        ObjectInputStream ois = new ObjectInputStream(fis);
        Hashtable<Key,String> ht_in = (Hashtable<Key,String>)ois.readObject();
        ois.close();
        if(ht_in.contains("value")) {
            System.out.println("value is fand in");
        }
        System.out.println("---------" );
        System.out.println("object is found" + ht_in.get(key));
        System.out.println("-----------" );
        if(ht_in.get(key) == null) {
            System.out.println("object is not found"); //未输出
        } else {
            System.out.println("object is found" + ht_in.get(key)); //正常输出
        }

    }

}
class Key implements Serializable {
    //Does not override hashCode()
    private int num;
    Key(int num){
        this.num = num;
    }

    @Override
    public int hashCode() {
        return 31 * num;
    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof Key)){
            return false;
        }
        return ((Key) obj).num == num;
    }
} 

3.定义了equals()方法的类必须定义hashCode()方法

简介

覆写了Object.equals()方法的类必须同时覆写Object.hashCode()方法。java.lang.Object类要求当两个对象用equals()方法进行比较并得到等同的结果时,对这两个对象调用hashCode()方法时必须产生一样的整数结果。equal()方法用于判定两个对象实例逻辑上的等同性。因此对于所有等同的对象,hashCode()方法必须返回相同的数值。没能遵守这一合约是一个常见的产生错误地原因

错误示例一

public class Solution1 {
    private final int number;

    public Solution1(int number) {
        this.number = number;
    }
    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Solution1)) {
            return false;
        }

        return ((Solution1) o).number == number;
    }

    public static void main(String[] args) {
        Map<Solution1,String> m = new HashMap<Solution1, String>();
        m.put(new Solution1(100),"sssssss");
        System.out.println(m.get(new Solution1(100))); //输出为null
    }
} 

问题说明

造成这一错误行为的原因是CreditCrad类覆写了equals()方法,但没有覆写hashCode()方法。默认的hashCode()方法对不同的对象返回一个不同的数值。

修正办法

public class Solution1 {
    private final int number;

    public Solution1(int number) {
        this.number = number;
    }
    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Solution1)) {
            return false;
        }

        return ((Solution1) o).number == number;
    }
    
 	@Override
	public int hashCode() {
		int result = 17;
		result = 30 * result + number;
		return result;
	}

    public static void main(String[] args) {
        Map<Solution1,String> m = new HashMap<Solution1, String>();
        m.put(new Solution1(100),"sssssss");
        System.out.println(m.get(new Solution1(100))); //输出为 sssssss
    }
} 

本文地址:https://blog.csdn.net/weixin_40563850/article/details/107620292