Java - 混合ArrayLists?

11

在 ArrayList 中存储不同类型的对象是否可能?如果可以,如何实现?

这是我目前尝试过的方法:

List<Object> list = new ArrayList<Object>();

list.add(new String("Hello World"));
list.add(new Integer(1));
list.add(new Long(1l));

for (i = 0; i < list.size(); i++) {
    if (list.get(i) instanceof String){
        sqlPreparedStatement.setString((i+1), (String) list.get(i));
    } else if (list.get(i) instanceof Integer) {
        sqlPreparedStatement.setInt((i+1), (Integer) list.get(i));
    } else if (list.get(i) instanceof Long) {
        sqlPreparedStatement.setLong((i+1), (Long) list.get(i));
    }
}

但它抛出了一个类型转换异常。

提前感谢任何输入!


7
无法正常工作。 - Oliver Charlesworth
为什么要使用Object进行参数化?这样做可以得到什么? - Jeremy
8
@Jeremy:它避免了Eclipse中烦人的、摇晃的黄色下划线! - Oliver Charlesworth
1
请显示您的异常堆栈跟踪。有趣的点将是ClassCastException的行号(并在源代码中标记此行号)。源代码看起来很好,除了像scientiaesthete答案中的一些优化以及那里多余的new String(...) - Paŭlo Ebermann
@Paulo是正确的。找出问题所在的正确方法是查看堆栈跟踪。您的List的顺序是否与PreparedStatement中发生的情况相匹配? - Atreys
3个回答

20

以下是您应该拥有的内容:

List<Object> list = new ArrayList<Object>();

list.add(new String("Hello World"));
list.add(new Integer(1));
list.add(new Long(1l));

for (Object obj: list) {
    if (obj instanceof String){
        sqlPreparedStatement.setString((String) obj);
    } else if (obj instanceof Integer) {
        sqlPreparedStatement.setInt((Integer) obj);
    } else if (obj instanceof Long) {
        sqlPreparedStatement.setLong((Long) obj);
    }
}

6
顺便说一下,其实不需要使用"new String()"。 - Paul Cager
2
@scientiaesthete:除了List#get(int)被调用的次数比你的代码多一倍,以及使用迭代器之外,你的代码片段和OP的没有区别。我是否漏掉了什么 - 在强制转换方面有什么区别吗? - bguiz
1
@bguiz,setXXX()的签名不同。OP的是setXXX(int, XXXthing),而这个只有setXXX(XXXthing)。其中一个与API不匹配,我想。 - Atreys
1
@Atreys:是的,这个“答案”是错误的,事实上,OP的代码更好,因为它实际上可以编译并给for循环提供一个int参数,该参数可以在准备好的语句的方法调用中使用。我不得不想知道这个答案是如何得到5个赞成票的?我给它投了反对票。 - Hovercraft Full Of Eels
1
实际上,使用自动装箱时不需要任何 new - trutheality
显示剩余3条评论

13

抱歉打断你的想法,但你本应该避免使用一个包含三种(或任何数量)不同类型的ArrayList。如果这些信息相关,应该创建一个持有相关信息的类,并创建一个仅保存这个类对象的ArrayList。

Edit 1:
例如,可以创建一个用于保存数据的类:

class SqlData {
   private String textData;
   private int intData;
   private long longData;

   public SqlData(String textData, int intData, long longData) {
      this.textData = textData;
      this.intData = intData;
      this.longData = longData;
   }

   public String getTextData() {
      return textData;
   }

   public int getIntData() {
      return intData;
   }

   public long getLongData() {
      return longData;
   }

}

并且可以这样使用:

  List<SqlData> sqlDataList = new ArrayList<SqlData>();
  sqlDataList.add(new SqlData("Hello World", 1, 11L));

  for (int i = 0; i < sqlDataList.size(); i++) {
     try {
        sqlPreparedStatement.setString(i + 1, sqlDataList.get(i).getTextData());
        sqlPreparedStatement.setInt(i + 1, sqlDataList.get(i).getIntData());
        sqlPreparedStatement.setLong(i + 1, sqlDataList.get(i).getLongData());
     } catch (SQLException e) {
        e.printStackTrace();
     }
  }

2
这种方法更加描述性。但我认为我们不需要在这里使用 sqlDataListfor 循环。 - Genzer
+1 @Hovercraft:只是为了抵消你可能遭受的“报复”踩;而且我也同意,在任何列表中,你不应该混合不同类型的对象;除非是继承的类型(遵守“is-a”规则)可能有例外。 - bguiz
1
虽然在列表中不应该混合使用不同类型的对象,但这并不意味着人们不能这样做,也不意味着没有软件存在其中含有这种类型的代码。 - Atreys
1
@Atreys:这不是“不能”的问题,而是当一个人遵循这种不良实践时,创建难以调试、维护和扩展的软件的问题。 - Hovercraft Full Of Eels
我非常喜欢这个答案,因为它教你正确的做事方式!很多时候,人们只是为了回答问题而回答问题,而不是看整个大局! - Sam Malayek

5
为什么你要把这个问题搞得那么复杂?PreparedStatement有一个setObject()方法 - 直接使用它即可:
    List<Object> list = new ArrayList<Object>();
    list.add(new String("Hello World"));
    list.add(new Integer(1));
    list.add(new Long(1l));
    for (int i = 0; i < list.size(); i++)
        sqlPreparedStatement.setObject(i + 1, list.get(i)); // NOTE: columns count from 1

注意:Java SQL API计数从1开始,而不是从零开始,因此列的编号为1...size(),而不是0...size()-1


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接