面试官考我Object类中的所有方法及场景使用?我...

news2024/10/6 16:24:39

  咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java 知识点啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~


🏆本文收录于「Java进阶实战」专栏,数多年Java开发老兵项目累计经验,专业攻坚指数级提升,助你一臂之力,早日实现财富自由🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!!

环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8

  前几日,有位女读者遇到了一个很常见却又不好答的棘手面试题,于是特地向我诉苦了一波,于此,我怎么能见女不救,正所谓救人一命胜造七级浮屠。在此,我们就一起来再来温故一波对象的鼻祖Object类,及它的所有方法及使用场景吧。

解读Object类

  在Java中,我们都知道,Object类是所有类的根类,它位于类层次结构的顶端。Object类提供了一些基本的方法,这些方法被继承到所有的类中。以下是Object类中定义的主要方法及其用法:

toString()

  1. toString() - 返回对象的字符串表示,通常用于打印对象的简要信息。
   Object obj = new Object();
   System.out.println(obj.toString()); 

默认实现会返回类名@哈希码,源码实现如下:


  如上段代码是Java中用于生成对象的字符串表示形式的常见方法之一。它在默认情况下返回一个由类名和对象的哈希码组成的字符串,格式为类名@哈希码

拓展一下:

  1. getClass().getName() 返回对象所属类的名称。
  2. Integer.toHexString(hashCode()) 将对象的哈希码转换为十六进制字符串表示。

  因此,toString() 方法返回的字符串将类名和对象的哈希码连接在一起,以 @ 符号分隔。这样的字符串并不是特别有用,因为它不提供对象的实际内容信息,但是它可以用于快速检查对象的标识。

示例演示:

equals(Object obj)

  1. equals(Object obj) - 用于比较两个对象是否相等。默认实现是比较对象的引用,即是否为同一个实例。
   Object obj1 = new Object();
   Object obj2 = obj1;
   Object obj3 = new Object();
   System.out.println(obj1.equals(obj2)); // true,因为obj1和obj2是同一个对象
   System.out.println(obj1.equals(obj3)); // false,因为obj1和obj3是不同的对象

示例演示如下:

hashCode()

  1. hashCode() - 返回对象的哈希码值,该值在equals方法中用于比较对象的相等性。默认实现返回对象的系统标识符。

例如:

   Object obj = new Object();
   int hash = obj.hashCode();

示例演示:

在这里插入图片描述

getClass()

  1. getClass() - 获取运行时对象的类信息,返回一个Class对象。

例如:

   Object obj = new Object();
   Class<?> clazz = obj.getClass(); // 获取obj的运行时类类型

示例演示:

在这里插入图片描述

clone()

  1. clone() - 创建并返回对象的一个副本。默认实现是浅拷贝,即复制对象的引用值,而不是实际的内容。

例如:

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:02
 */
public class testObject implements Cloneable{

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) {
        testObject obj = new testObject();
        try {
            testObject cloneObj = (testObject) obj.clone(); // 创建obj的一个浅拷贝
            System.out.println(cloneObj);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

示例演示:

在这里插入图片描述

拓展一下:

  在Java中,要使用clone()方法,首先需要确保被克隆的对象的类实现了Cloneable接口。如果一个类没有实现Cloneable接口,调用其clone()方法会抛出CloneNotSupportedException异常。

  另外,clone()这个方法使用了protected访问修饰符,因此只能在同一包内的类或者继承了这个类的子类中访问,因此只能在同一个包内或者子类中使用。

在这里插入图片描述

如果要克隆一个对象,最好的方式是通过实现Cloneable接口并重写clone()方法。示例代码如下:

class MyClass implements Cloneable {
    // 类的成员和方法

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

然后你可以这样使用:

MyClass obj = new MyClass();
MyClass cloneObj = (MyClass) obj.clone();

  若你直接对Object类的实例调用了clone()方法,但是Object类并没有实现Cloneable接口,会抛出CloneNotSupportedException异常。

wait()

  1. wait() - 使当前线程等待,直到另一个线程调用此对象的notify()notifyAll()方法。
   synchronized (obj) {
       try {
           obj.wait(); // 当前线程等待
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }

  示例这里我就先不着急给大家演示,同学们先看下我给大家解读的notify()方法学习后,我再一并给大家演示,毕竟这两是一起连用的,单独用没啥意义。

notify()

  1. notify() - 唤醒在此对象上等待的单个线程(如果有的话)。

使用例如:

   synchronized (obj) {
       obj.notify(); // 唤醒一个在此对象上等待的线程
   }

示例演示:

  这里联合notify(),关于Object类中使用wait()及notify()方法的示例演示:

定义启动类,将演示wait()、notify()方法效果。

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:38
 */
public class WaitNotifyExample {

    public static void main(String[] args) {
        Message message = new Message();

        // 创建一个等待线程
        Thread waiterThread = new Thread(new Waiter(message));

        // 创建一个通知线程
        Thread notifierThread = new Thread(new Notifier(message));

        // 启动线程
        waiterThread.start();
        notifierThread.start();
    }
}

定义一个Message类,用于在线程之间传递消息

package com.example.javase.bugTest.objectDemo;

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:38
 */
public class Message {
    private String content;

    public synchronized String getContent() {
        return content;
    }

    public synchronized void setContent(String content) {
        this.content = content;
    }
}

定义一个Waiter类,等待消息并打印。

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:38
 */
public class Waiter implements Runnable {
    private Message message;

    public Waiter(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        synchronized (message) {
            try {
                System.out.println("Waiter 等待中...");
                // 调用wait()方法,等待被通知
                message.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 收到通知后打印消息
            System.out.println("Waiter 收到通知: " + message.getContent());
        }
    }
}

定义一个Notifier类,负责发送通知。

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:38
 */
// Notifier类负责发送通知
public class Notifier implements Runnable {
    private Message message;

    public Notifier(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        synchronized (message) {
            // 设置消息内容
            message.setContent("你好,这是一条消息!");
            // 通知等待线程
            message.notify();
            System.out.println("Notifier 发送通知完毕");
        }
    }
}

  其中这个示例包含了一个Message类用于在线程之间传递消息,一个Waiter类等待消息并打印,一个Notifier类负责发送通知。在Waiter类中,使用了wait()方法来使线程进入等待状态,直到收到Notifier类发送的通知才继续执行。

实际运行结果展示:

拓展一下:

  如上示例演示了Object类中的wait()和notify()方法的使用,用于线程间的通信和同步。第一,我定义了一个Message类,它包含一个私有的字符串成员变量msg,以及一个getMessage()方法和setMessage()方法用于设置和获取消息。第二,定义了一个Waiter类和一个Notifier类,它们都实现了Runnable接口,用于作为线程执行体。Waiter类中的run()方法中调用了message.waitMessage()方法,而Notifier类中的run()方法中调用了message.setMessage()方法。第三,在WaitNotifyExample类的main()方法中,先创建了一个Message对象,并分别创建了一个等待线程waiterThread和一个通知线程notifierThread,它们都传入了同一个Message对象。最后,通过start()方法启动了这两个线程,实现了等待线程和通知线程的交互。

  总的来说,为大家演示了如何使用wait()和notify()方法实现线程间的等待和通知机制,从而实现线程间的协作。不知道大家可否能及时掌握,有疑问的及时评论区告知于我。

notifyAll()

  1. notifyAll() - 唤醒在此对象上等待的所有线程。

例如:

   synchronized (obj) {
       obj.notifyAll(); // 唤醒所有在此对象上等待的线程
   }

示例演示:

1、定义一个MessageProducer类,实现Runnable 接口,定位为一个消息生产者,当执行它的 run() 方法时,它会将一个新消息设置到 message 对象中,并通知所有等待中的线程。

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:51
 */
public class MessageProducer implements Runnable {
    private Message message;

    public MessageProducer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        synchronized (message) {
            // 生产消息
            message.setContent("New message: Hello, world!");
            // 通知所有等待的线程
            message.notifyAll();
        }
    }
}

2、定义一个MessageConsumer类,实现Runnable 接口,定位为一个消息消费者,目的是实现一个等待消息并处理的逻辑,通过线程的等待和唤醒机制,确保消息在到达后能够及时被消费。

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:51
 */
public class MessageConsumer implements Runnable {
    private Message message;

    public MessageConsumer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        synchronized (message) {
            // 等待消息的到来
            while (message.getContent() == null) {
                try {
                    // 等待消息通知
                    message.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 收到消息后进行处理
            System.out.println("Received message: " + message.getContent());
        }
    }
}

3、定义一个mian主函数,用于创建生产者和消费者线程,最后通过启动线程,达到生产者线程将消息放入 Message 对象中,而消费者线程则从 Message 对象中获取消息并进行处理的效果。

package com.example.javase.bugTest.objectDemo;

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 19:51
 */
public class NotifyAllTest {

    public static void main(String[] args) {
        // 创建一个共享的消息对象
        Message message = new Message();

        // 创建生产者线程和消费者线程
        Thread producerThread = new Thread(new MessageProducer(message));
        Thread consumerThread1 = new Thread(new MessageConsumer(message));
        Thread consumerThread2 = new Thread(new MessageConsumer(message));

        // 启动线程
        producerThread.start();
        consumerThread1.start();
        consumerThread2.start();
    }
}

4、执行main函数本地测试结果如下:

  很明显,结果符合预期,生产者将消息传递后且唤醒在此对象上等待的所有线程(所有消费者线程),消费者拿到消息后并进行了打印。

拓展一下:

  如上示例演示了线程间如何通过共享对象进行通信。具体来说,创建了一个名为 NotifyAllTest 的公共类,其中包含一个名为 main 的静态方法。在 main 方法中:

  1. 创建了一个 Message 对象,这是一个自定义的消息对象,用于在生产者和消费者线程之间传递消息。
  2. 创建了一个生产者线程 (producerThread) 和两个消费者线程 (consumerThread1consumerThread2)。
  3. 启动了这三个线程。

  其中,MessageProducer 类和 MessageConsumer 类实现了 Runnable 接口,用于定义生产者和消费者线程的行为。生产者线程将消息放入 Message 对象中,而消费者线程则从 Message 对象中获取消息并进行处理。

  这个示例,我给大家演示了下线程间的基本通信和协作机制,但需要注意的是,它并没有提供线程安全的保障。在实际应用中,可能需要采取额外的措施来确保多线程环境下的数据安全性。

finalize()

  1. finalize() - 在垃圾收集器决定回收对象之前,由垃圾收集器调用此方法。这个 finalize 机制是不确定的,不保证会被调用,且在Java 9中已经被弃用。

简单使用实例例如:

   protected void finalize() throws Throwable {
       super.finalize();
       // 清理资源的代码
   }

示例演示:

好的,下面是一个关于Object类使用finalize()方法的示例:

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-02 20:08
 */
public class FinalizeExample {

    // 定义一个类来演示finalize()方法
    static class MyObject {

        // 在对象销毁前调用finalize()方法
        @Override
        protected void finalize() throws Throwable {
            try {
                // 执行清理资源的操作
                System.out.println("对象被销毁前执行finalize()方法");
            } finally {
                super.finalize();
            }
        }
    }

    public static void main(String[] args) {
        // 创建一个对象
        MyObject obj = new MyObject();

        // 将对象设为null,以便触发垃圾回收
        obj = null;

        // 强制垃圾回收
        System.gc();

        // 等待一段时间以确保finalize()方法被调用
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

本地执行结果如下:

在这里插入图片描述

  在这个示例中,我定义了一个包含finalize()方法的内部类MyObject。在该方法中,我们可以执行清理资源的操作。在主函数中,我创建了一个MyObject对象,并将其设为null以便触发垃圾回收。然后,我手动调用了System.gc()方法来强制进行垃圾回收。最后,通过让主线程休眠一段时间,等待finalize()方法被调用。

小结

  大多数时候,你可能需要重写这些方法来提供特定的实现。例如,为了正确地比较两个对象是否相等,你可能需要重写equalshashCode方法。同样,为了实现深拷贝,你可能需要重写clone方法。

  请注意,Object类中的wait(), notify()notifyAll()方法是同步控制的一部分,它们只能在对象的监视器(由synchronized关键字实现)被当前线程持有时调用。不当使用这些方法可能导致死锁或其他同步问题。

… …

  ok,以上就是我这期的全部内容啦,如果还想学习更多,你可以看看专栏《Java进阶实战》中的其他硬货,每篇都是实打实的项目实战经验所撰。只要你每天学习一个奇淫小知识,日积月累下去,你一定能成为别人眼中的大佬的!功不唐捐,久久为功!

「赠人玫瑰,手留余香」,咱们下期拜拜~~

☀️建议/推荐你

  无论你是计算机专业的学生,还是对编程感兴趣的跨专业小白,都建议直接入手「滚雪球学Java」专栏;该专栏不仅免费,bug菌还郑重承诺,只要你学习此专栏,均能入门并理解Java SE,以全网最快速掌握Java语言,每章节源码均同步「Gitee」,你真值得拥有;学习就像滚雪球一样,越滚越大,带你指数级提升。

最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同Java实战类型技术硬货,还可免费白嫖最新BAT大厂面试真题、4000G Pdf技术书籍、万份简历/PPT模板、技术文章Markdown文档等海量资料,你想要的我都有!

📣关于我

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 20w+;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1826851.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mac M3 Pro 部署Spark-2.3.2 On Hive-3.1.3

mac的配置如下 1、下载安装包 官网 Apache Projects Releases 在search中搜索hadoop、hive spark &#xff1a; Index of /dist/spark/spark-2.3.2 网盘 Hadoop https://pan.baidu.com/s/1p4BXq2mvby2B76lmpiEjnA?pwdr62r 提取码: r62r Hive https://pan.baidu.com/s/…

c++的lamda表达式

作用: 弥补了main函数里面不可以定义函数的缺陷&#xff0c;减少了全局变量的声明 可以在main里面搭建小的构件&#xff0c;如下&#xff1a; #include<bits/stdc.h> #define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) #define int long long #define loop…

rsa加签验签C#和js、java、微信小程序互通

js实现rsa加签验签 https://github.com/kjur/jsrsasign 11.1.0版本 解压选择需要的版本&#xff0c;这里选择all版本了 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>JS RSA加签验签</title&g…

Java——变量作用域和生命周期

一、作用域 1、作用域简介 在Java中&#xff0c;作用域&#xff08;Scope&#xff09;指的是变量、方法和类在代码中的可见性和生命周期。理解作用域有助于编写更清晰、更高效的代码。 2、作用域 块作用域&#xff08;Block Scope&#xff09;&#xff1a; 块作用域是指在…

SQLserver前五讲课堂笔记

第一讲 基本内容 为什么要学习数据库系统?什么是数据库?什么是数据库系统?什么是数据库管理系统&#xff1f;本课程学什么以及学到什么程度? 重点难点 一组概念的区分&#xff1a;数据库、数据库系统和数据库管理系统熟悉表 的相关要素及术语熟悉数据库系统的构成(工作…

Springboot项目ES报异常query_shard_exception

详细异常信息如下&#xff1a; {"error": {"root_cause": [{"type": "query_shard_exception","reason": "failed to create query: {\n \"bool\" : {\n \"filter\" : [\n {\n \…

【docker hub镜像源失效】2024年6月6日 docker 国内镜像源失效

文章目录 概述中科大镜像源阿里镜像源其他镜像源可用的镜像源写在最后 之前违反社区规定了&#xff0c;做了和谐 概述 大家都知道使用docker hub官方镜像需要魔法&#xff0c;虽然大部人有魔法&#xff0c;但是网速也是很慢&#xff0c;还有部分同学没有&#xff0c;全靠国内各…

Linux-Https协议

文章目录 前言一、Https协议二、常见的加密方式对称加密非对称加密数据摘要&&数据指纹中间人攻击 三、Https的加密历程方案1-只使用对称加密方案2-只使用非对称加密方案3-双方都使用非对称加密方案4-非对称加密对称加密 前言 之前我们学习了Http协议&#xff0c;也试着…

Bug:SSH Failed Permission Denied(完美解决)

Bug&#xff1a;SSH Failed Permission Denied&#xff08;完美解决&#xff09; 今天我本机mac通过ssh访问linux服务器时报错&#xff1a;SSH Failed Permission Denied 思路&#xff1a; linux服务器sshd是否开启linux /etc/ssh/sshd_config配置是否正确&#xff08;是否开启…

YouTube583美元账户做到一千多万美元,125万粉的顶级交易员

油管125万粉丝的Ross Cameron,一位把583美元账户做到一千多万美元。他说他曾经也是像无头苍蝇一样交易,最终凄惨爆仓,也就是在爆仓之后,他终于开始沉下心来研究交易策略,终于终于,他有一天找到了交易模型,并用它执行至今。 Ross Cameron无疑是最成功的日内交易员之一,而…

Asp.Net Core 读取配置接口 IOptions、IOptionsMonitor以及IOptionsSnapshot

&#x1f340;简介 Options是.net Core Web api框架自带的功能&#xff0c;Options模式通过定义强类型的类来表示相关配置设置的集合&#xff0c;使得配置管理更为结构化和类型安全。 IOptions、IOptionsMonitor和IOptionsSnapshot是用于处理配置的依赖注入接口。这些接口允许…

Linux基础 (十八):Libevent 库的安装与使用

目录 一、Libevent 概述 1.0 Libevent的安装 1.0.1 使用源码方式 1.0.2 终端命令行安装 1.1 主要特性 1.2 主要组件 1.3 Libevent 使用模型 1.4 原理 1.5 使用的基本步骤 1.5.1 初始化事件基础设施 1.5.2. 创建和绑定服务器套接字 1.5.3. 设置监听事件 1.5.4. 定义…

电脑缺失d3dcompiler_47.dll会怎么样,该如何修复呢

在计算机使用过程中&#xff0c;我们常常会遇到一些错误提示&#xff0c;其中之一就是“缺少d3dcompiler47.dll文件”。那么&#xff0c;d3dcompiler47.dll到底是什么&#xff1f;为什么计算机会缺失它&#xff1f;它会对电脑产生什么具体影响&#xff1f;如何解决这个问题&…

【CT】LeetCode手撕—25. K 个一组翻转链表

目录 题目1-思路2- 实现⭐25. K 个一组翻转链表——题解思路 3- ACM实现 题目 原题连接&#xff1a;25. K 个一组翻转链表 1-思路 1. dummyHead&#xff1a;设置虚拟头结点&#xff0c;通过虚拟头结点保证每个结点的地位相同2. 定位 pre 和 end 拆链&#xff1a;借助 pre 、s…

(新)Spring Security如何实现登录认证(实战篇)

一、回顾认证流程详解 概念速查: Authentication接口: 它的实现类&#xff0c;表示当前访问系统的用户&#xff0c;封装了用户相关信息。 AuthenticationManager接口&#xff1a;定义了认证Authentication的方法 UserDetailsService接口&#xff1a;加载用户特定数据的核心接…

软件体系结构笔记(自用)

来自《软件体系结构原理、方法与实践&#xff08;第三版&#xff09;》清华大学出版社 张友生编著 1-8章12章 复习笔记 如有错误&#xff0c;欢迎指正&#xff01;&#xff01;&#xff01;

Python使用策略模式生成TCP数据包

使用策略模式&#xff08;Strategy Pattern&#xff09;来灵活地生成不同类型的TCP数据包。 包括三次握手、数据传输和四次挥手。 from scapy.all import * from scapy.all import Ether, IP, TCP, UDP, wrpcap from abc import ABC, abstractmethodclass TcpPacketStrategy(A…

网络安全技术实验六 入侵检测技术实践

一、实验目的和要求 理解基于网络的入侵检测系统的基本原理&#xff0c;掌握snort IDS工作机理&#xff1b; 学习应用snort三种方式工作&#xff1b;熟练编写snort规则&#xff1b; 完成snort数据包记录、日志查看、字符串匹配、ARP欺骗攻击检测、端口扫描工具检测等功能。 …

微信小游戏插件申请,微信小程序插件管理

微信小游戏的插件申请与小程序不一样&#xff0c;官方没有提供一个统一的管理入口进行申请插件&#xff0c;以及查看插件&#xff0c;没有小程序方便的&#xff1b; 小程序申请查看插件入口如下图所示&#xff1a; 小游戏的插件可以通过以下的方式进行申请&#xff1a; 如下…

代码随想录-Day31

455. 分发饼干 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都…