I have a class called Item, which - besides everything else as usual - defines the toString method like this:
我有一个名为Item的类,除了通常的其他所有东西之外,还定义了这样的toString方法:
@Override
public String toString() {
return "Item [id=" + id + ", name=" + name + ", type=" + type + "]";
}
Then I have an SQL connector for dumping all items in the table like this:
然后我有一个SQL连接器用于转储表中的所有项目,如下所示:
public ArrayList<Item> dumpAll() {
ArrayList<Item> dump = new ArrayList<Item>();
connectDB();
try {
result = connectDB().prepareStatement("SELECT * FROM Items").executeQuery();
if (result != null) {
connectDB().close();
while (result.next()) {
Item item = new Item();
item.toString();
dump.add(item);
}
}
} catch (Exception e) {
System.out.println("Query failed.");
// e.printStackTrace();
}
return dump;
}
connectDB();
is working fine. When I call the toString method elsewhere, I can see a result like this:
connectDB();工作正常。当我在其他地方调用toString方法时,我可以看到如下结果:
Item [id=0, name=null, type=null]
This line is repeated as many times as I have items in the table, i.e. I have 50 items; I get 50 lines showing zeroes and nulls. The format is exactly as I want it but obviusly the results are not. I think I'm missing something obvious handling the result
, but trying to debug with String itm = result.toString();
, Item.equals(result.toString());
and so on hasn't worked out.
这条线重复的次数与表中的项目一样多,即我有50个项目;我得到50行显示零和空值。格式完全按照我的要求,但显然结果不是。我想我错过了一些明显处理结果的东西,但试图用String调试itm = result.toString();, Item.equals(result.toString());等等还没有解决。
2 个解决方案
#1
2
Answer
It's your
Item item = new Item();
line. That says: "initialise an Item with NOTHING!" So of course you have empty objects. It should be:
线。这就是说:“用NOTHING初始化一个项目!”所以你当然有空物品。它应该是:
Item item = new Item(result.getInt(0), result.getString(1), result.getString(2));
Or whatever column names you gave them in the SQL table.
或者在SQL表中给出的任何列名。
Side note
It's bad practice to allow invalid objects. You shouldn't HAVE a default constructor for your Item object, because there should never be an Item object with invalid data. Trust me when I say it makes everything easier in the long run.
允许无效对象是不好的做法。您不应该为Item对象设置默认构造函数,因为永远不会有包含无效数据的Item对象。相信我,当我说它从长远来看使一切变得更容易。
Experimental solution
If you must use the SQL columns automatically (without having to specify each column), it's possible using reflection, but it's fairly brittle. It only works if the following is satisfied:
如果必须自动使用SQL列(无需指定每列),则可以使用反射,但它相当脆弱。仅在满足以下条件时才有效:
- The property names on the Java object are exactly the same as the SQL columns
- The property types on the Java object are the default types from ResultSet (primitives to Wrapper classes are ok)
Java对象上的属性名称与SQL列完全相同
Java对象上的属性类型是ResultSet中的默认类型(原语到Wrapper类都可以)
The reflection part can be put into a base class to be extended elsewhere. Here I've called it SimpleSQL. (This has the distinct feeling that I'm being too clever with this answer. I take no responsibility for this code; it's purely being presented as a "you could do this" scenario)
可以将反射部分放入基类中以在其他地方扩展。在这里,我称之为SimpleSQL。 (这有一种明显的感觉,我对这个答案太聪明了。我对这段代码不负任何责任;它纯粹是以“你可以做到这一点”的方式呈现)
import java.lang.reflect.*;
import java.sql.ResultSet;
public class SimpleSQL {
public SimpleSQL(ResultSet result) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
for (Field f: getClass().getDeclaredFields()) {
// Get the field type name, converting the first character to uppercase
String fTypNam = f.getType().getSimpleName();
fTypNam = fTypNam.substring(0,1).toUpperCase() + fTypNam.substring(1);
// Get an object that represents each of the methods we want to call
Method getM = result.getClass().getMethod("get" + fTypNam, String.class);
Method setM = f.getClass().getMethod("set", Object.class, Object.class);
// Set the property of this object using the field object's set
// and the ResultSet's get.
setM.invoke(f, this, getM.invoke(result, f.getName()));
// For a hypothetical 'id' field that is an int, this is equivalent to:
// this.id = result.getInt("id");
}
}
@Override
public String toString() {
String result = getClass().getName()+"[";
try {
Field[] fields = getClass().getDeclaredFields();
result += fields[0].getName() + ": " + fields[0].get(this);
for(int i = 1; i < fields.length; ++i) {
result += ", " + fields[i].getName() + ": " + fields[i].get(this);
}
} catch(IllegalAccessException e) {
// This happens if the field is private.
throw new RuntimeException(e.getMessage());
}
result += "]";
return result;
}
}
(see more on toString and reflection here. tl;dr, the Apache Commons library provides a ReflectionToStringBuilder class for a better version of my toString())
(请参阅更多关于toString和reflection的信息.tl; dr,Apache Commons库提供了一个ReflectionToStringBuilder类,用于更好的toString()版本)
Then you can just define your Item as:
然后你可以将你的项目定义为:
import java.lang.reflect.*;
import java.sql.*;
public class Item extends SimpleSQL {
protected int id;
protected String name;
protected String description;
public Item(ResultSet result) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
super(result);
}
}
#2
1
Your Item class should have getters()
, setters()
, constructor()
, and the toString()
methode like this:
你的Item类应该有getters(),setters(),constructor()和toString()方法,如下所示:
public class Item {
private int id;
private String name;
private String type;
public Item(int id, String name, String type) {
this.id = id;
this.name = name;
this.type = type;
}
//...Getters and Setters
@Override
public String toString() {
return "Item [id=" + id + ", name=" + name + ", type=" + type + "]";
}
}
So after that you should to create an object like this:
所以在那之后你应该创建一个像这样的对象:
while (result.next()) {
Item item = new Item(result.getInt("id"), result.getString("name"), result.getString("type"));
item.toString();
}
Hope this can help you.
希望这可以帮到你。
#1
2
Answer
It's your
Item item = new Item();
line. That says: "initialise an Item with NOTHING!" So of course you have empty objects. It should be:
线。这就是说:“用NOTHING初始化一个项目!”所以你当然有空物品。它应该是:
Item item = new Item(result.getInt(0), result.getString(1), result.getString(2));
Or whatever column names you gave them in the SQL table.
或者在SQL表中给出的任何列名。
Side note
It's bad practice to allow invalid objects. You shouldn't HAVE a default constructor for your Item object, because there should never be an Item object with invalid data. Trust me when I say it makes everything easier in the long run.
允许无效对象是不好的做法。您不应该为Item对象设置默认构造函数,因为永远不会有包含无效数据的Item对象。相信我,当我说它从长远来看使一切变得更容易。
Experimental solution
If you must use the SQL columns automatically (without having to specify each column), it's possible using reflection, but it's fairly brittle. It only works if the following is satisfied:
如果必须自动使用SQL列(无需指定每列),则可以使用反射,但它相当脆弱。仅在满足以下条件时才有效:
- The property names on the Java object are exactly the same as the SQL columns
- The property types on the Java object are the default types from ResultSet (primitives to Wrapper classes are ok)
Java对象上的属性名称与SQL列完全相同
Java对象上的属性类型是ResultSet中的默认类型(原语到Wrapper类都可以)
The reflection part can be put into a base class to be extended elsewhere. Here I've called it SimpleSQL. (This has the distinct feeling that I'm being too clever with this answer. I take no responsibility for this code; it's purely being presented as a "you could do this" scenario)
可以将反射部分放入基类中以在其他地方扩展。在这里,我称之为SimpleSQL。 (这有一种明显的感觉,我对这个答案太聪明了。我对这段代码不负任何责任;它纯粹是以“你可以做到这一点”的方式呈现)
import java.lang.reflect.*;
import java.sql.ResultSet;
public class SimpleSQL {
public SimpleSQL(ResultSet result) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
for (Field f: getClass().getDeclaredFields()) {
// Get the field type name, converting the first character to uppercase
String fTypNam = f.getType().getSimpleName();
fTypNam = fTypNam.substring(0,1).toUpperCase() + fTypNam.substring(1);
// Get an object that represents each of the methods we want to call
Method getM = result.getClass().getMethod("get" + fTypNam, String.class);
Method setM = f.getClass().getMethod("set", Object.class, Object.class);
// Set the property of this object using the field object's set
// and the ResultSet's get.
setM.invoke(f, this, getM.invoke(result, f.getName()));
// For a hypothetical 'id' field that is an int, this is equivalent to:
// this.id = result.getInt("id");
}
}
@Override
public String toString() {
String result = getClass().getName()+"[";
try {
Field[] fields = getClass().getDeclaredFields();
result += fields[0].getName() + ": " + fields[0].get(this);
for(int i = 1; i < fields.length; ++i) {
result += ", " + fields[i].getName() + ": " + fields[i].get(this);
}
} catch(IllegalAccessException e) {
// This happens if the field is private.
throw new RuntimeException(e.getMessage());
}
result += "]";
return result;
}
}
(see more on toString and reflection here. tl;dr, the Apache Commons library provides a ReflectionToStringBuilder class for a better version of my toString())
(请参阅更多关于toString和reflection的信息.tl; dr,Apache Commons库提供了一个ReflectionToStringBuilder类,用于更好的toString()版本)
Then you can just define your Item as:
然后你可以将你的项目定义为:
import java.lang.reflect.*;
import java.sql.*;
public class Item extends SimpleSQL {
protected int id;
protected String name;
protected String description;
public Item(ResultSet result) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
super(result);
}
}
#2
1
Your Item class should have getters()
, setters()
, constructor()
, and the toString()
methode like this:
你的Item类应该有getters(),setters(),constructor()和toString()方法,如下所示:
public class Item {
private int id;
private String name;
private String type;
public Item(int id, String name, String type) {
this.id = id;
this.name = name;
this.type = type;
}
//...Getters and Setters
@Override
public String toString() {
return "Item [id=" + id + ", name=" + name + ", type=" + type + "]";
}
}
So after that you should to create an object like this:
所以在那之后你应该创建一个像这样的对象:
while (result.next()) {
Item item = new Item(result.getInt("id"), result.getString("name"), result.getString("type"));
item.toString();
}
Hope this can help you.
希望这可以帮到你。