自学内容网 自学内容网

Java基础:面向对象编程7

1 Java 不可变对象

1.1 什么是不可变类

  • 定义:一个类的对象在通过构造方法创建后,其状态(成员变量值)不会再被改变,这样的类称为不可变(immutable)类。
  • 特点
    • 所有成员变量的赋值仅在构造方法中完成。
    • 不提供任何 setter 方法供外部类修改成员变量。
  • 优点
    • 对象状态不可变,每次修改状态都会产生新对象,避免并发问题。

1.2 常见的不可变类

  • String 类
    • 常量池:字符串常量池是 Java 堆内存中一个特殊的存储区域,当创建一个 String 对象时,假如此字符串在常量池中不存在,那么就创建一个;假如已经存在,就不会再创建了,而是直接引用已经存在的对象。这样做能够减少 JVM 的内存开销,提高效率。
    • hashCode:因为字符串是不可变的,所以在它创建的时候,其 hashCode 就被缓存了,因此非常适合作为哈希值(比如作为HashMap的键),多次调用只返回同一个值,来提高效率。
    • 线程安全:如果对象的状态是可变的,那么在多线程环境下,就很容易造成不可预期的结果。而 String 是不可变的,就可以在多个线程之间共享,不需要同步处理。
    • 方法返回新对象:当我们调用 String 类的任何方法(比如说 trim()、substring()、toLowerCase())时,总会返回一个新的对象,而不影响之前的值。
  • 包装类
    • 除了 String 类,包装器类 Integer、Long 等也是不可变类

1.3 手撸一个不可变类

1.3.1 条件

  1. 类声明为 final:防止子类修改。
  2. 成员变量声明为 final:确保初始化后不可更改。
  3. 不提供 setter 方法:防止外部修改状态。
  4. 修改状态返回新对象:例如,String 的 substring() 方法。

1.3.2 代码示例

  • 来自定义一个简单的不可变类 Writer
/**
 * @package: com.yunyang.javabetter.oop.immutabledemo
 * @description: 定义一个简单的不可变类 Writer
 * @author: Yunyang
 * @date: 2024/10/16  9:21
 * @version:1.0
 **/
public final class Writer {
    private final String name;
    private  final int age;
    private final Book book;

    public Writer(String name, int age, Book book) {
        this.name = name;
        this.age = age;
        this.book = book;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Book getBook() {
        Book clone = new Book();
        clone.setPrice(this.book.getPrice());
        clone.setName(this.book.getName());
        return clone;
    }
}

Writer 类是 final 的,name、age 和 book 也是 final 的,没有 setter 方法

  • Book 类是这样定义的
/**
 * @package: com.yunyang.javabetter.oop.immutabledemo
 * @description: Book类
 * @author: Yunyang
 * @date: 2024/10/16  9:23
 * @version:1.0
 **/
public class Book {
    private String name;
    private int price;

    public String getName() {
        return name;
    }

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

    public int getPrice() {
        return price;
    }

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

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

2 个字段,分别是 name 和 price,以及 getter 和 setter,重写后的 toString() 方法

  • 测试类
/**
 * @package: com.yunyang.javabetter.oop.immutabledemo
 * @description: 测试类
 * @author: Yunyang
 * @date: 2024/10/16  9:26
 * @version:1.0
 **/
public class WriteDemo {
    public static void main(String[] args) {
        Book book = new Book();
        book.setName("Java进阶之路");
        book.setPrice(79);

        Writer writer = new Writer("沉默王二", 18, book);
        System.out.println("定价: " + writer.getBook());
        writer.getBook().setPrice(59);
        System.out.println("促销价:" + writer.getBook());
    }
  • 注意:如果一个不可变类中包含了可变类的对象,那么就需要确保返回的是可变对象的副本。所以,Writer 类中的 getBook() 方法被修改为:
public Book getBook() {
    Book clone = new Book();
    clone.setPrice(this.book.getPrice());
    clone.setName(this.book.getName());
    return clone;
}
  • 运行结果:
定价: Book{name='Java进阶之路', price=79}
促销价:Book{name='Java进阶之路', price=79}

1.4 小结

不可变对象是 Java 中一种重要的设计模式,能够提高代码的安全性、可维护性和性能。掌握不可变类的概念和设计原则,对于编写高质量的 Java 代码至关重要。

2 Java 方法重写和方法重载

2.1 引入

方法重载

  • 定义:一个类中可以有多个名字相同但参数个数或类型不同的方法。
  • 目的:提高程序的可读性,避免为相似功能的方法取不同的名字。

方法重写

  • 定义:子类中定义与父类相同的方法(方法名、参数、返回类型相同,但方法体可能不同)。
  • 目的:提供父类方法的特殊实现,实现多态。

2.2 方法重载

实现方式

  1. 改变参数数目:例如,add(int a, int b)add(int a, int b, int c)
  2. 改变参数类型:例如,add(int a, int b)add(double a, double b)

重载 main 方法

  • 尽管可以重载 main() 方法,但程序只认标准写法 public static void main(String[] args)

重载与类型转换

  • 当传递的参数类型不匹配时,会发生隐式类型转换。
  • 例如,byte 可以转换为 shortintlongfloatdouble

2.3 方法重写

规则

  1. 方法名相同
  2. 参数相同
  3. 继承关系(is-a 关系)。

重写时应当遵守的规则

  1. 只能重写继承的方法:只能重写 publicprotecteddefault 修饰的方法,private 方法无法被重写。
  2. final、static 方法不能被重写
    • final 方法无法被子类继承,因此无法重写。
    • static 方法属于类,而不是对象,因此无法重写。
  3. 参数列表必须相同
  4. 返回类型必须相同
  5. 权限修饰符不能更严格
    • default 方法可以重写为 defaultprotectedpublic
    • protected 方法可以重写为 protectedpublic
    • public 方法只能重写为 public
  6. 不能抛出更高级别的异常:只能抛出父类方法抛出异常的子类或不抛出异常。
  7. 使用 super 调用父类方法
  8. 构造方法不能被重写:构造方法与类名相同,子类无法重写父类的构造方法。
  9. 抽象方法必须在子类中重写
  10. synchronized 不影响重写规则synchronized 关键字用于多线程环境,不影响重写规则。
  11. strictfp 不影响重写规则strictfp 关键字用于精确浮点运算,不影响重写规则。

2.4 小结

方法重载

  • 两同:在同一个类,方法名相同。
  • 一不同:参数不同。

方法重写

  • 两同:方法名相同,参数相同。
  • 一小:子类方法声明的异常类型要比父类小或相等。
  • 一大:子类方法的访问权限要比父类大或相等。

3 思维导图

在这里插入图片描述
在这里插入图片描述

4 参考链接

  1. 聊聊Java中的不可变对象
  2. 方法重写 Override 和方法重载 Overload 有什么区别

原文地址:https://blog.csdn.net/gaosw0521/article/details/142970606

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!