如何在 Java 中构造对象(学习 Java 编程语言 034)

1. 构造器

Java 对象都是在堆中构造的。

先看看 Employee 类的构造器:

public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;
    
    public Employee(String name, double salary, int year, int month, int day) {
        this.name = name;
        this.salary = salary;
        hireDay = LocalDate.of(year, month, day);
    }
    ...
}

构造器与类同名。在构造 Employee 类的对象时,构造器会运行并初始化实例字段。

当使用下面这条代码创建 Employee 类的实例时:
new Employee("James Bond", 100000, 1950, 1, 1);
将会把实例字段设置为:

name = "James Bond";
salary = 100000;
hireDay = LocalDate.of(1950, 1, 1); // 1950-01-01

有关构造方法,需要记住:

  • 构造器与类同名
  • 每个类可以有一个以上的构造器。
  • 构造器可以有 0 个、1 个或多个参数。
  • 构造器没有返回值。
  • 构造器总是伴随着 new 操作符一起调用。

注意,不要在构造器中定义与实例字段同名的局部变量。例如:

public Employee(String n, double s, int y, int m, int d) {
    String name = n; // 错误
    double salary = s; // 错误
    ...
}

这个构造器声明了局部变量 name 和 salary。这些变量只能在构造器内部访问。这些变量会遮蔽同名的实例字段。有些程序员偶尔会不假思索地写出这类代码,因为它们的手指会不自觉地增加数据类型。这种错误很难检查出来,因此,必须注意在所有方法中都不要使用与实例字段同名的变量。

2. 重载

有些类有多个构造器。
new StringBuilder();
new StringBuilder("String");
这种功能叫做重载(overloading)。如果多个方法有相同的名字、不同的参数,便出现了重载。

Java 允许重载任何方法,而不只是构造器方法。

编译器必须挑选出具体调用哪个方法,它用各个方法首部的参数类型与特定方法调用中所使用的值类型进行匹配,来选出正确的方法。如果编译器找不到匹配的参数,就会产生编译时错误,因为根本不存在匹配,或者没有一个比其他的更好。这个查找匹配的过程被称为重载解析(overloading resolution)。

要完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。例如,String 类有 4 个名为 indexOf 的公共方法。它们的签名是:
indexOf(int)
indexOf(int, int)
indexOf(String)
indexOf(String, int)
返回类型不是方法签名的一部分。也就是说,不能有两个名字相同、参数类型也相同却有不同返回类型的方法。

3. 无参数的构造器

很多类都包含一个无参数的构造器,由无参数构造函数创建对象时,其状态会设置为适当的默认值。例如,以下是无参数构造器:

public class Employee {
    private String name;
    private double salary;
    protected LocalDate hireDay;

    public Employee() {
        name = "";
        salary = 0;
        hireDay = LocalDate.now();
    }
}

如果写一个类时没有编写构造器,就会为你提供一个无参数构造器。这个构造器将所有的实例字段设置为默认值。于是,实例字段中的数值型数据设置为 0、布尔型数据设置为 false、所有对象变量将设置为 null。

如果类中提供了至少一个构造器,但是没有提供无参数的构造器,那么构造对象时如果不提供参数就是为不合法。

警告: 仅当类没有任何其他构造器的时候,才会得到一个默认的无参数构造器。编写类的时候,如果写了一个你自己的构造器,要想让这个类的用户能够通过以下调用构造一个实例:
new ClassName();
你就必须提供一个无参数的构造器,当然,如果希望所有的字段被赋予默认值,只需要提供以下代码:

public ClassName() {

}

4. 参数名

在编写很小的构造器时,常常在参数命名时感到困惑。

常常用单个字母作为参数名:

public class Employee {
    ...
    public Employee(String n, double s) {
        name = n;
        salary = s;
    }
}

但这样做有一个缺点:只有阅读代码才能够了解参数 n 和参数 s 的含义。

有些程序员在每个参数前面加上一个前缀 “a”:

public class Employee {
    ...
    public Employee(String aName, double aSalary) {
        name = aName;
        salary = aSalary;
    }
}

这样很清晰。读者一眼就能看懂参数的含义。

还有一种常用的技巧,它基于这样的事实:参数变量会遮蔽同名的实例字段。如果将参数名命名为 salary,salary 将指示这个参数,而不是实例字段。但是,还是可以用 this.salary 访问实例字段。this 指示隐式参数,也就是所构造的对象。

public class Employee {
    ...
    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
}

5. 调用另一个构造器

关键字 this 指示一个方法的隐式参数。这个关键字还有另一个含义。

如果构造器的第一个语句形如 this(...),这个构造器将调用同一个类的另一个构造器。下面是一个典型的例子:

public class Employee {
    ...
    public Employee (double s)
    {
        // calls Employee(String, double)
        this("Employee #" + nextId, s);
        nextId++;
    }
    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
}

当调用 new Employee(6000) 时,Employee(double) 构造器将调用 Employee(name, double) 构造器。

采用这种方式使用 this 关键字非常有用,这样对公共的构造器代码只需要编写一次即可。

6. 对象析构与 finalize 方法

由于 Java 会完成自动的垃圾回收,不需要人工回收内存,所以 Java 不支持析构器。

某些对象使用了内存之外的其他资源,例如,文件或使用了系统资源的另一个对象的句柄。在这种情况下,当资源不再需要时,将其回收和再利用显得十分重要。

如果一个资源一旦使用完就需要立即关闭,那么应当提供一个 close 方法来完成必要的清理工作。可以在对象用完时调用这个 close 方法。

如果可以等到虚拟机退出,那么可以用方法 Runtime.addShutdownHook 增加一个 “关闭钩”(shutdown hook)。在 Java 9 中,可以使用 Cleaner 类注册一个动作,当对象不再可达时(除了清洁器还能访问,其他对象都无法访问这个对象),就会完成这个动作。在实际中这些情况很少见。

警告: 不要使用 finalize 方法来完成清理。这个方法原本要在垃圾回收器清理对象之前调用。不过,你并不知道这个方法到底什么时候调用,而且该方法已经被废弃。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值