Java 强制调用所有方法
我经常使用对象来存储从数据库中获取的实体的属性。我在对象中使用私有变量,然后使用getter和setter来设置值。因此,为了初始化对象,我调用对象的所有setter。但是不可能跟踪所有的设置者,我经常忘记设置一些变量。有没有一种方法可以强制设定设定者的呼叫。我当然可以使用构造函数来初始化变量,但是使用构造函数来设置10-12个属性会使代码看起来很糟糕。我希望以这样一种方式使用接口和子类,即它们的工作方式与实现接口的所有方法所必需的方式相同,但这里不是实现而是调用它们Java 强制调用所有方法,java,Java,我经常使用对象来存储从数据库中获取的实体的属性。我在对象中使用私有变量,然后使用getter和setter来设置值。因此,为了初始化对象,我调用对象的所有setter。但是不可能跟踪所有的设置者,我经常忘记设置一些变量。有没有一种方法可以强制设定设定者的呼叫。我当然可以使用构造函数来初始化变量,但是使用构造函数来设置10-12个属性会使代码看起来很糟糕。我希望以这样一种方式使用接口和子类,即它们的工作方式与实现接口的所有方法所必需的方式相同,但这里不是实现而是调用它们 com.mysql.jdb
com.mysql.jdbc.PreparedStatement getInternships = (PreparedStatement) Connection.con.prepareCall("CALL getInternships()");
rs=getInternships.executeQuery();
Internship current;
while(rs.next()){
current=new Internship();
current.setId(Integer.parseInt(rs.getString("id")));
current.setTitle(rs.getString("title"));
current.setCategory(rs.getString("category"));
current.setOpening(rs.getDate("opening"));
current.setClosing(rs.getDate("closing"));
current.setDuration(Integer.parseInt(rs.getString("duration")));
current.setStatus(rs.getString("status"));
current.setApplicants(Integer.parseInt(rs.getString("applicants")));
current.setSeats(Integer.parseInt(rs.getString("seats")));
current.setHired(Integer.parseInt(rs.getString("hired")));
list.add(current);
}
实习班
package internships;
import java.util.Date;
public class Internship {
private String title,category,status,about,eligibility,information;
private int id,duration,applicants,seats,hired;
private Date opening,closing;
/**
* @return the opening
*/
public Date getOpening() {
return opening;
}
/**
* @param opening the opening to set
*/
public void setOpening(Date opening) {
this.opening = opening;
}
/**
* @return the hired
*/
public int getHired() {
return hired;
}
/**
* @param hired the hired to set
*/
public void setHired(int hired) {
this.hired = hired;
}
/**
* @return the seats
*/
public int getSeats() {
return seats;
}
/**
* @param seats the seats to set
*/
public void setSeats(int seats) {
this.seats = seats;
}
/**
* @return the applicants
*/
public int getApplicants() {
return applicants;
}
/**
* @param applicants the applicants to set
*/
public void setApplicants(int applicants) {
this.applicants = applicants;
}
/**
* @return the closing
*/
public Date getClosing() {
return closing;
}
/**
* @param closing the closing to set
*/
public void setClosing(Date closing) {
this.closing = closing;
}
/**
* @return the duration
*/
public int getDuration() {
return duration;
}
/**
* @param duration the duration to set
*/
public void setDuration(int duration) {
this.duration = duration;
}
/**
* @return the category
*/
public String getCategory() {
return category;
}
/**
* @param category the category to set
*/
public void setCategory(String category) {
this.category = category;
}
/**
* @return the status
*/
public String getStatus() {
return status;
}
/**
* @param status the status to set
*/
public void setStatus(String status) {
this.status = status;
}
/**
* @return the title
*/
public String getTitle() {
return title;
}
/**
* @param title the title to set
*/
public void setTitle(String title) {
this.title = title;
}
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the about
*/
public String getAbout() {
return about;
}
/**
* @param about the about to set
*/
public void setAbout(String about) {
this.about = about;
}
/**
* @return the eligibility
*/
public String getEligibility() {
return eligibility;
}
/**
* @param eligibility the eligibility to set
*/
public void setEligibility(String eligibility) {
this.eligibility = eligibility;
}
/**
* @return the information
*/
public String getInformation() {
return information;
}
/**
* @param information the information to set
*/
public void setInformation(String information) {
this.information = information;
}
}
这里有一个建议:
- 定义一个包含所有字段(类别、开始、结束、持续时间等)的“数据”类,例如,
InternishipData
- 在
类中,定义一个setter方法:实习
。无论何时需要配置setData(实习数据)
,都可以使用此设置器实习
- 在setter内部,检查所提供的
对象的所有字段是否已正确初始化。如果不是,您可以抛出异常,或者从setter返回internishipData
,并从外部检查返回的值false
实习生
构造函数,可以使用类似的方法)
这使您可以在单个位置检查所有字段(使用
setData
)方法,这对于您当前的方法来说是很难做到的,因为您有一堆setter,您不知道从客户端代码调用它们的顺序。这是另一个运行时想法——我能想到的唯一编译时答案是引入新的PMD/FindBugs规则,并让IDE在每次保存时运行这些
对于要避免“未初始化”值的每个类,您需要声明一个位集
,以跟踪已设置的字段,以及一个名为字段
的枚举
,该枚举将为您计算字段并将字段名与其对应的位集
索引相关联
// keeps track of initialized fields
private BitSet initialized = new BitSet(Fields.values().length);
// field-names not included here will not be considered included in BitSet
enum Fields {
title,category,status,about,eligibility,information,
id,duration,applicants,seats,hired,
opening,closingopening
}
只有在字段
中的所有字段至少设置一次时,才会返回true:
public void isFullyInitialized() {
return initialized.cardinality() == initialized.size();
}
这将是一个样本设定者:
/**
* @param opening the opening to set
*/
public void setOpening(Date opening) {
this.opening = opening;
initialized.set(Fields.opening.ordinal()); // <- do this in all setters
}
/**
*@param打开要设置的开口
*/
公开开标(开标日期){
这个。打开=打开;
initialized.set(Fields.opening.ordinal());//这个简单的反射有趣吗
我们将使用实习类的一个较轻的变体。用@NotNull标记最后不应为null的字段。是的,这不适用于基元字段,但除非构造函数强制,否则您的字段可以具有未定义的状态,该状态由值null表示。使用基元将隐藏该事实
class Internship {
@NotNull
private String name;
private String status;
public Internship() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
下面是对注释及其处理器的完整测试,该处理器是一个名为validateNotNullFields的漂亮方法。它获取对象的每个字段,甚至是私有字段和在超类中定义的字段。如果在一个值为null的字段上发现注释,则抛出一个IllegalArgumentException。如果您喜欢我的解决方案,您可能会布莱希望对此进行调整,并正确输出字段名称,甚至毫无例外地选择解决方案
public class Test {
public static void main(String... args) {
Internship a = new Internship();
a.setName("Karl");
a.setStatus(null);
validateNotNullFields(a);
System.out.println("ok");
try {
Internship b = new Internship();
b.setName(null);
b.setStatus(null);
validateNotNullFields(b); // throws IllegalStateException!
System.out.println("not ok");
} catch (IllegalStateException ise) {
System.out.println("ok");
}
}
static void validateNotNullFields(Object candidate) throws IllegalStateException {
if (candidate == null) {
throw new IllegalArgumentException("argument candidate must not be null!");
}
Class<?> clazz = candidate.getClass();
while (!Object.class.equals(clazz)) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
Annotation annotation = field.getAnnotation(NotNull.class);
if (annotation == null) {
continue;
}
field.setAccessible(true);
try {
if (field.get(candidate) == null) {
throw new IllegalStateException(
"Field " + field.getName() + " must not be null at this point!");
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
clazz = clazz.getSuperclass();
}
}
}
公共类测试{
公共静态void main(字符串…参数){
实习a=新实习();
a、 设置名称(“卡尔”);
a、 设置状态(空);
validateNotNullFields(a);
System.out.println(“ok”);
试一试{
实习b=新实习();
b、 集合名(空);
b、 设置状态(空);
validateNotNullFields(b);//抛出非法状态异常!
System.out.println(“不正常”);
}捕获(非法状态){
System.out.println(“ok”);
}
}
静态void validateNotNullFields(对象候选)引发IllegalStateException{
if(候选者==null){
抛出新的IllegalArgumentException(“参数候选者不能为null!”);
}
Class clazz=candidate.getClass();
而(!Object.class.equals(clazz)){
Field[]fields=clazz.getDeclaredFields();
用于(字段:字段){
Annotation=field.getAnnotation(NotNull.class);
if(注释==null){
继续;
}
字段。setAccessible(true);
试一试{
if(field.get(candidate)==null){
抛出新的非法状态异常(
“Field”+Field.getName()+“此时不能为空!”;
}
}捕获(IllegalArgumentException | IllegalAccessException ex){
抛出新的运行时异常(ex);
}
}
clazz=clazz.getSuperclass();
}
}
}
您可以使用一种方法,在每次调用时为您读取所有字段,而不是事后检查是否已设置了每个字段。不再有内存丢失:
static void load(Object target, ResultSet rs) throws Exception {
Class<?> clazz = target.getClass();
ResultSetMetaData rsmd = rs.getMetaData();
for (int i=0; i<rsmd.getColumnCount(); i++) {
Field field = clazz.getDeclaredField(rsmd.getColumnName(i+1));
field.setAccessible(true);
int type = rsmd.getColumnType(i+1);
switch (type) {
case Types.DATE: {
field.set(target, rs.getDate(i+1));
}
case Types.VARCHAR: {
field.set(target, rs.getString(i+1));
}
case Types.BIGINT: {
field.set(target, rs.getInt(i+1));
}
default: {
throw new IllegalArgumentException(
"Unhandled field type: " + type);
}
}
}
}
静态无效加载(对象目标、结果集rs)引发异常{
Class clazz=target.getClass();
ResultSetMetaData rsmd=rs.getMetaData();
对于(int i=0;i可能重复签出,虽然它可以强制调用所有方法,但我不确定它是否真的可以使您的代码更干净……这篇文章对我帮助不大,因为对我来说,我不打算使用默认值,而是希望在实例化objectI时必须使用所有setterg调用setter——只需迭代ResultSet的列并自动调用setter。请参见下面的答案。因为调用所有这些setter都是错误的