目录
- 一. object简介
- 二. 常用方法
- 1. clone()方法
- 2. hashcode()方法
- 3. equals(obj)方法
- 4. getclass()方法
- 5. tostring()方法
- 6. wait()、wait(long)、wait(long,int)、notify()、notifyall()方法
- 7. finalize()方法
- 三. 结语
一. object简介
1. 简介
在了解object中的常用方法之前,我们先来看看object类的源码,如下所示:
/** * class {@code object} is the root of the class hierarchy. * every class has {@code object} as a superclass. all objects, * including arrays, implement the methods of this class. * @author unascribed * @see java.lang.class * @since jdk1.0 */ public class object { ......
从object类的源码注释可以知道,object类是java中所有类的父类,相当于是java中的”万类之王“,处于最顶层。 所以在java中,所有的类默认都继承自object类。同时java中的所有类对象,包括数组,也都要实现这个类中的方法。
所以,object是java中所有类的父类、超类、基类,位于继承树的最顶层。可以说,任何一个没有显式地继承别的父类的类,都会直接继承object,否则就是间接地继承object,并且任何一个类也都会享有object提供的方法。又因为object是所有类的父类,所以基于多态的特性,该类可以用来代表任何一个类,允许把任何类型的对象赋给 object类型的变量,也可以作为方法的参数、方法的返回值。
二. 常用方法
在object类中,自带了几个常用的方法,这几个方法任意的子类都会继承,如下图所示:
根据上图,小编把object类中的常用方法归纳为这么几种:
构造方法;
hashcode()和equals()方法用来判断对象是否相同;
wait()、wait(long)、wait(long,int)、notify()、notifyall();
tostring()和getclass();
clone();
finalize()
接下来小编就给各位介绍object类中的几个常用方法,分别说一下这些方法的功能作用。
1. clone()方法
1.1 clone方法作用
object中有两个protected修饰的方法,其中一个就是clone()方法,并且该方法还是一个native方法。clone()方法用于创建复制出当前类对象的一个副本,得到一个复制对象。 所谓的复制对象,首先会分配一个和源对象(调用clone方法的对象)同样大小的内存空间,在这个内存空间中会创建出一个新对象;然后再使用源对象中对应的各个成员,填充新对象的成员,填充完成之后,clone方法会创建返回一个新的相同对象供外部引用。
1.2 clone源码分析
我们再看看clone()方法源码上的注释,如下图所示:
从这段注释中,我们可以了解到:
以x为蓝本创建出的副本,与x对象并不相同,这保证了克隆出的对象拥有单独的内存空间;
源对象和克隆的新对象字节码相同,它们具有相同的类类型,但这并不是强制性的;
源对象和克隆的新对象利用equals()方法比较时是相同的,但这也不是强制性的。
1.3 java的浅克隆与深克隆
因为每个类的直接或间接父类都是object,因此它们都含有clone()方法,但因该方法是protected修饰的,所以我们不能在类外访问该方法。但如果我们要对一个对象进行复制,可以对clone方法进行复写,而java中提供了两种不同的克隆方式,浅克隆(shallowclone) 和深克隆(deepclone)。
1.3.1 浅克隆
在浅克隆中,如果源对象的成员变量是值类型,则复制一份给克隆对象;如果源对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说源对象和克隆对象的成员变量指向相同的内存地址。
简单说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。我们可以用下图对浅克隆进行展示:
在java语言中,通过实现cloneable接口,默认覆盖object类的clone()方法就可以实现浅克隆。
1.3.2 深克隆
在深克隆中,无论源对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,即深克隆将源对象的所有引用对象也复制一份给克隆对象。
简单来说,在深克隆中,除了对象本身被复制外,对象中包含的所有成员变量也将复制。我们可以用下图对深克隆进行展示:
在java语言中,如果需要实现深克隆,可以通过实现cloneable接口,自定义覆盖object类的clone()方法实现,也可以通过序列化(serialization)等方式来实现。 如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。
2. hashcode()方法
2.1 简介
hashcode()是object中的一个native方法,也是所有类都拥有的一个方法,主要是返回每个对象十进制的hash值。hash值是由hash算法根据对象的地址、对象中的字符串、数字等计算出来的。一般情况下,相同的对象应会返回相同的哈希吗值,不同的对象会返回不同的哈希码值。
2.2 hash值
哈希值是根据地址值换算出来的一个值,并不是实际的地址值,常用于哈希表中,如hashmap、hashtable、hashset。关于哈希值,不同的jdk算法其实是不一样的:
- java 6、7 中会默认返回一个随机数;
- java 8 中默认通过和当前线程有关的一个随机数 三个确定值,运用marsaglia’s xorshift scheme的随机数算法得到的一个随机数。
2.3 案例
dog dog01=new dog("乔治01"); dog dog02=new dog("乔治02"); //两个对象的hash值是不同的 system.out.println("dog01的hash值 " dog01.hashcode()); system.out.println("dog02的hash值 " dog02.hashcode());
以上两个对象的hash值是不同的,表示这是不同的两个对象。
3. equals(obj)方法
3.1 equals简介
object中的equals方法用于判断this对象和obj本身的值是否相等,即用来判断调用equals方法的对象和形参obj所引用的对象是否是同一对象。 所谓同一对象,就是指两个对象是否指向了内存中的同一块存储单元地址。如果this和obj指向的是同一块内存单元地址,则返回true;如果this和obj指向的不是同一块内存单元地址,则返回false。如果没有指向同一内存单元,即便是内容完全相等,也会返回false。
object类的equals方法,其作用是比较两个对象是否相同,默认比较的是内存地址,其底层是通过==实现的。如果我们不想比较内存地址,那么就需要重写equals方法。默认的实现源码如下:
public boolean equals(object obj) { return (this == obj); }
我们知道,java中还有一个==运算符,也可以对两个对象进行比较。如果是基本数据类型,==比较的是它们的值是否相同;如果是引用数据类型,比较的是它们的内存地址是否相同。而equals()方法则是比较两个对象的内容是否相等。
3.2 使用原则
我们在使用equals()方法时,需注意下面这些原则:
(1).equals()只能处理引用类型变量;
(2).一般情况下,equals()方法比较的是两个引用类型变量的地址值是否相等;
(3).但是string类、基本类型包装类、file类、date类等,都重写了object类的equals()方法,比较是两个对象的"具体内容"是否相同。
3.3 基本特性
另外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。
3.4 案例
/** * @author 一一哥sun * 千锋教育 */ public class objecttest { public static void main(string[] args) { dog dog01=new dog("乔治01"); dog dog02=new dog("乔治02"); system.out.println("dog01对比dog02 " (dog01==dog02));//false //equals()方法的底层默认还是利用==实现的 system.out.println("dog01对比dog02 " (dog01.equals(dog02)));//false } }
从上面的案例中,我们也可以证明,equals()方法用于处理引用类型的变量,默认比较的是两个引用类型的变量地址是否相等。
4. getclass()方法
4.1 简介
getclass()方法可以用于获取对象运行时的字节码类型,得到该对象的运行时的真实类型。该方法属于java的反射机制,其返回值是class类型,例如 class c = obj.getclass();。
通过对象c,我们可以进一步获取该对象的所有成员方法,每个成员方法都是一个method对象。我们也可以获取该对象的所有成员变量,每个成员变量都是一个field对象。同样的,我们也可以获取该对象的构造函数,构造函数则是一个constructor对象。
4.2 案例
/** * @author 一一哥sun * 千锋教育 */ public class objecttest { public static void main(string[] args) { //判断运行时d对象和c对象是否是同一个类型 animal d = new dog(); animal c = new cat(); //方式1:通过instanceof关键字判断 if((d instanceof dog && c instanceof dog) ||(d instanceof cat && c instanceof cat)) { system.out.println("是同一个类型"); }else { system.out.println("不是同一个类型"); } //方式2:通过getclass方法判断 if(d.getclass() == c.getclass()) { system.out.println("是同一个类型"); }else { system.out.println("不是同一个类型"); } } }
从上面的代码案例中,我们可以得知,getclass方法用于返回该对象的真实类型(运行时的类型),可以根据对象的字节码来判断两个对象是否是同一个对象。
5. tostring()方法
5.1 简介
tostring()方法可以说是一个进行“自我描述”的方法,可以返回某个对象的字符串,当要输出某个实例对象的信息时,我们可以通过重写该方法来输出自我描述的信息。该方法通常只是为了方便输出本类的描述信息,比如执行system.out.println("xyz")
这样的日志语句。一般情况下,当程序要输出一个对象或者把某个对象和字符串进行连接运算时,系统就会自动调用该对象的tostring()方法返回该对象的字符串表示。
object类的tostring()方法会返回“运行时的类名@十六进制哈希码”格式的字符串,但很多类都重写了 object类的tostring()方法,用于返回可以表述该对象信息的字符串。
5.2 案例
/** * @author 一一哥sun * 千锋教育 */ public class dog implements animal{ private string name; public dog() {} public dog(string name) { this.name = name; } @override public void eat() { system.out.println("小狗" this.name "狗爱吃骨头"); } //@override //public string tostring() { //return "dog name= " name; //} } public class objecttest { public static void main(string[] args) { dog dog=new dog("乔治"); system.out.println("dog一号=" dog); system.out.println("dog二号=" dog.tostring()); } }
上述代码执行结果如下图所示:
从上面程序的运行结果可以发现,默认情况下,对象带不带tostring()方法,其最终的输出结果是一样的,即对象输出时一定会调用 object类中的 tostring()方法打印内容,所以我们可以利用此特性来通过 tostring()方法取得一些对象的信息。
6. wait()、wait(long)、wait(long,int)、notify()、notifyall()方法
这几个函数体现的是java的多线程机制,一般是结合synchronize语句使用。
- wait()用于让当前线程失去操作权限,当前线程进入等待序列;
- notify()用于随机通知一个持有对象的锁的线程获取操作权限;
- wait(long) 和wait(long,int)用于设定下一次获取锁的距离当前释放锁的时间间隔;
- notifyall()用于通知所有持有对象的锁的线程获取操作权限。
这几个方法我们后面在分析多线程的面试题时再细说,此处先仅做了解。
7. finalize()方法
7.1 简介
finalize()方法在进行垃圾回收的时候会用到,主要是在垃圾回收时,用于作为确认该对象是否确认被回收的一个标记。我们在使用finalize()方法时要注意:
- finalize方法不一定会执行,只有在该方法被重写的时候才会执行;
- finalize方法只会被执行一次;
- 对象可以在finalize方法中获得自救,避免自己被垃圾回收,同样的自救也只能进行一次;
- 不推荐java程序员手动调用该方法,因为finalize方法代价很大。
7.2 案例
为了测试出finalize()方法的作用,小编给大家设计了如下案例:
/** * @author 一一哥sun * 千锋教育 */ public class dog implements animal{ private string name; public dog() {} public dog(string name) { this.name = name; } @override public void eat() { system.out.println("小狗" this.name "狗爱吃骨头"); } //复写finalize方法 @override protected void finalize() throws throwable { super.finalize();//不要删除这行代码 system.out.println("finalize方法执行了"); } }
然后我们对dog对象进行回收测试:
public class objecttest { public static void main(string[] args) { dog dog=new dog("乔治"); //手动将对象标记为垃圾对象 dog = null; //触发垃圾回收器,回收垃圾对象 system.gc(); } }
要想确保finalize()方法的执行,我们首先需要在相关对象中重新finalize()方法,然后将待回收的对象手动标记为null,最后再手动调用gc()方法,这样才有可能确保finalize()方法一定执行。
三. 结语
至此,就把object类给大家介绍完毕了,这个类的内容并不是很难,主要是掌握几个常用的方法就可以了,尤其是equals()、hashcode()、tostring()、getclass()等方法。
以上就是java中object用法详解的详细内容,更多关于java object的资料请关注其它相关文章!