Object类是所有类的超类,也就是说,Java中的每一个类都是由Object扩展而来的。因而每当你创建一个对象,它都将拥有Object类中的全部方法。让我们先来看看java.lang.Object的中的主要方法有哪些:
public class Object{
//公共构造函数
public Object();
//公共实例方法
public boolean equals(Object obj);
public native int hashCode();
public final native Class getClass();
public String toString();
public final native void notify();
public final native void notifyAll();
public final void wait() throws InterruptedException;
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException;
//保护实例方法
protected native Object clone();
protected void finalize() throws Throwable;
}
其中,方法equals测试的是两个对象是否相等,方法clone进行对象拷贝,方法getClass返回和当前对象相关的Class对象,方法notify,notifyall,wait都是用来对给定对象进行线程同步的。
对于"=="方法与equals()方法的区别中,我们首先来看一下Object类中的这个两个方法是如何定义的:
public boolean equals(Object obj) {
return (this == obj);
}
不难看出,它仅仅判断了两个对象的引用是否相等,如果引用指向同一内存对象,则为true,这在很多情况下并没有太大的实际意义。
所以,在Object类中equals()方法与"=="是等效的。
java语言规范要求equals方法具有以下性质:
自反性:对于任何非空引用x, x.equals(x)返回true。
对称性:对于任何非空引用x和y, 当且仅当y.equals(x)返回true时,x.equals(y)返回true。
传递性:对于任何引用x,y和z,如果x.equals(y)返回true并且y.equals(z)也返回true,那么x.equals(z)应该返回true。
一致性:如果x和y引用的对象没有改变,那么x.equals(y)的重复调用应该返回同一结果。
对于任何非空引用x, x.equals(null)应该返回false。
这5条规则显示良好的逻辑性,想要写好自己的equals方法,必须满足它们。那么如何才能做到这些规则呢?
假设当前equals方法传进来的参数名为otherObject,
测试this是否与otherObject相等。
测试otherObject是否为null,如果是,一定要返回false。
测试this通otherObject是否同属于一个类。这是为了满足规则2。
把 otherObject强制转换为另一个变量(这里称为other):Classname other = (Classname) otherObject。然后比较所有的字段。使用 == 比较基本类型字段,使用equals方法比较对象字段。如果所有的字段都匹配返回true,否则返回false。
下面举一个简单的例子:
class TestEqual{
int number;
String s;
public boolean equals(Object otherObject){
//首先看看这两个对象引用是否相等
if (this == otherObject)
return true;
//这是为了满足规则5
if(otherObject == null)
return false;
//如果两个对象所属类型不同,它们不可能相等
if(getClass() != otherObject.getClass())
return false;
TestEqual other = (TestEqual)otherObject;
//比较所有字段
return s.equals(other.s) && number == other.number;
}
}
这个例子虽然很简单,但却清晰地反映出了以上所说的要点。
还有一个需要注意的地方是,在子类中,首先要调用超类的equals方法,如果这项测试无法通过,那么两个对象不可能相等。也就是:
例如
public class TestEqualSub extends TestEqual{
public boolean equals(Object otherObject)
{
if (!super.equals(otherObject)) return false;
// super.equals checked that this and otherObject belong to the same class
TestEqualSub other = (TestEqualSub) otherObject;
return s.equals(other.s) && number == other.number;
}
}
到这里相信大家已经对编写自己的equals方法有了一定的认识,只要在平时写程序的时候多注意一下,写好它并不难。
再来看看本文的第二大主题:
如何编写自己的clone方法
类 似equals方法,我们先来讨论一下Object的clone方法效果是怎样的。不过在此之前,有个问题要提一下,所有使用clone方法的类,不论是 继承Object.clone()还是覆盖它,都必须实现一个名为cloneable的接口。如果你打开java类库查一下,会发现这个接口里什么也没 有,它仅仅是表明某个类具有被clone的能力。
用一个例子来研究一下Object.clone()的复制效果:
public class TestClone1 implements Cloneable{
int count;
TestClone1 next;
public TestClone1(int count) {
this.count=count;
if(count>0)
next=new TestClone1(count-1);
}
void add(){
count++;
if(next!=null)
next.count++;
}
public String toString(){
String s=String.valueOf(count)+" ";
if(next!=null)
s+=next.toString();
return s;
}
public Object clone(){
Object o=null;
//如果没有实现cloneable,将会抛出CloneNotSupported异常
try{
o=super.clone();
}
catch(CloneNotSupportedException e){
System.err.println("cannot clone");
}
return o;
}
public static void main(String[] args){
TestClone1 t=new TestClone1(1);
System.out.println("t="+t);
TestClone1 t1=(TestClone1)t.clone();
System.out.println("t1="+t1);
t.add();
System.out.println("after added\nt t="+t+"\nt1="+t1)
}
}
在这个例子中创建t相当于两个相连的TestClone1实例,而在调用了t的add方法之后,意想不到的结果出现了:
t=1 0
t1=1 0
after added
t t=2 1
t1=1 1
t1 也发生了改变,这点也许有些出乎你的意料。实际上Object.clone()进行的复制有着"bitwise"原则,也就是逐位复制。对于一个对象中定 义的对象,它只是简单的复制这个对象的引用。这也就是常说的浅层拷贝(shallow copy),明白了这一点,想要执行深层拷贝(deep copy)也就不难了。
只需要在TestClone1 t1=(TestClone1)t.clone();后面加上t1.next=(TestClone1)t.next.clone();就能得到:
t=1 0
t1=1 0
after added
t t=2 1
t1=1 0
这个正确的结果。
接下来要介绍的是,如何控制clone能力。从前面可以知道,clone()是protected的,你必须覆盖并实现cloneable接口并处理必要的异常才能使用它。这样,你在设计自己的类时,有以下几种风格来控制clone能力:
不理会clone(),也就是在你的类中不涉及任何有关clone()的内容,如果有人想实现clone功能,必须写一个子类并完成刚才所说的要求。这适合于Object.clone()可以胜任复制你的类中全部字段的情况。
支持clone()。你在你的类中实现cloneable接口并且覆盖clone方法以及捕获相应的异常。
有 条件的支持clone()。这种情况有些特殊,也就是你的类中保存着一些可能不能被复制的对象的引用(这里是指它们没有实现cloneable)。这时候 你只是在clone()中复制所有这些对象,如果遇到异常,抛出所有这些异常给使用你的类的人。举个例子,假设你在写一个类似于ArrayList的类, 你不知道别人会在把什么样的对象保存在你的ArrayList里,所以你也不知道他们是否能够被复制。
不实现cloneable接口但覆盖clone方法为protected。这样你虽然让你的类不能被复制,但却提供了正确的clone方法,这样如果有人想复制你的类,写一个子类实现cloneable接口就行了。
不实现cloneable接口并覆盖clone方法直接抛出异常来防止你的类被复制。不过这并不是根本的解决方法,只能对付那些直接调用你的clone方法或是在子类中调用super.clone()的人。
使用final修饰你的类来防止你的类被复制。如果你的超类中有覆盖clone方法的,再重新覆盖clone方法并直接抛出异常。这也是最彻底的办法。
分享到:
相关推荐
其次,Object类是实现Java泛型的基础,Java中的泛型是一种提供给Java程序员们使用的编程技术,它允许程序员们编写出使用一种或多种类型作为参数、返回结果或变量的类、接口以及方法,并且可以在运行时进行类型安全性...
object-c编程实例,主要介绍如果用object-c编写计算器
要求覆盖基类Object中的ToString()方法和Equals()方法,使得直接输出Student对象时输出的是对象的id,name和age信息;并且当两个对象的学号相同时认为它们相等; 然后写一个主方法测试以上定义。
这程序应用了MapObject,对Shp文件实现了添加,放大,缩小,鹰眼图,还有DragFeedback等功能。
7. Object-C的description方法 8. Object-C的异常处理 9. id类型 10. 类的继承 11. 动态判定与选择器 12. 类别Category 13. 协议@protocol 14. 内存管理 15. 常用的类型 16. 写入和读取属性 17. 对象的...
一款用Object-C语言编写的视频播放器框架
本文件用于iOS object-c生成辣鸡代码,使用Python编写的工具。可以根据自己想要的内容进行修改。
用图像平铺形状程序(C#源代码编写)private void Form1_Paint(object sender, PaintEventArgs e) { Image image = new Bitmap("..\\..\\test.bmp"); TextureBrush tBrush = new TextureBrush(image); tBrush.Wrap...
在JavaScript程序编写过程中,根据不同的上下文,JS会自动将object转换成number或者string后再处理。这种自动转换的规则如下: object自动转换成string的规则: 1.如果object所属类覆写了toString()方法,则调用该...
delphi7版本的X-SuperObject, 超简单,超好用,使用json于数据交换,大大方便程序代码的编写。
介绍该库基于UIAlertViewController,是在Object-C或Swift项目中使用AlertView和ActionSheet的一种简便方法。 ]用法: 在仓库文件中添加仓库使用pod'HLAlert'或将库拖到您的项目文件夹中使用Object-C 导入标题 #...
automatic_system 利用PageObject分类设计模式,pytest框架,编写自动化测试脚本
另一种是qt5后官方推荐的方法,即创建一个Object继承Qobject类,将自己要在线程里实现的方法和对象,在该类中定义。然后在主线程里实例化一个QThread对象,利用Qobject类的moveToThread方法,将自己创建的Object类都...
这是 Kotlin 语言编写的 Android 应用程序中的 MainActivity 类,其中声明了一个名为 nativeMethod 的本地方法。该方法会在点击 sampleText 视图时被调用,从而触发 native 方法的执行。在 companion object 中还...
掌握Object类中equals方法和toString方法的覆盖方法。 二、实验内容 1、设计一个名为figure的图形软件包(package)。包中包含三角形、矩形、圆三个类。要求:(1)每个类都要构造方法并为成员设置get和set方法;(2...
其中Java Application至少有一个主类,这个类中包含一个名为 的方法 7、 JDK下解释执行Java的程序是 。 8、 语句如下: int[] c1=int[10]; int[] c2={1,2,3,4,5,6,7,8,9,0}; 数组c1中的元素有 个;...
教你如何编写面向对象的C程序. object oriented C
通过跟随博客,读者可以了解Object-C的基本概念、特点和应用场景,学会如何编写简单的Object-C程序、使用高级特性、参与相关社区,并为未来的深入学习打下坚实的基础。 ### 其他说明 本博客注重实用性和易懂性,尽量...
适合java初学者学习, 封装:就是把数据和...Class类:object类中的getclass方法返回class类型的一个实例,程序启动时包含在main方法的类会被加载,虚拟机要加载他需要的所有类,每一个加载的类都要加载它需要的类。
用 Object Pascal 编写的差分进化库。通过使用差分进化 (DE),可以通过尝试改进关于给定质量度量的候选解决方案来迭代优化问题。