学习日志09 java

我要(ง •_•)ง!!

1 面向对象里面的编程的属性,其实就是变量啦

在面向对象编程里,“属性”(Attribute)也被叫做 “成员变量” 或者 “字段”(Field),指的是类中用来存储对象状态数据的变量。在这个题目里,Student类和Undergraduate类的属性分别如下:

Student类的属性

  • name:类型为String,用来存储学生的姓名。
  • age:类型为int,用来存储学生的年龄。

Undergraduate类的属性

  • 继承自Student类的属性:
    • name:存储本科生的姓名。
    • age:存储本科生的年龄。
  • 自身特有的属性:
    • major:类型为String,用来存储本科生的专业。

而题目中提到的show()方法,它的作用是输出对象的属性信息。也就是说,show()方法会把对象里各个属性的值组合成特定格式的字符串并返回。

代码示例说明属性与show()方法的关系

以下是结合你提供代码的简单说明:

Student

java

package PTA_training.Demo3_4;

public class Student {
    protected String name;
    protected int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String show() {
        return "Student[name=" + name + ",age=" + age + "]";
    }
}

Student类中,nameage就是属性。show()方法将这两个属性的值组合成"Student[name=XXX,age=XX]"格式的字符串。

Undergraduate

java

package PTA_training.Demo3_4;

public class Undergraduate extends Student {
    private String major;

    public Undergraduate(String name, int age, String major) {
        super(name, age);
        this.major = major;
    }

    public String show() {
        return "Undergraduate[name=" + name + ",age=" + age + ",major=" + major + "]";
    }
}

Undergraduate类中,除了继承自Student类的nameage属性,还有自身的major属性。show()方法会把这三个属性的值组合成"Undergraduate[name=XXX,age=XXX,major=XXX]"格式的字符串。

2 关于java里面的equals方法

在 Java 中,equals()方法是一个基础且重要的方法,主要用于比较两个对象是否相等。下面从多个方面对它进行详细介绍:

1. 方法定义

equals()方法在Object类中被定义,这意味着 Java 里的所有类都会继承该方法。其原始定义如下:

java

public boolean equals(Object obj) {
    return (this == obj);
}

可以看到,默认情况下,equals()方法比较的是两个对象的引用是否相同,也就是它们是否指向内存中的同一个对象。

2. 重写 equals () 方法

通常,我们需要根据对象的内容来判断它们是否相等,这时就需要重写equals()方法。比如:

java

public class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }
}

3. 重写 equals () 的规范

在重写equals()方法时,需要遵循以下几个原则:

  • 自反性:对于任何非空引用值xx.equals(x)都应返回true
  • 对称性:若x.equals(y)返回true,那么y.equals(x)也应返回true
  • 传递性:若x.equals(y)true,且y.equals(z)true,那么x.equals(z)也应为true
  • 一致性:只要对象的关键属性没有改变,多次调用equals()方法应返回相同的结果。
  • 非空性:对于任何非空引用值xx.equals(null)应返回false

4. 与 "==" 的区别

  • ==:用于比较两个引用是否指向同一个对象,或者比较基本数据类型的值是否相等。
  • equals():在未被重写时,功能和==一样;重写后,可用于比较对象的内容是否相同。

5. 重写 equals () 时必须重写 hashCode ()

根据Object类的规范,如果两个对象通过equals()方法比较是相等的,那么它们的hashCode()返回值也必须相同。因此,重写equals()方法时,必须同时重写hashCode()方法,以保证这一规范的实现

java

@Override
public int hashCode() {
    return Objects.hash(name, age);
}

6. 常见错误

  • 未重写 equals ():直接使用默认的引用比较,可能无法满足业务需求。
  • 参数类型错误:若方法签名写成public boolean equals(Person other),这并不是对equals()方法的重写,而是定义了一个新方法。
  • 遗漏 null 或类型检查:可能会导致NullPointerException或比较逻辑出错。

7. 工具生成 equals ()

现代 IDE(如 IntelliJ IDEA、Eclipse)能够自动生成equals()hashCode()方法。此外,Lombok 库可以通过注解(如@EqualsAndHashCode)来自动生成这些方法。

8. 特殊类的 equals () 方法

  • 包装类(如 Integer、String):重写了equals()方法,用于比较对象的值。

    java

    Integer a = 1000;
    Integer b = 1000;
    System.out.println(a.equals(b)); // 输出true
    System.out.println(a == b);      // 输出false(装箱后的对象引用不同)
    
  • 数组:使用Arrays.equals()来比较数组内容,直接调用equals()比较的是引用。

    java

    int[] arr1 = {1, 2, 3};
    int[] arr2 = {1, 2, 3};
    System.out.println(arr1.equals(arr2));        // 输出false
    System.out.println(Arrays.equals(arr1, arr2)); // 输出true
    

总结

equals()方法是 Java 中用于对象内容比较的重要方法。在实际开发中,为了让对象能够按照业务逻辑进行相等性判断,我们通常需要重写该方法,并且要遵循相关规范,同时重写hashCode()方法。这样可以确保对象在集合操作(如 HashMap、HashSet)中能够正常工作。

4 和equals方法类似的相关的方法

是的,在 Java 中还有一些与equals()方法类似或相关的方法,它们在不同场景下用于比较对象或数据。以下是几个重要的相关方法:

1. hashCode()

  • 作用:返回对象的哈希码(整数),主要用于哈希表(如HashMapHashSet)。
  • equals()的关系
    • 如果两个对象通过equals()比较相等,则它们的hashCode()必须相同。
    • 如果hashCode()不同,则对象一定不相等(无需再调用equals())。
  • 示例

    java

    @Override
    public int hashCode() {
        return Objects.hash(name, age); // 根据属性计算哈希码
    }
    

2. compareTo()Comparable接口)

  • 作用:定义对象之间的自然排序规则,返回负数、零或正数表示当前对象 “小于”、“等于” 或 “大于” 另一个对象。
  • 适用场景:用于排序(如Collections.sort()Arrays.sort())或实现有序集合(如TreeSetTreeMap)。
  • 示例

    java

    public class Person implements Comparable {
        private String name;
        private int age;
    
        @Override
        public int compareTo(Person other) {
            return Integer.compare(this.age, other.age); // 按年龄排序
        }
    }
    
  • equals()的关系:若compareTo()返回 0,建议equals()也返回true,但这不是强制要求(如BigDecimal)。

3. Objects.equals()

  • 作用:null 安全的equals()方法,避免NullPointerException
  • 示例

    java

    String a = null;
    String b = null;
    System.out.println(Objects.equals(a, b)); // 输出true,无需手动检查null
    

4. Arrays.equals()

  • 作用:比较数组的内容是否相等(支持多维数组,需用Arrays.deepEquals())。
  • 示例

    java

    int[] arr1 = {1, 2, 3};
    int[] arr2 = {1, 2, 3};
    System.out.println(Arrays.equals(arr1, arr2)); // 输出true
    

5. deepEquals()Objects类)

  • 作用:递归比较对象或数组的内容,适用于嵌套结构(如多维数组)。
  • 示例

    java

    Object[] arr1 = { new int[]{1, 2}, new int[]{3, 4} };
    Object[] arr2 = { new int[]{1, 2}, new int[]{3, 4} };
    System.out.println(Objects.deepEquals(arr1, arr2)); // 输出true
    

6. instanceof 关键字

  • 作用:检查对象是否是某个类或接口的实例。
  • 示例

    java

    if (obj instanceof String) {
        String str = (String) obj; // 安全类型转换
    }
    

7. isAssignableFrom()Class类)

  • 作用:判断一个类是否是另一个类的父类或接口。
  • 示例

    java

    List.class.isAssignableFrom(ArrayList.class); // 返回true(ArrayList实现了List)
    

8. ReferenceEquals()Object类,Java 9+)

  • 作用:等同于==,直接比较对象引用。
  • 示例

    java

    Object a = new Object();
    Object b = a;
    System.out.println(Object.referenceEquals(a, b)); // 输出true
    

总结

方法 / 关键字 比较维度 null 安全 适用场景
equals() 对象内容 自定义对象相等性判断
hashCode() 哈希值(配合equals 哈希表(如 HashMap)
compareTo() 自然排序 排序和有序集合
Objects.equals() 对象内容 可能为 null 的对象比较
Arrays.equals() 数组内容 部分是 一维数组比较
Objects.deepEquals() 嵌套对象内容 多维数组或嵌套结构比较
instanceof 类型兼容性 类型检查和转换
isAssignableFrom() 类层次关系 反射和泛型编程

根据具体场景选择合适的比较方法,可以避免NullPointerException、提高代码健壮性,并确保集合操作的正确性。

5 为java的面向编程里面的属性设置get/set方法是为什么?

它把类的内部实现和外部接口分离开来,增强了代码的安全性、可维护性和可扩展性。

在 Java 面向对象编程里,为类属性设置getset方法(也就是访问器和修改器)是很关键的封装实践,主要目的如下:

1. 访问控制

借助get/set方法,能够对属性的读写权限进行精确控制。比如,把属性设为private,仅允许通过特定方法访问,这样可以防止外部代码随意修改对象状态。

java

public class Person {
    private int age; // 私有属性

    public int getAge() { // 提供只读访问
        return age;
    }
}

2. 数据验证

set方法中,可以添加验证逻辑,保证输入数据是合法的。

java

public void setAge(int age) {
    if (age >= 0) { // 验证逻辑
        this.age = age;
    } else {
        throw new IllegalArgumentException("年龄不能为负数");
    }
}

3. 解耦实现细节

外部代码只需通过方法来获取或修改数据,不用关心内部的实现方式。要是后续需要对实现进行修改,比如更改数据存储格式,也不会影响外部调用。

java

// 原本直接返回属性
public Date getBirthDate() {
    return birthDate;
}

// 改为返回计算后的年份,调用方无需修改
public int getBirthYear() {
    return birthDate.getYear() + 1900;
}

4. 增强安全性

可以避免直接暴露对象内部状态,降低被恶意修改的风险。

java

private List secrets = new ArrayList<>();

public List getSecrets() {
    return new ArrayList<>(secrets); // 返回副本,防止外部修改原列表
}

5. 实现高级功能

在方法中能够添加额外的逻辑,像缓存、日志记录、事件触发等。

java

private int counter = 0;

public void increment() {
    counter++;
    notifyObservers(); // 计数器更新时通知观察者
}

自动生成工具

现代 IDE(如 IntelliJ IDEA、Eclipse)可以自动生成get/set方法,减少了手动编写的工作量。例如:

java

public class User {
    private String name;
    private int id;

    // IDE自动生成的getter和setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
}

总结

get/set方法是实现封装的重要手段,它把类的内部实现和外部接口分离开来,增强了代码的安全性、可维护性和可扩展性。在设计类时,除非有特殊原因,否则建议将属性设为私有,并通过公共方法来控制访问。

6 equals的括号里面只可以写 Object obj 吗? 是的!

在 Java 中,重写equals方法时,参数类型必须是Object

!!!!!!!!!!这是因为equals方法是在java.lang.Object类中定义的,其签名为:

java

public boolean equals(Object obj)

当你在子类中重写这个方法时,必须保持方法签名完全一致(包括参数类型、返回类型和访问修饰符),否则就不是重写(override),而是重载(overload)一个新方法。重载的方法不会被Object.equals()的多态机制调用,导致你的比较逻辑失效。

错误示例(重载而非重写)❌的!!!!

以下代码会创建一个新的equals方法,而不是重写父类的方法:

java

// 错误!这是重载,不是重写
public boolean equals(Teacher other) { // 参数类型是 Teacher,不是 Object
    return this.no.equals(other.no);
}

这种写法会导致以下问题:

  1. 当你调用teacher1.equals(teacher2)时,如果teacher2被声明为Object类型,实际执行的是Object.equals(),而非你定义的方法。
  2. 违反了equals方法的对称性原则(a.equals(b)b.equals(a)可能结果不同)。

正确示例(重写)✔的哦~~~~~~

java

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || !(obj instanceof Teacher)) return false;
    
    Teacher other = (Teacher) obj;
    return this.no.equals(other.no);
}

为什么必须是Object

Java 的多态机制依赖于方法签名的一致性。当你调用obj.equals(other)时:

  1. 编译时:编译器只知道objObject类型,因此会查找Object.equals(Object)方法。
  2. 运行时:根据obj的实际类型(如Teacher),动态调用其重写的equals(Object)方法。

如果参数类型不是Object,编译器会认为这是一个全新的方法,无法通过多态调用。

总结

  • 重写equals时,参数必须是Object类型
  • 如果使用其他参数类型(如Teacher),会导致方法重载,而非重写,从而使equals失效。
  • 重写时建议添加@Override注解,让编译器帮你检查方法签名是否正确。

你可能感兴趣的:(学习)