【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 本文详细介绍了 Java 中 `toString()` 方法的重写技巧及其重要

 目录

一、toString() 方法是啥?

(一)默认的 toString() 方法

(二)toString() 方法的作用

二、为啥要重写 toString() 方法?

(一)提高代码的可读性

(二)方便调试

三、如何重写 toString() 方法?

(一)重写的规则

(二)代码示例

四、toString() 方法重写的最佳实践

(一)包含关键属性信息

(二)保持格式的一致性和简洁性

(三)考虑对象的嵌套关系

五、toString() 方法与其他方法的配合使用

(一)与 equals() 和 hashCode() 方法的关系

(二)在日志记录中的应用

image.gif 编辑

宝子们,今天咱要好好唠唠 Java 里一个看似不起眼,但实则用处很大的知识点 ——toString() 方法的重写。在 Java 的世界中,当我们想要直观地了解一个对象的信息时,toString() 方法就派上用场了。不过呢,默认的 toString() 方法有时候可能不太能满足我们的需求,这时候就需要对它进行重写啦。

一、toString() 方法是啥?

(一)默认的 toString() 方法

每个 Java 类都默认继承自 java.lang.Object 类,而 Object 类中就有这个 toString() 方法。当我们创建一个对象,然后直接打印这个对象时,实际上调用的就是它的 toString() 方法。比如说:

认真学哦,掌握这些知识,就像看小说一样,你会越来越强大。

class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public static void main(String[] args) {
        Person person = new Person("张三", 25);
        // 这里直接打印 person 对象,会调用其 toString() 方法
        System.out.println(person);
    }
}

image.gif

在这个例子中,如果我们没有重写 toString() 方法,打印出来的结果可能是类似 Person@15db9742 这样一串不太好理解的字符串,这其实是对象的默认哈希码表示形式,对于我们了解对象的具体内容没啥太大帮助。

(二)toString() 方法的作用

toString() 方法的主要作用就是返回一个能代表对象状态的字符串。当我们在调试程序或者需要将对象的信息以一种可读的方式展示出来时,它就非常重要了。比如在日志记录中,我们可能需要记录某个对象的详细信息,这时候一个合适的 toString() 方法就能让我们快速了解对象的各个属性值,而不是看到一堆乱码一样的哈希码。

二、为啥要重写 toString() 方法?

(一)提高代码的可读性

想象一下,我们在一个大型项目中,有很多地方都需要打印对象的信息来进行调试或者查看数据的状态。如果不重写 toString() 方法,看到的都是那些默认的哈希码,根本不知道对象里面到底存了些啥数据。但如果我们重写了 toString() 方法,就可以按照我们想要的格式返回对象的属性信息,比如对于一个 Student 对象,我们可以让 toString() 方法返回 “学生姓名:[具体姓名],年龄:[具体年龄],成绩:[具体成绩]” 这样清晰明了的字符串,这对于我们快速了解学生对象的情况就非常方便,大大提高了代码的可读性。

(二)方便调试

在调试程序的时候,我们经常需要查看各种对象的状态,看看数据是否正确地被赋值和修改。如果能够通过重写 toString() 方法,将对象的关键属性信息以一种直观的方式展示出来,那么在调试过程中就能更快地发现问题所在。比如在一个电商系统中,对于一个 Order 对象,重写 toString() 方法返回订单号、商品列表、总价等信息,当出现订单问题时,我们可以很容易地通过打印 Order 对象来查看这些关键信息,从而更快地定位和解决问题。

三、如何重写 toString() 方法?

(一)重写的规则

  • 方法签名:必须和 Object 类中的 toString() 方法签名完全一致,也就是 public String toString()。这是 Java 重写方法的基本规则,保证了在运行时能够正确地调用子类重写后的方法。
  • 返回值:返回一个字符串,这个字符串要能够准确地描述对象的状态。通常我们会将对象的各个属性值以一种合理的格式组合成一个字符串返回。
  • 访问权限:一般将其声明为 public,这样在任何需要使用该对象的地方都能够方便地调用 toString() 方法获取对象的信息。

(二)代码示例

class Book {
    private String title;
    private String author;
    private double price;
    public Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }
    // 重写 toString() 方法
    @Override
    public String toString() {
        return "Book{" +
                "title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
    public static void main(String[] args) {
        Book book = new Book("Java 编程思想", "Bruce Eckel", 89.9);
        // 现在打印 book 对象,会调用重写后的 toString() 方法,输出详细的书籍信息
        System.out.println(book);
    }
}

image.gif

在这个例子中,我们重写了 Book 类的 toString() 方法,将书籍的标题、作者和价格等属性以 “Book {title='[具体标题]', author='[具体作者]', price=[具体价格]}” 的格式返回。这样,当我们打印 Book 对象时,就能清晰地看到书籍的详细信息,而不是那个让人摸不着头脑的默认哈希码。

四、toString() 方法重写的最佳实践

(一)包含关键属性信息

在重写 toString() 方法时,要确保包含对象的关键属性信息,这些信息能够完整地描述对象的状态。比如对于一个 Employee 类,除了员工的姓名、年龄等基本信息外,如果员工还有职位、部门等重要属性,也应该包含在 toString() 方法返回的字符串中,这样才能在查看员工对象信息时全面了解其情况。

class Employee {
    private String name;
    private int age;
    private String position;
    private String department;
    public Employee(String name, int age, String position, String department) {
        this.name = name;
        this.age = age;
        this.position = position;
        this.department = department;
    }
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", position='" + position + '\'' +
                ", department='" + department + '\'' +
                '}';
    }
}

image.gif

(二)保持格式的一致性和简洁性

  • 一致性:如果一个项目中有多个类都重写了 toString() 方法,尽量保持格式的一致,这样在查看不同对象的信息时,能够更加清晰地进行对比和分析。例如,都采用 “类名 {属性 1 = 值 1, 属性 2 = 值 2,...}” 这样的格式,让开发者能够快速适应和理解每个类的 toString() 方法返回的信息结构。
  • 简洁性:不要在 toString() 方法中返回过于复杂或者冗长的字符串,要突出重点,只包含必要的属性信息。避免在方法中进行复杂的计算或者逻辑处理,因为 toString() 方法的主要目的是提供对象的简要信息,而不是执行复杂的业务逻辑。

(三)考虑对象的嵌套关系

如果一个对象中包含其他对象作为属性,比如一个 Order 类中包含多个 Item 对象(代表订单中的商品项),在重写 Order 类的 toString() 方法时,要考虑如何合理地展示这些嵌套对象的信息。可以采用简洁的方式,比如只显示每个 Item 对象的关键信息(如商品名称和数量),或者提供一个方法让用户可以进一步查看 Item 对象的详细信息,而不是在 OrdertoString() 方法中展开所有的嵌套对象细节,导致字符串过于复杂难以阅读。

class Item {
    private String name;
    private int quantity;
    public Item(String name, int quantity) {
        this.name = name;
        this.quantity = quantity;
    }
    @Override
    public String toString() {
        return "Item{" +
                "name='" + name + '\'' +
                ", quantity=" + quantity +
                '}';
    }
}
class Order {
    private List<Item> items;
    public Order(List<Item> items) {
        this.items = items;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("Order{");
        for (Item item : items) {
            sb.append(item.toString()).append(", ");
        }
        if (sb.length() > "Order{".length()) {
            sb.setLength(sb.length() - 2);
        }
        sb.append('}');
        return sb.toString();
    }
}

image.gif

在这个例子中,Order 类的 toString() 方法通过循环将每个 Item 对象的 toString() 方法返回的字符串连接起来,展示了订单中包含的商品项信息,既简洁又能让用户对订单的内容有一个大致的了解。

五、toString() 方法与其他方法的配合使用

(一)与 equals()hashCode() 方法的关系

在 Java 中,当我们重写 equals() 方法来判断两个对象是否相等时,通常也需要重写 hashCode() 方法,以保证对象在哈希表中的正确存储和查找。而 toString() 方法也可以与这两个方法配合使用,提供更全面的对象比较和信息展示功能。

例如,如果两个 Person 对象的 equals() 方法判断它们的姓名和年龄都相等,那么它们的 hashCode() 方法应该返回相同的值,并且它们的 toString() 方法返回的信息也应该能够反映出这种相等关系,让开发者在调试和查看对象信息时能够更加清晰地理解对象的状态和相等性判断逻辑。

class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass()!= o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

image.gif

(二)在日志记录中的应用

在进行日志记录时,toString() 方法可以与日志框架(如 Log4jSlf4j 等)配合使用,方便地记录对象的详细信息。例如:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggingExample {
    private static final Logger logger = LoggerFactory.getLogger(LoggingExample.class);
    public static void main(String[] args) {
        Person person = new Person("李四", 30);
        // 使用日志框架记录 Person 对象的信息,会自动调用 toString() 方法
        logger.info("创建了新的 Person 对象:{}", person);
    }
}

image.gif

在这个例子中,当我们使用日志框架记录 Person 对象时,toString() 方法会被自动调用,将对象的信息以一种可读的方式记录到日志中,方便后续查看和分析程序的运行状态。

宝子们,toString() 方法的重写虽然看起来不是很难,但在实际的 Java 编程中却有着重要的作用,能够大大提高我们代码的可读性、调试效率以及与其他方法和框架的配合效果。希望通过这篇文章,大家都能掌握 toString() 方法重写的技巧和最佳实践,写出更加优秀的 Java 代码。如果在学习过程中还有什么疑问或者想要深入探讨的地方,随时回来看看这篇文章,或者查阅更多的相关资料哦。

image.gif 编辑


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
30天前
|
算法 Java C++
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
本文介绍了经典的0/1背包问题及其动态规划解法。
48 5
|
30天前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
62 6
|
30天前
|
Java 数据库连接 数据库
【潜意识Java】深度分析黑马项目《苍穹外卖》在Java学习中的重要性
《苍穹外卖》项目对Java学习至关重要。它涵盖了用户管理、商品查询、订单处理等模块,涉及Spring Boot、MyBatis、Redis等技术栈。
84 4
|
4天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
45 14
|
7天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
37 13
|
8天前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
1月前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
1月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
109 17
|
2月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者