简介
java程序的逻辑是由一个个的办法组成的,而在编写办法的过程中,咱们也须要恪守肯定的平安规定,比方办法的参数进行校验,不要在assert中增加业务逻辑,不要应用废除或者过期的办法,做安全检查的办法肯定要设置为private等。
明天咱们再来深刻的探讨一下,java办法的编写过程中还有哪些要留神的中央。
不要在构造函数中调用能够被重写的办法
一般来说在构造函数中只能调用static,final或者private的办法。为什么呢?
如果父类在执行构造函数的时候调用了一个能够被重写的办法,那么在该办法中可能会应用到未初始化的数据,从而导致运行时异样或者意外完结。
另外,还可能到办法获取到未初始化结束的实例,从而导致数据不一致性。
举个例子,咱们定义了一个Person的父类:
public class Person { public void printValue(){ System.out.println("this is person!"); } public Person(){ printValue(); }}
而后定义了一个Boy的子类,然而在Boy子类中,从新了父类的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(); }}
输入后果:
this is person!this is Boy!
能够看到Boy调用了本人重写过的printValue办法。
留神,这里并不是说会产生语法错误,而是这样会导致业务逻辑看起来十分凌乱。
怎么解决呢?简略方法就是将Person中的printValue置位final即可。
不要在clone()办法中调用可重写的办法
同样的,咱们在定义clone办法的时候也不要调用可重写的办法,否则也会产生意想不到的变动。
还是下面的例子,这次咱们增加了clone办法到Person类:
public Object clone() throws CloneNotSupportedException { Person person= (Person)super.clone(); person.printValue(); return person; }
接下来咱们增加clone办法到Boy类:
public Object clone() throws CloneNotSupportedException { Boy clone = (Boy) super.clone(); clone.printValue(); return clone; }
因为在clone办法中调用了可重写的办法,从而让零碎逻辑变得凌乱。不举荐这样应用。
重写equals()办法
考虑一下父类和子类的状况,如果在父类中咱们定义了一个equals办法,这个办法是依据父类中的字段来进行比拟判断,最终决定两个对象是否相等。
如果子类增加了一些新的字段,如果不重写equals办法,而是应用父类的equals办法,那么就会脱漏子类中新增加的字段,最终导致equals返回意想不到的后果。
所以一般来说,子类须要重写equals办法。
如果从新equals办法,须要满足上面几个个性:
- reflexive反射性
对于一个Object a来说,a.equals(a)必须成立。
- symmetric对称性
对于一个Object a和Object b来说,如果a.equals(b)==true,那么b.equals(a)==true肯定成立。
- transitive传递性
对于Object a,b,c来说,如果a.equals(b)==true,b.equals(c)==true,那么a.equals(c)==true肯定成立。
- consistent一致性
对于Object a,b来说,如果a和b没有产生任何变动,那么a.equals(b)的后果也不能变。
- 对于非空的援用a,a.equals(null) 肯定要等于false
具体代码的例子,这里就不写了,大家能够自行练习一下。
hashCode和equals
hashCode是Object中定义的一个native办法:
@HotSpotIntrinsicCandidate public native int hashCode();
依据Oracle的倡议,如果两个对象的equals办法返回的后果是true,那么这两个对象的hashCode肯定要返回同样的int值。
为什么呢?
咱们看下上面的一个例子:
public class Girl { private final int age; public Girl(int age) { this.age = age; } @Override public 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办法,然而并没有重写hashCode,最初返回的后果是null。
因为咱们new了两次Girl这个对象,最初导致native办法中两个不同对象的hashCode是不一样的。
咱们能够给Girl类中增加一个hashCode办法:
public int hashCode() { return age; }
这样就能够返回正确的值。
compareTo办法的实现
咱们在实现可比拟类的时候,通常须要实现Comparable接口。Comparable接口定义了一个compareTo办法,用来进行两个对象的比拟。
咱们在实现compareTo办法的时候,要留神保障比拟的通用规定,也就是说,如果x.compareTo(y) > 0 && y.compareTo(z) > 0 那么示意 x.compareTo(z) > 0.
所以,咱们不能应用compareTo来实现非凡的逻辑。
最近看了一个日本的电影,叫做dubo默示录,外面有一集就是石头,剪刀,布来判断输赢。
当然,石头,剪刀,布不满足咱们的通用compareTo办法,所以不能将逻辑定义在compareTo办法中。
本文的代码:
learn-java-base-9-to-20/tree/master/security
本文已收录于 http://www.flydean.com/java-security-code-line-method/最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!