到目前为止,我已经看到了两种在 Java 中设置变量值的方法。有时使用带参数的构造函数,其他的 setter 方法用于设置每个变量的值。
我知道一旦使用“new”关键字实例化类,构造函数就会在类中初始化实例变量。
但是我们什么时候使用构造函数,什么时候使用setter呢?
到目前为止,我已经看到了两种在 Java 中设置变量值的方法。有时使用带参数的构造函数,其他的 setter 方法用于设置每个变量的值。
我知道一旦使用“new”关键字实例化类,构造函数就会在类中初始化实例变量。
但是我们什么时候使用构造函数,什么时候使用setter呢?
当您想要创建对象的新实例时,您应该使用构造函数方法,并且已经填充了值(一个准备使用的对象,其中填充了值)。这样,您无需为对象中的每个字段显式调用 setter 方法来填充它们。
当您想在创建对象后更改字段的值时,您可以使用 setter 方法设置值。
例如:-
MyObject obj1 = new MyObject("setSomeStringInMyObject"); // Constructor approach
// Yippy, I can just use my obj1, as the values are already populated
// But even after this I can change the value
obj1.setSomeString("IWantANewValue"); // Value changed using setter, if required.
..
MyObject obj2 = new MyObject();
obj2.setSomeString("setSomeStringNow"); // Setter approach
// values weren't populated - I had to do that. Sad :(
正如 Axel 提到的,如果你想创建不可变的对象,你不能使用 setter-methods 方法。我不会说所有东西都必须在构造函数中初始化,因为存在不同的方法,比如惰性求值,即使是不可变对象也可以使用。
我想你问了一个很好的问题: - 但是我们什么时候使用构造函数,什么时候使用 setter?
首先,让我们从一些概念开始。我希望这个解释能帮助所有想知道何时使用构造函数或 setters() 和 getters() 方法(访问器和突变器)的人。构造函数类似于方法,但是构造函数和java中的方法之间几乎没有区别:
1)构造函数用于初始化对象的状态。 方法用于暴露对象的行为。
2)构造函数不能有返回类型。方法必须有返回类型。
3)构造函数被隐式调用。方法被显式调用。
4) Getters()或访问器是提供对对象实例变量的访问的方法。Setters()或 mutators 是为调用者提供更新特定实例变量值的机会的方法。
清楚了这一点,让我们从面向对象编程 (OOP) 的角度来考虑,以满足 OOP 原则的要求(面向对象编程 (OOP)是基于四大原则构建的:封装、数据抽象、多态性和继承。),Getter ()和Setter()方法是实现这一点的关键。
这是一个公式,它将向您展示我的意思:
私有字段 + 公共访问器 == 封装;
正如您所看到的,当我们设置私有字段并使用公共访问器时,我们正在执行 4 个 OOP 主体之一的封装。
在这里,我将为您提供两个类,我对其添加了注释以尝试使我的代码自我解释。将这些类作为具有方法的实验室Customer
和TestCustomer
[具有main()
方法的类] 类,您可以复制代码并自己运行它。注意我使用了两个构造函数来解释一个具有多个构造函数并具有公共setters()
和getters()
方法以访问私有实例变量的类:
package com.exercise.lecture2;
/**
* 1) Create a Customer class that has the following attributes:
* name, SSN.
* 2) This class should have two methods: getName() and getSSN().
* 3) If the class is instantiated with only a SSN, then give the default name of "John Doe". (HINT: Use two constructors)
* 4) Also, add a method toString(), that returns a string representation of the customer object (name and SSN concatenated).
* Make sure to set this method public.
* 5) Create a class to test your program (e.g. a class that include the main() method). In your test program, instantiate
* three customers and print out the value using toString() method.
*
* @author Samuel M.
*
*/
//this class is complemented with class TestLabCustomer.java
public class LabCustomer {
// Private filds: name and socialSecurityNum
private String name;
private int socialSecurityNum;
// constructors
public LabCustomer(String name, int socialSecurityNum) {
this.name = name;
this.socialSecurityNum = socialSecurityNum;
}
/** The keyword 'this' can be used to call a constructor from a constructor,
* when writing several constructor for a class, there are times when
* you'd like to call one constructor from another to avoid duplicate code.
*/
// Account with This() on a second constructor
public LabCustomer(int socialSecurityNum) {
this("John Doe", socialSecurityNum); // default name is printed if only the SSN is provided
}
// Public accessors (getters and setters)
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
int getSSN() {
return socialSecurityNum;
}
void setSSN(int socialSecurityNum) {
this.socialSecurityNum = socialSecurityNum;
}
// instance method
public String toString() { //overriding the toString() method
return ("Customer name: " + getName() + ", SSN#: " + getSSN() ); // concatenating the name and SSN
}
}
这是测试类,它具有main()
方法并在实例化预览类的对象后调用实例方法:
package com.exercise.lecture2;
//this class is complemented with class LabCustomer.java
public class TestLabCustomer {
public static void main(String[] args) {
// Instantiating an object of class LabCustomer and creating three customers objects
LabCustomer cust1 = new LabCustomer("Juan Melendez", 123457789);
LabCustomer cust2 = new LabCustomer("Mary Lee", 125997536);
LabCustomer cust3 = new LabCustomer(124963574); // when instantiating with no "name", the default (John Doe) is printed
/**
* Once you've instantiated an object and have an object variable,
* you can use object variable to call an instance method.
* e.g.:
* object variables: cust1, cust2, cust3
* call the method toString() using the object variable and dot [.] in order to perform the method call.
*/
// calling method toString() in class LabCustomer to print customer values
System.out.println(cust1.toString());
System.out.println(cust2.toString());
System.out.println(cust3.toString());
}
}
结果:
客户姓名:Juan Melendez,SSN#:123457789
客户姓名:Mary Lee,SSN#:125997536
客户姓名:John Doe,SSN#:124963574
如果您想拥有一个不可变的类,请使用构造函数,否则使用设置器。
我们根据场景使用该方法。
构造方法:当对象的实例化必须有参数并且没有它们我们无法构造对象时,我们应该继续使用这种方法。
Setter 方法:对于可选参数,我们可以继续使用 setter 方法。
在大多数情况下,我同时使用它们:) (因为你 9/10 次想要回来编辑一些东西(这不是一个好的做法来创建它的新实例)
我通常会做这样的事情
public class User {
private int id;
private String initials;
private String firstName;
private String lastName;
private String email;
public User() {
this(0, "", "", "");
}
public User(int id, String firstName, String lastName, String email) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
// Getters and setters should be here
}
当您想用它编辑某些内容时,您可以使用设置器,(例如,如果您将用户保存在 ArrayList 中,那么您可以从 ArrayList 中获取对象并设置您想要编辑的字段,而不是为它制作一个全新的对象:)
假设我们有一个名为 Counter 的类:
public class Counter{
int count;
//constructor
public Counter(int c){
count = c;
}
public void setCounter(int newCounter){
count = newCounter;
}
}
在上面的类中,当您想创建一个新的Counter 对象时,您将使用构造函数并在其中设置 count 变量。像这样:
Counter myCounter = new Counter(1);
如果要在运行时更改计数变量,可以使用 setter 方法:
myCounter.setCounter(2);
在构造函数的情况下,当您更新字段时,您每次都使用new关键字创建一个新对象。
Customer customer = new Customer("Tom", 23, 10000);
例如,如果要更新 Tom 的薪水,则需要将更新后的薪水再次写入这一行,这意味着内存浪费。
在设置方法的情况下,您只能在原始对象中设置单个字段。
它取决于应用程序域和其中类的用途。
Java bean 通常有一个无参数构造函数和相关成员变量的 getter/setter。这种方法有很多优点,因为在许多框架(如 Struts 和 Spring)中都支持开箱即用的 Java bean。
类还可以通过将此类变量作为参数传递给基本构造函数来强制值的可用性。并且可以通过其他便利的构造函数或 setter 方法设置非强制值。
另一方面,不可变类可以具有构造函数,但需要修改其状态的缺席方法,包括 setter。
总体而言,可以在考虑应用程序的整体设计、它运行的框架1、它必须执行的合同等方面做出这样的决定。
1 - 虽然,它建议类设计应该独立于框架。像 Spring 这样的优秀框架不会强制执行此类要求。
您可以将这两种方法结合起来。在构造函数中,您可以调用实例变量的设置器。就像是:
public class TestClass {
private String someField;
public TestClass(String someField) {
setSomeField(someField);
}
public String getSomeField() {
return someField;
}
public void setSomeField(String someField) {
this.someField = someField;
}
}