学习日志06 java

还有四天要去比赛了,能赢吗?逼自己一把。。。!!加油!

1 对比一下java重写还是不重写tostring的区别

1. 不重写 toString() 的情况

java

class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

public class Main {
    public static void main(String[] args) {
        Point p = new Point(10, 20);
        System.out.println(p); // 直接打印对象
        System.out.println(p.toString()); // 显式调用 toString()
    }
}

输出结果

Point@1b6d3586
Point@1b6d3586

分析

  • 默认行为:所有类继承自 Object,默认的 toString() 返回 类名@哈希码
  • 问题:返回值无法提供对象的实际状态(如 x 和 y 的值),对调试和日志不友好。

2. 重写 toString() 的情况

java

class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // 重写 toString() 方法
    @Override
    public String toString() {
        return "Point{x=" + x + ", y=" + y + "}";
    }
}

public class Main {
    public static void main(String[] args) {
        Point p = new Point(10, 20);
        System.out.println(p); // 自动调用 toString()
        System.out.println(p.toString()); // 显式调用
    }
}

输出结果

Point{x=10, y=20}
Point{x=10, y=20}

分析

  • 自定义格式:重写后返回包含对象属性的字符串,直观展示对象状态。
  • 自动调用System.out.println(p) 会隐式调用 p.toString()

3. 核心区别总结

对比项不重写 toString()重写 toString()
返回值类名@哈希码(如 Point@1b6d3586自定义格式(如 Point{x=10, y=20}
可读性低(无法获取对象状态)高(清晰展示属性值)
应用场景无实际意义,仅用于标识对象内存地址调试、日志记录、UI 展示对象信息
调用方式手动调用 obj.toString() 才有输出自动调用(如 print(obj) 或字符串拼接时)

4. 常见误区澄清

  • 误区 1:“不重写 toString() 就不能打印对象”
    ✅ 错误:可以打印,但输出的是无意义的哈希码。

  • 误区 2:“只有 System.out.println() 会调用 toString()
    ✅ 错误:所有需要字符串的场景都会自动调用,例如:

    java

    String s = "Point: " + p; // 等价于 "Point: " + p.toString()
    
  • 误区 3:“重写 toString() 会影响对象的其他功能”
    ✅ 错误toString() 仅用于生成字符串表示,不影响对象的核心逻辑。

5. 最佳实践

  • 所有自定义类都应重写 toString(),方便调试和日志记录。
  • 格式推荐:使用 JSON 风格(如 {key=value})或明确的描述性文本。
  • IDE 自动生成:大多数 IDE(如 IntelliJ、Eclipse)可自动生成 toString() 代码。例如:

    java

    // IntelliJ 自动生成的 toString()
    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
    

通过重写 toString(),可以让对象在打印时提供有价值的信息,避免输出无意义的内存地址,这是 Java 开发中的基础规范之一。

2 对比一下我写的代码和优雅的代码,需要进步

我写的,也是敢于接受批评直接全部放上了哈。题目也在里面

package PTA_training;
/*
7-3 定义商品类,封装成员变量,输出对象
定义一个商品类。创建对象并按指定格式输出它。
商品类要求:
(1)成员变量:商品编号(String) 、商品名称(String)、商品单价(double)
(2)成员变量封装,定义为私有属性,并为每个成员变量定义getXXXX,setXXXX方法
(3)定义构造方法,要求带三个参数,参数值用于给成员变量赋值。
(4)重写toString()方法,将对象转换为字符串,格式:商品编号,商品名称,商品单价
测试类要求:
按指定的格式 输入商品信息,调用构造方法生成对象,并输出它。
例:输入:WJ002 记事本 5.5
输出:WJ002,记事本,5.5
输入商品的信息,每个属性值之间用1个空格分隔。
输出 格式,商品的每个属性值之间用逗号分隔。
输入样例:
WJ002 记事本 5.5
输出样例:
WJ002,记事本,5.5
 */

import java.util.Scanner;

public class Demo2_3 {
    private String number  ;
    private String name;
    private double price;

    public void setNumber(String number){
        this.number=number;
    }

    public String getNumber() {
        return number;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public double getPrice() {
        return price;
    }

    public Demo2_3(String number ,String name ,double price){
        this.number=number;
        this.name=name;
        this.price=price;
    }

    @Override
    public String toString() {
        return number+","+name +"," +price;
    }

    public static void main(String[] args) {
        Scanner scanner =new Scanner(System.in);
        String number= scanner.next();
        String name= scanner.next();
        double price= scanner.nextDouble();
        Demo2_3 a = new Demo2_3(number,name,price);
        System.out.println(a);
        scanner.close();
    }
}

ai生成优化的优雅的代码

package PTA_training;

import java.util.Scanner;

public class Product {
    private final String id;
    private final String name;
    private final double price;

    public Product(String id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public String getId() { return id; }
    public String getName() { return name; }
    public double getPrice() { return price; }

    @Override
    public String toString() {
        return String.format("%s,%s,%.1f", id, name, price);
    }

    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            Product product = new Product(
                scanner.next(),
                scanner.next(),
                scanner.nextDouble()
            );
            System.out.println(product);
        }
    }
}    

代码对比分析

以下是你的代码与优化版本的详细对比:

对比项你的代码优化版本
类命名Demo2_3(无明确语义)Product(清晰表达业务含义)
成员变量number(普通描述)id(专业术语)
final修饰final修饰(不可变对象)
构造方法参数顺序与输入一致保持相同参数顺序
getter/setter完整实现(有 setter)仅保留 getter(数据不可变)
toString()简单字符串拼接String.format(精确控制格式)
资源管理未关闭 Scanner(原来忘记关了55)try-with-resources(自动关闭)
main 方法多个局部变量直接构造对象(减少临时变量)
输出格式直接拼接(可能出现多位小数)%.1f(强制保留 1 位小数)
业务封装功能集中在一个类职责分离(商品类专注业务)
线程安全可变对象不可变对象(线程安全)
代码行数48 行32 行(减少 33%)

具体改进点解释

  1. 命名优化

    • Product类名明确表示这是一个商品模型
    • id属性更符合专业领域术语(如数据库设计)
  2. 不可变设计

    java

    // 你的代码
    private String number; // 可修改
    
    // 优化后
    private final String id; // 不可变
    
     

    不可变对象在多线程环境中更安全,且符合数据封装原则

  3. 格式化输出

    java

    // 你的代码
    return number+","+name +"," +price; // 可能输出5.5000
    
    // 优化后
    return String.format("%s,%s,%.1f", id, name, price); // 强制保留1位小数
    
  4. 资源管理

    java

    // 你的代码
    Scanner scanner = new Scanner(System.in); // 需要手动关闭
    
    // 优化后
    try (Scanner scanner = new Scanner(System.in)) { // 自动关闭
        // 使用scanner
    }
    
  5. 代码精简

    java

    // 你的getter
    public String getNumber() {
        return number;
    }
    
    // 优化后的getter
    public String getId() { return id; } // 单行格式
    

为什么这些改进更好

  1. 可维护性:语义化命名和清晰的结构使代码更易于理解和修改

  2. 健壮性

    • 不可变对象减少了程序状态的复杂性
    • 资源自动关闭避免了内存泄漏风险
  3. 专业性

    • 使用领域术语(如id)体现专业素养
    • 精确的格式控制符合企业级应用要求
  4. 性能

    • String.format 在频繁格式化时性能更优
    • 减少不必要的对象创建(如临时变量)
  5. 扩展性

    • 职责分离的设计更容易添加新功能
    • 不可变对象支持函数式编程范式

建议在后续学习中关注:

  • 面向对象设计原则(SOLID)
  • Java 8+ 的函数式特性
  • 单元测试与代码覆盖率
  • 代码静态分析工具(如 SonarLint)的使用

================================可以了接下来就对着这个学习===================

谢谢伟大的AI!!!!

 3 感受进步,初版(无法跑起来的代码)vs 满足题目要求的代码

package PTA_training;
/*
7-4 定义类与创建对象

定义一个类Person,定义name和age属性,定义有参的构造方法对name和age进行初始化。
在测试类中创建该类的2个对象,姓名、年龄分别为lili、19和lucy、20,在屏幕打印出2个对象的姓名和年龄。
输入格式:
本题目无输入
输出格式:
在一行中输出一个人的姓名和年龄
输入样例:
在这里给出一组输入。例如:
输出样例:
在这里给出相应的输出。例如:
this person is lili,her age is 19
this person is lucy,her age is 20
 */

public class Demo2_4 {
    private static String name = null;
    public static String name1;
    public static String name2;
    public static int age = 0;
    public static int age1;
    public static int age2;
    public Demo2_4(String name, int age){
        Demo2_4.name =name;
        Demo2_4.age =age;
        name1 ="lili";
        name2 ="lucy";
        age1 = 19;
        age2 = 20;
    }
    @Override
    public String toString() {
        return"this person is "+name+",her age is "+age;
    }

    public static void main(String[] args) {
        Demo2_4 a = new Demo2_4(name1,age1);
        Demo2_4 b = new Demo2_4(name2,age2);
        System.out.println(a);
        System.out.println(b);
    }

    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
}
//只给提示不给正确答案,这个代码有问题,我应该怎么办

提示:

你的代码有以下问题,按顺序解决它们:

  1. 类名错误:题目要求定义Person类,但你仍在使用Demo2_4作为主类名
  2. 静态属性问题
    • nameage等属性被声明为static导致所有对象共享同一属性
    • 静态属性会被最后一次赋值覆盖,无法保存多个对象的状态
  3. 构造函数逻辑错误
    • 在构造函数中固定设置name1name2age1age2的值
    • 每次创建对象都会覆盖这些静态变量,导致数据混乱
  4. 对象创建顺序问题
    • 在创建对象ab时,name1age1尚未初始化(null0
    • 构造函数会先使用这些未初始化的值,然后再设置静态变量

提示:

  1. 创建Person类并定义非静态nameage属性
  2. Person类的构造函数中直接初始化当前对象的属性(使用this.namethis.age
  3. 在测试类的main方法中创建两个Person对象,分别传入 "lili",19 和 "lucy",20 作为参数
  4. 确保每个对象的属性独立保存,不使用静态变量
package PTA_training;

public class Demo2_4 {
   String name;
   int age;
    public Demo2_4(String n, int a){
       this.name = n;
       this.age = a;
    }
    @Override
    public String toString() {
        return"this person is "+name+",her age is "+age;
    }
    public static void main(String[] args) {
        Demo2_4 a = new Demo2_4("lili",19);
        Demo2_4 b = new Demo2_4("lucy",20);
        System.out.println(a);
        System.out.println(b);
    }

}
//我改成这样了,对比一下给我进步

对比:

你的修改非常棒!现在代码已经完全符合题目要求了。主要改进包括:

  1. 类设计优化

    • nameage改为实例变量(去掉了static修饰符)
    • 每个对象现在拥有独立的属性值,不会相互干扰
  2. 构造函数修正

    • 直接通过参数初始化当前对象的属性(this.name = n
    • 不再使用额外的静态变量(如name1name2
  3. 对象创建方式

    • main方法中直接传入具体参数创建对象
    • 正确初始化了两个不同的Demo2_4对象
  4. 输出格式

    • 通过重写toString()方法确保输出格式符合题目要求

关键进步总结

  • 理解了实例变量和静态变量的区别
  • 掌握了构造函数的正确使用方法
  • 学会了通过对象实例化保存不同数据

最终建议
根据题目要求,类名应该是Person而不是Demo2_4。虽然代码功能正确,但可能因为类名不符导致测试不通过。可以将类名改为Person,其他部分保持不变即可:

java

public class Person {
    String name;
    int age;
    
    public Person(String n, int a) {
        this.name = n;
        this.age = a;
    }
    
    @Override
    public String toString() {
        return "this person is " + name + ",her age is " + age;
    }
    
    public static void main(String[] args) {
        Person a = new Person("lili", 19);
        Person b = new Person("lucy", 20);
        System.out.println(a);
        System.out.println(b);
    }
}

这样就完全符合题目要求了!继续加油,你已经掌握了面向对象编程的基础概念。

4 我的最终代码和ai提供的最优雅代码 

以下是优化后的代码,包含详细注释和最佳实践:

java

// 使用题目要求的类名Person
public class Person {
    // 使用private封装属性,提供公共访问方法
    private String name;
    private int age;
    
    // 构造方法:参数名与属性名保持一致,使用this区分
    public Person(String name, int age) {
        this.name = name;  // this.name指类的属性,=右边的name是参数
        this.age = age;
    }
    
    // 提供公共的访问器方法(Getter)
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    // 重写toString方法,使用String.format提高可读性
    @Override
    public String toString() {
        return String.format("this person is %s,her age is %d", name, age);
    }
    
    // 主方法作为程序入口
    public static void main(String[] args) {
        // 创建对象时直接传入字面量参数
        Person person1 = new Person("lili", 19);
        Person person2 = new Person("lucy", 20);
        
        // 打印对象自动调用toString()
        System.out.println(person1);
        System.out.println(person2);
        
        // 可选:演示如何通过访问器获取属性
        System.out.printf("Name: %s, Age: %d%n", person1.getName(), person1.getAge());
    }
}

关键优化点对比:

  1. 类设计

    • 使用Person作为类名(符合题目要求)
    • 将属性设为private(封装性原则)
    • 提供公共的getter方法(数据访问控制)
  2. 构造方法

    java

    // 原代码
    public Demo2_4(String n, int a) { ... }
    
    // 优化后
    public Person(String name, int age) { ... }
    
     
    • 参数名与属性名保持一致(提高可读性)
    • 使用this明确指向类属性
  3. toString 方法

    java

    // 原代码
    return "this person is " + name + ",her age is " + age;
    
    // 优化后
    return String.format("this person is %s,her age is %d", name, age);
    
     
    • 使用String.format提高字符串拼接的可读性
    • 占位符%s(字符串)和%d(整数)使格式更清晰
  4. 变量命名

    java

    // 原代码
    Demo2_4 a = new Demo2_4("lili", 19);
    
    // 优化后
    Person person1 = new Person("lili", 19);
    
     
    • 使用更具描述性的变量名person1person2
    • 类型名与变量名形成语义关联
  5. 可扩展性

    • 添加了getName()getAge()方法
    • 为类未来的功能扩展预留接口
    • 符合 JavaBean 规范(私有属性 + 公共访问器)

为什么这样设计更优雅:

  1. 遵循面向对象原则

    • 封装性:通过private属性和公共方法控制访问
    • 可读性:类名、方法名、变量名均表意明确
    • 可维护性:结构清晰,易于添加新功能
  2. 代码健壮性

    • 避免直接访问属性(如person.name = "xxx"
    • 通过方法可以添加逻辑校验(如年龄合法性检查)
  3. 符合行业规范

    • 使用标准的 JavaBean 模式
    • 字符串格式化优先使用String.format
    • 构造方法参数名与属性名一致
  4. 最佳实践

    • 为每个属性提供getter(如果需要修改,还应提供setter
    • 重写toString()以便调试和日志输出
    • 使用有意义的变量名提高代码自解释性

---------------------------------------------------------------------------------------------------------------------------------这个时代有ai大模型实在是太好了!/(ㄒoㄒ)/

5 对自己所写的代码要有清晰的认知,细节明白,感谢ai注释 

好的,让我们逐行分析这个代码,并解释每一步的作用:

java

public class Demo2_4 {
    // 定义类的属性(成员变量)
    String name;  // 存储人的姓名,每个对象独立拥有
    int age;      // 存储人的年龄,每个对象独立拥有
    
    // 构造方法:用于创建对象时初始化属性值
    public Demo2_4(String n, int a) {
        this.name = n;  // 将参数n的值赋给当前对象的name属性
        this.age = a;   // 将参数a的值赋给当前对象的age属性
    }
    
    // 重写toString()方法:控制对象打印时的输出格式
    @Override
    public String toString() {
        return "this person is " + name + ",her age is " + age;
    }
    
    // 程序入口点
    public static void main(String[] args) {
        // 创建第一个对象:姓名"lili",年龄19
        Demo2_4 a = new Demo2_4("lili", 19);
        // 创建第二个对象:姓名"lucy",年龄20
        Demo2_4 b = new Demo2_4("lucy", 20);
        
        // 直接打印对象时,会自动调用对象的toString()方法
        System.out.println(a);  // 输出:this person is lili,her age is 19
        System.out.println(b);  // 输出:this person is lucy,her age is 20
    }
}

核心概念解释:

  1. 实例变量(非静态属性)

    java

    String name;
    int age;
    
     
    • 每个对象独立拥有一份nameage
    • 创建多个对象时,它们的属性值互不影响
  2. 构造方法

    java

    public Demo2_4(String n, int a) {
        this.name = n;
        this.age = a;
    }
    
     
    • this.name表示当前对象的name属性
    • 参数na是临时变量,仅在构造方法内部有效
    • 作用:在创建对象时必须传入姓名和年龄,立即完成初始化
  3. 对象创建过程

    java

    Demo2_4 a = new Demo2_4("lili", 19);
    
     
    • new Demo2_4("lili", 19):调用构造方法,创建一个新对象
    • "lili"19作为参数传递给构造方法
    • 构造方法将参数值赋给对象的nameage属性
    • Demo2_4 a = ...:将新创建的对象引用赋值给变量a
  4. 方法重写

    java

    @Override
    public String toString() {
        return "this person is " + name + ",her age is " + age;
    }
    
     
    • @Override:告诉编译器这是重写父类的方法
    • toString()是 Object 类的方法,所有对象都继承这个方法
    • 重写后,当你System.out.println(a)时,会自动调用这个方法

对比之前的错误:

你的原始代码中使用了静态变量:

java

private static String name = null;
public static int age = 0;

静态变量属于类,所有对象共享同一份数据。无论创建多少个对象,它们都会修改同一个nameage

而现在的写法:

java

String name;  // 实例变量
int age;      // 实例变量

每个对象都有自己独立的nameage,互相不干扰。这是面向对象编程的基础概念。

 //现在的学习方法让我感受到了进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值