当前位置: 移动技术网 > IT编程>开发语言>Java > java安全编程规范标准

java安全编程规范标准

2020年07月31日  | 移动技术网IT编程  | 我要评论



一、方法规范

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网