到目前为止,我已经看到了两种在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。就像是:
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;
}
}
我想你问了一个很好的问题: - 但是我们什么时候使用构造函数?什么时候使用setter?
首先,让我们从一些概念开始。我希望这个解释可以帮助每个想知道何时使用构造函数或setter()和getters()方法(Accessors和Mutators)的人。构造函数与Methods类似,但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。
假设我们有一个名为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);
我们根据场景使用该方法。
在大多数情况下,我使用它们:)(因为你有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
}
当你想用它编辑一些东西时你可以使用setter,(例如,如果你将用户保存在ArrayList中,那么你可以从arraylist中获取对象,然后设置你想编辑的字段)而不是制作一个全新的对象:)
它取决于应用程序域和类中的目的。
Java bean通常没有arg构造函数和相关成员变量的getter / setter。这种方法有一些优点,因为在许多框架(如Struts和Spring)中,Java bean都是开箱即用的。
类还可以通过将这些变量作为参数传递给基础构造函数来强制实施值的强制可用性。并且可以通过其他便捷构造函数或setter方法设置非强制值。
另一方面,不可变类可以有构造函数,但需要缺省方法来修改其状态,包括setter。
总的来说,这样的决策可以考虑到应用程序的整体设计,运行的框架1,必须强制执行的合同等。
1 - 虽然,它建议类设计应该独立于框架。像Spring这样的好框架不会强制执行这样的要求。
对于构造函数,在更新字段时,每次都使用new关键字创建一个新对象。
Customer customer = new Customer("Tom", 23, 10000);
例如,如果要更新Tom的工资,则需要使用更新的工资再次写入此行,这意味着浪费了内存。
对于setter方法,您只能在原始对象中设置单个字段。