java安全编码指南之:方法编写指南
文章目錄
- 簡(jiǎn)介
- 不要在構(gòu)造函數(shù)中調(diào)用可以被重寫(xiě)的方法
- 不要在clone()方法中調(diào)用可重寫(xiě)的方法
- 重寫(xiě)equals()方法
- hashCode和equals
- compareTo方法的實(shí)現(xiàn)
簡(jiǎn)介
java程序的邏輯是由一個(gè)個(gè)的方法組成的,而在編寫(xiě)方法的過(guò)程中,我們也需要遵守一定的安全規(guī)則,比如方法的參數(shù)進(jìn)行校驗(yàn),不要在assert中添加業(yè)務(wù)邏輯,不要使用廢棄或者過(guò)期的方法,做安全檢查的方法一定要設(shè)置為private等。
今天我們?cè)賮?lái)深入的探討一下,java方法的編寫(xiě)過(guò)程中還有哪些要注意的地方。
不要在構(gòu)造函數(shù)中調(diào)用可以被重寫(xiě)的方法
一般來(lái)說(shuō)在構(gòu)造函數(shù)中只能調(diào)用static,final或者private的方法。為什么呢?
如果父類(lèi)在執(zhí)行構(gòu)造函數(shù)的時(shí)候調(diào)用了一個(gè)可以被重寫(xiě)的方法,那么在該方法中可能會(huì)使用到未初始化的數(shù)據(jù),從而導(dǎo)致運(yùn)行時(shí)異常或者意外結(jié)束。
另外,還可能到方法獲取到未初始化完畢的實(shí)例,從而導(dǎo)致數(shù)據(jù)不一致性。
舉個(gè)例子,我們定義了一個(gè)Person的父類(lèi):
public class Person {public void printValue(){System.out.println("this is person!");}public Person(){printValue();} }然后定義了一個(gè)Boy的子類(lèi),但是在Boy子類(lèi)中,重新了父類(lèi)的printValue方法。
public class Boy extends Person{public void printValue(){System.out.println("this is Boy!");}public Boy(){super();}public static void main(String[] args) {Person persion= new Person();Boy boy= new Boy();} }輸出結(jié)果:
this is person! this is Boy!可以看到Boy調(diào)用了自己重寫(xiě)過(guò)的printValue方法。
注意,這里并不是說(shuō)會(huì)產(chǎn)生語(yǔ)法錯(cuò)誤,而是這樣會(huì)導(dǎo)致業(yè)務(wù)邏輯看起來(lái)非常混亂。
怎么解決呢?簡(jiǎn)單辦法就是將Person中的printValue置位final即可。
不要在clone()方法中調(diào)用可重寫(xiě)的方法
同樣的,我們?cè)诙xclone方法的時(shí)候也不要調(diào)用可重寫(xiě)的方法,否則也會(huì)產(chǎn)生意想不到的變化。
還是上面的例子,這次我們添加了clone方法到Person類(lèi):
public Object clone() throws CloneNotSupportedException {Person person= (Person)super.clone();person.printValue();return person;}接下來(lái)我們添加clone方法到Boy類(lèi):
public Object clone() throws CloneNotSupportedException {Boy clone = (Boy) super.clone();clone.printValue();return clone;}因?yàn)樵赾lone方法中調(diào)用了可重寫(xiě)的方法,從而讓系統(tǒng)邏輯變得混亂。不推薦這樣使用。
重寫(xiě)equals()方法
考慮一下父類(lèi)和子類(lèi)的情況,如果在父類(lèi)中我們定義了一個(gè)equals方法,這個(gè)方法是根據(jù)父類(lèi)中的字段來(lái)進(jìn)行比較判斷,最終決定兩個(gè)對(duì)象是否相等。
如果子類(lèi)添加了一些新的字段,如果不重寫(xiě)equals方法,而是使用父類(lèi)的equals方法,那么就會(huì)遺漏子類(lèi)中新添加的字段,最終導(dǎo)致equals返回意想不到的結(jié)果。
所以一般來(lái)說(shuō),子類(lèi)需要重寫(xiě)equals方法。
如果重新equals方法,需要滿足下面幾個(gè)特性:
對(duì)于一個(gè)Object a來(lái)說(shuō),a.equals(a)必須成立。
對(duì)于一個(gè)Object a和Object b來(lái)說(shuō),如果a.equals(b)==true,那么b.equals(a)==true一定成立。
對(duì)于Object a,b,c來(lái)說(shuō),如果a.equals(b)==true,b.equals?==true,那么a.equals?==true一定成立。
對(duì)于Object a,b來(lái)說(shuō),如果a和b沒(méi)有發(fā)生任何變化,那么a.equals(b)的結(jié)果也不能變。
具體代碼的例子,這里就不寫(xiě)了,大家可以自行練習(xí)一下。
hashCode和equals
hashCode是Object中定義的一個(gè)native方法:
@HotSpotIntrinsicCandidatepublic native int hashCode();根據(jù)Oracle的建議,如果兩個(gè)對(duì)象的equals方法返回的結(jié)果是true,那么這兩個(gè)對(duì)象的hashCode一定要返回同樣的int值。
為什么呢?
我們看下下面的一個(gè)例子:
public class Girl {private final int age;public Girl(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (o == this) {return true;}if (!(o instanceof Girl)) {return false;}Girl cc = (Girl)o;return cc.age == age;}public static void main(String[] args) {HashMap<Girl,Integer> hashMap= new HashMap<>();hashMap.put(new Girl(20), 20);System.out.println(hashMap.get(new Girl(20)));} }上面的Girl中,我們定義了equals方法,但是并沒(méi)有重寫(xiě)hashCode,最后返回的結(jié)果是null。
因?yàn)槲覀僴ew了兩次Girl這個(gè)對(duì)象,最后導(dǎo)致native方法中兩個(gè)不同對(duì)象的hashCode是不一樣的。
我們可以給Girl類(lèi)中添加一個(gè)hashCode方法:
public int hashCode() {return age;}這樣就可以返回正確的值。
compareTo方法的實(shí)現(xiàn)
我們?cè)趯?shí)現(xiàn)可比較類(lèi)的時(shí)候,通常需要實(shí)現(xiàn)Comparable接口。Comparable接口定義了一個(gè)compareTo方法,用來(lái)進(jìn)行兩個(gè)對(duì)象的比較。
我們?cè)趯?shí)現(xiàn)compareTo方法的時(shí)候,要注意保證比較的通用規(guī)則,也就是說(shuō),如果x.compareTo(y) > 0 && y.compareTo(z) > 0 那么表示 x.compareTo(z) > 0.
所以,我們不能使用compareTo來(lái)實(shí)現(xiàn)特殊的邏輯。
最近看了一個(gè)日本的電影,叫做dubo默示錄,里面有一集就是石頭,剪刀,布來(lái)判斷輸贏。
當(dāng)然,石頭,剪刀,布不滿足我們的通用compareTo方法,所以不能將邏輯定義在compareTo方法中。
本文的代碼:
learn-java-base-9-to-20/tree/master/security
本文已收錄于 http://www.flydean.com/java-security-code-line-method/
最通俗的解讀,最深刻的干貨,最簡(jiǎn)潔的教程,眾多你不知道的小技巧等你來(lái)發(fā)現(xiàn)!
歡迎關(guān)注我的公眾號(hào):「程序那些事」,懂技術(shù),更懂你!
超強(qiáng)干貨來(lái)襲 云風(fēng)專(zhuān)訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的java安全编码指南之:方法编写指南的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Web Storage API的介绍和使
- 下一篇: 看动画学算法之:递归和递归树