Java中Object用法详解

目录
  • 一. Object简介
    • 1. 简介
  • 二. 常用方法
    • 1. clone()方法
      • 1.1 clone方法作用
      • 1.2 clone源码分析
      • 1.3 Java的浅克隆与深克隆
    • 2. hashCode()方法
      • 2.1 简介
      • 2.2 hash值
      • 2.3 案例
    • 3. equals(obj)方法
      • 3.1 equals简介
      • 3.2 使用原则
      • 3.3 基本特性
      • 3.4 案例
    • 4. getClass()方法
      • 4.1 简介
      • 4.2 案例
    • 5. toString()方法
      • 5.1 简介
      • 5.2 案例
    • 6. wait()、wait(long)、wait(long,int)、notify()、notifyAll()方法
    • 7. finalize()方法
      • 7.1 简介
      • 7.2 案例
  • 三. 结语

一. 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的资料请关注我们其它相关文章!

(0)

相关推荐

  • java之Object类用法实例

    本文实例讲述了java中Object类用法.分享给大家供大家参考.具体如下: 1.Object类是所有java类的基类 如果在类的声明中未使用extends关键字指明其基类,则默认基类为Object类,ex: public class Person{ ~~~~~ } 等价于 public class Person extends Object{ ~~~~~ } 2.Object类之equals方法 ①.Object类中定义有: public boolean equals(Object obj)方

  • Java Objects工具类原理及用法详解

    Objects工具类 jdk 1.7引进的工具类,都是静态调用的方法,jdk 1.8新增了部分方法 重点方法 equals 用于字符串和包装对象的比较,先比较内存地址,再比较值 deepEquals 数组的比较,先比较内存地址,再比较值,如String.char.byte.int数组,或者包装类型Integer等数组 hashCode 返回对象的hashCode,若传入的为null,则返回0 hash 传入可变参数的所有值得hashCode的总和,底层用Arrays.hashCode 可变参数

  • 一文带你认识Java中的Object类和深浅拷贝

    目录 前言 一.初识Object类 1.Object类接收所有子类实例 2.Object类部分方法介绍 ①.Object内的toString方法 ②.Object内的equals和hashCode方法 ③.Object类的getClass方法 ④.Object类的clone方法 二.认识深拷贝和浅拷贝 1.什么是深浅拷贝? 2.实现深拷贝 三.Object类和深浅拷贝总结 前言 本文介绍了Object类以及Object类部分方法,toString方法,equals和hashCode方法(重写前和

  • Java中的Object类用法总结

    目录 1.Object类是什么? 2.Object类中的equals方法 3.Object类中的hashCode方法 4.编译器自动生成equals和hashCode 总结 1.Object类是什么?

  • java如何将Object数组转换为指定类型数组

    目录 将Object数组转换为指定类型数组 1.转换函数 2.测试main函数 3.实体类 将Object转换为数组的情况 将Object数组转换为指定类型数组 1.转换函数     public static <T> T[] convertArray(Class<T> targetType, Object[] arrayObjects) {         if (targetType == null) {             return (T[]) arrayObject

  • java中JsonObject与JsonArray转换方法实例

    目录 备忘一下,首先 JsonArray转换为JsonObject JsonArrayStr 转换为 JsonObjectStr 补充:java中JSONObject和JSONArray解析 总结 备忘一下,首先 这是一个JsonArrayStr,他可以转换为JsonArray. [{"name":"a1"},{"name":"a2"}] 这是一个JsonObjectStr,他可以转换为JsonObject. {"r

  • Java中SimpleDateFormat用法详解

    public class SimpleDateFormat extends DateFormat SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (date -> text).语法分析 (text -> date)和标准化. SimpleDateFormat 允许以为日期-时间格式化选择任何用户指定的方式启动. 但是,希望用 DateFormat 中的 getTimeInstance. getDateInstance 或 getDateTime

  • Java中DecimalFormat用法详解

    我们经常要将数字进行格式化,比如取2位小数,这是最常见的.Java 提供DecimalFormat类,帮你用最快的速度将数字格式化为你需要的样子.下面是一个例子: importjava.text.DecimalFormat; public class TestNumberFormat{ public static void main(String[]args){ doublepi=3.1415927; //圆周率 //取一位整数 System.out.println(newDecimalForm

  • Java 中 Reference用法详解

    Java  Reference详解 在 jdk 1.2 及其以后,引入了强引用.软引用.弱引用.虚引用这四个概念.网上很多关于这四个概念的解释,但大多是概念性的泛泛而谈,今天我结合着代码分析了一下,首先我们先来看定义与大概解释(引用类型在包 Java.lang.ref 里). 1.强引用(StrongReference) 强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型.举个例子来说: Object obj = new Object(); 这里的obj引用便是一个强引

  • java中BigDecimal用法详解

    首先,学习一个东西,我们都必须要带着问题去学,这边我分为 [为什么?][是什么?][怎么用?] [为什么要用BigDecimal?] 首先,我们先看一下,下面这个现象 那为什么会出现这种情况呢? 因为不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度. 注:根本原因是:十进制值通常没有完全相同的二进制表示形式;十进制数的二进制表示形式可能不精确.只能无限接近于那个值 但是,在项目中,我们不可能让这种情况出现,特别是金融项目,因为涉及金额的计算都必须十分精确

  • Java中Socket用法详解

    目录 1 问题引入 1.1 网络架构模型 1.1.1 OSI参考模型 1.1.2 TCP/IP五层模型 1.1.3 各协议层的说明 1.2 网络编程中的问题 1.3 TCP协议与UDP协议 1.3.1 TCP 1.3.2 UDP 1.3.3 TCP和UDP的区别 2 socket网络编程 2.1什么是socket? 2.2 Socket的原理 3 基于java的socket网络编程实现 3.2 基于UDP的socket实现 1 问题引入 1.1 网络架构模型 网络架构模型主要有OSI参考模型和T

  • java.text.DecimalFormat用法详解

    简要 DecimalFormat 的 pattern 都包含着 正负子 pattern ,例如 "#,##0.00;(#,##0.00)": /** * Created by Shuai on 2016/7/11. */ public class Main { public static void main(String[] args) { // 正值 BigDecimal bigDecimal = BigDecimal.valueOf(-12211151515151.541666);

  • Java RandomAccessFile的用法详解

    RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫

  • Java中final关键字详解及实例

    final在Java中可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,如果你试图将变量再次初始化的话,编译器会报编译错误.  final的含义在不同的场景下有细微的差别,但总体来说,它指的是"不可变". 1. final变量 凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为final的都叫作final变量.final变量经常和static关键字一起使用,作为常量.用final关键字修饰的变量,只能进行一次赋值操作

  • Python之Class&Object用法详解

    类和对象的概念很难去用简明的文字描述清楚.从知乎上面的一个回答中可以尝试去理解: 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为.例如,一条狗是一个对象,它的状态有:颜色.名字.品种:行为有:摇尾巴.叫.吃等. 类:类是一个模板,它描述一类对象的行为和状态. 我觉得有一本书对这个类与对象描述的特别好:Head First Java第2版中文版,大家可以通过Java去学习类和对象. class class是用来定义类的.类在面向对象编程里面是很有用的,能够大大提升开发效率和代码维护性

  • java Beanutils.copyProperties( )用法详解

    这是一篇开发自辩甩锅稿~~~~ 昨天测试小姐姐将我的一个bug单重开了,emmmm....内心OS:就调整下对象某个属性类型这么简单的操作,我怎么可能会出错呢,一定不是我的锅!!but再怎么抗拒,bug还是要改的,毕竟晚上就要发版本了~~ 老老实实将我前天改的部分跟了一遍,恩,完美,没有任何的缺失~~but本应success的测试数据,接口返还的结果确实是false来着,那还是老老实实debug吧. 一步步跟下来,恩,多么顺畅,就说一定不是我的锅~~诶?不对不对,这里的ID值,为啥是null?传

随机推荐

其他