构造代码块、equals
来源:互联网 发布:中国自然灾害数据库 编辑:程序博客网 时间:2024/06/06 11:38
构造代码块
在类中直接定义没有任何修饰符、前缀、后缀的代码块即为构造代码块。我们明白一个类必须至少有一个构造函数,构造函数在生成对象时被调用。构造代码块和构造函数一样同样是在生成一个对象时被调用,那么构造代码在什么时候被调用?如何调用的呢?看如下代码:
public class Test { /** * 构造代码 */ { System.out.println("执行构造代码块..."); } /** * 无参构造函数 */ public Test(){ System.out.println("执行无参构造函数..."); } /** * 有参构造函数 * @param id id */ public Test(String id){ System.out.println("执行有参构造函数..."); }}
上面定义了一个非常简单的类,该类包含无参构造函数、有参构造函数以及构造代码块,同时在上面也提过代码块是没有独立运行的能力,他必须要有一个可以承载的载体,那么编译器会如何来处理构造代码块呢?编译器会将代码块按照他们的顺序(假如有多个代码块)插入到所有的构造函数的最前端,这样就能保证不管调用哪个构造函数都会执行所有的构造代码块。上面代码等同于如下形式:
public class Test { /** * 无参构造函数 */ public Test(){ System.out.println("执行构造代码块..."); System.out.println("执行无参构造函数..."); } /** * 有参构造函数 * @param id id */ public Test(String id){ System.out.println("执行构造代码块..."); System.out.println("执行有参构造函数..."); }}
public static void main(String[] args) { new Test(); System.out.println("----------------"); new Test("1"); }------------Output:执行构造代码块...执行无参构造函数...----------------执行构造代码块...执行有参构造函数...
从上面的运行结果可以看出在new一个对象的时候总是先执行构造代码,再执行构造函数,但是有一点需要注意构造代码不是在构造函数之前运行的,它是依托构造函数执行的。正是由于构造代码块有这几个特性,所以它常用于如下场景:
1、 初始化实例变量
如果一个类中存在若干个构造函数,这些构造函数都需要对实例变量进行初始化,如果我们直接在构造函数中实例化,必定会产生很多重复代码,繁琐和可读性差。这里我们可以充分利用构造代码块来实现。这是利用编译器会将构造代码块添加到每个构造函数中的特性。 2、 初始化实例环境 一个对象必须在适当的场景下才能存在,如果没有适当的场景,则就需要在创建对象时创建此场景。我们可以利用构造代码块来创建此场景,尤其是该场景的创建过程较为复杂。构造代码会在构造函数之前执行。 上面两个常用场景都充分利用构造代码块的特性,能够很好的解决在实例化对象时构造函数比较难解决的问题,利用构造代码不仅可以减少代码量,同时也是程序的可读性增强了。特别是当一个对象的创建过程比较复杂,需要实现一些复杂逻辑,这个时候如果在构造函数中实现逻辑,这是不推荐的,因为我们提倡构造函数要尽可能的简单易懂,所以我们可以使用构造代码封装这些逻辑实现部分。
java equals
在Java规范中,它对equals()方法的使用必须要遵循如下几个规则:
equals 方法在非空对象引用上实现相等关系:
1、自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。 2、对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。 3、传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。 4、一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。 5、 对于任何非空引用值 x,x.equals(null) 都应返回 false。 对于上面几个规则,我们在使用的过程中最好遵守,否则会出现意想不到的错误。 在java中进行比较,我们需要根据比较的类型来选择合适的比较方式: 1) 对象域,使用equals方法 。 2) 类型安全的枚举,使用equals或== 。 3) 可能为null的对象域 : 使用 == 和 equals 。 4) 数组域 : 使用 Arrays.equals 。 5) 除float和double外的原始数据类型 : 使用 == 。 6) float类型: 使用Float.foatToIntBits转换成int类型,然后使用==。 7) double类型: 使用Double.doubleToLongBit转换成long类型,然后使用==。
至于6)、7)为什么需要进行转换,我们可以参考他们相应封装类的equals()方法,下面的是Float类的:
public boolean equals(Object obj) { return (obj instanceof Float) && (floatToIntBits(((Float)obj).value) == floatToIntBits(value)); }原因嘛,里面提到了两点:However, there are two exceptions:If f1 and f2 both representFloat.NaN, then the equals method returnstrue, even though Float.NaN==Float.NaNhas the value false.If <code>f1 represents +0.0f whilef2 represents -0.0f, or viceversa, the equal test has the valuefalse, even though 0.0f==-0.0fhas the value true.
在equals()中使用getClass进行类型判断
我们在覆写equals()方法时,一般都是推荐使用getClass来进行类型判断,不是使用instanceof。我们都清楚instanceof的作用是判断其左边对象是否为其右边类的实例,返回boolean类型的数据。可以用来判断继承中的子类的实例是否为父类的实现。注意后面这句话:可以用来判断继承中的子类的实例是否为父类的实现,正是这句话在作怪。我们先看如下实例(摘自《高质量代码 改善java程序的151个建议》)。
父类:Personpublic class Person { protected String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name){ this.name = name; } public boolean equals(Object object){ if(object instanceof Person){ Person p = (Person) object; if(p.getName() == null || name == null){ return false; } else{ return name.equalsIgnoreCase(p.getName()); } } return false; }} 子类:Employeepublic class Employee extends Person{ private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public Employee(String name,int id){ super(name); this.id = id; } /** * 重写equals()方法 */ public boolean equals(Object object){ if(object instanceof Employee){ Employee e = (Employee) object; return super.equals(object) && e.getId() == id; } return false; }}
上面父类Person和子类Employee都重写了equals(),不过Employee比父类多了一个id属性。测试程序如下:
public class Test { public static void main(String[] args) { Employee e1 = new Employee("chenssy", 23); Employee e2 = new Employee("chenssy", 24); Person p1 = new Person("chenssy"); System.out.println(p1.equals(e1)); System.out.println(p1.equals(e2)); System.out.println(e1.equals(e2)); }}
上面定义了两个员工和一个普通人,虽然他们同名,但是他们肯定不是同一人,所以按理来说输出结果应该全部都是false,但是事与愿违,结果是:true、true、false。 对于那e1!=e2我们非常容易理解,因为他们不仅需要比较name,还需要比较id。但是p1即等于e1也等于e2,这是非常奇怪的,因为e1、e2明明是两个不同的类,但为什么会出现这个情况?首先p1.equals(e1),是调用p1的equals方法,该方法使用instanceof关键字来检查e1是否为Person类,这里我们再看看instanceof:判断其左边对象是否为其右边类的实例,也可以用来判断继承中的子类的实例是否为父类的实现。他们两者存在继承关系,肯定会返回true了,而两者name又相同,所以结果肯定是true。 所以出现上面的情况就是使用了关键字instanceof,这是非常容易“专空子”的。故在覆写equals时推荐使用getClass进行类型判断。而不是使用instanceof。
在使用getClass是是需要进行null判断。 if(o == null || o.getClass() != getClass())
- 构造代码块、equals
- 构造块/静态代码块
- 构造函数、构造代码块
- 构造函数、构造代码块
- 构造函数、构造代码块
- 构造代码块
- 构造代码块
- 构造代码块
- 构造代码块
- 构造代码块
- java构造代码块
- 构造代码块
- java-构造代码块
- 构造代码块
- 构造代码块笔记
- 构造代码块
- java构造代码块
- 普通代码块 静态块 构造块
- Android Contxt上下文
- 5-7 六度空间
- 用户界面框架jQuery EasyUI示例大全之TreeGrid
- 读书感悟1
- 耦合
- 构造代码块、equals
- Bat批处理Java程序,简单好用
- 破解QQ空间访问权限神器-2016版破解器
- 动态规划趣味讲解
- HDU 5610 Baby Ming and Weight lifting(水~)
- 免费的端口转发工具
- Qt中指针异常问题解决
- VC 分割窗口发送消息给子窗口
- redis主从复制