如何将List<String>转换为List<Object>

57

我想将List<String>转换为List<Object>

现有的一个方法返回List<String>,我想将其转换为List<Object>。Java中是否有直接的方式,而不是通过逐个迭代元素进行转换?


4
String 是一个 Object,那么为什么需要它呢? - khachik
7
你可能需要将列表传递给一个期望 List<Object> 的函数。 - Riley Lark
15
你到底想做什么?由于类型擦除的原因,List<String> 实际上是一个 List<Object>。如果你有一个接受 List<Object> 的方法,那么应该将该方法修改为 List<? extends Object>。如果你无法控制该方法,那么可以按照以下任一答案操作。 - Reverend Gonzo
是的,我需要将其转换为List<Object>,因为我必须将其传递回另一个接受类似List<Object>的方法。 - Alexs
7个回答

103

List<String>作为参数传递给新的ArrayList<Object>的构造函数。

List<Object> objectList = new ArrayList<Object>(stringList);
任何实现了类型扩展自 ArrayListCollection 都可以作为构造函数的参数传递,例如 String 继承自 Object。虽然构造函数需要一个 Collection,但是 ListCollection 的子接口,因此可以直接使用 List<String>

4
这会构建不必要的对象,如果列表很大,可能会占用大量内存。只需进行转换即可。 - Martin Algesten
2
请阅读我的评论。强制转换并不是正确的解决方案。这个答案不应该被点踩。 - Erick Robertson
好的,我会取消踩一下(6分钟或者编辑后才能取消)。但是我的回答也不应该被踩。 - Martin Algesten
@Martin。它只创建了一个额外的对象(其内部机制很小)。即使列表很大,内存使用也没有显着影响,因为存储的是引用值。没有涉及深层复制。此外,这将继续使用泛型来强制集合具有相同类型,而强制转换将被丢弃。 - OscarRyz
3
今天我刚解决了一个占用内存过多的问题,其中一个列表增长到了九千万以上的元素,只有引用而已,在一个线程中总共分配了1.3GB的内存(而且我有4-5个这样的线程)。这是一个bug,不过通常情况下这个列表最多只会有570万个元素,仍然很大。这要看具体情况和实际选择。类型转换并不是绝对禁止的。 - Martin Algesten

29
任何Java集合都只是对象的集合,无论是字符串或其他类型。类型参数只是语法糖。根据情况,例如处理非常大的列表,您可能只想转换它 - 显然会冒着将两种不同类型的对象混合在同一列表中的风险。
List<Object> objectList = (List)stringList;

添加@SuppressWarning以摆脱不良影响...


4
没错,为什么你已经有所需内容时还要构建新的集合呢?这是理性和有效的。 - Martin Algesten
9
之后你将拥有指向同一对象的两个引用。其中一个引用认为它是一个List<String>,而另一个引用认为它是一个List<Object>。如果你使用新引用添加非字符串对象,旧引用将无法访问它们,从而抛出ClassCastException异常。 - Erick Robertson
3
当然,你显然可以犯错,混淆苹果和梨子,但根据情况而定,这可能正是所需的。例如,如果这是一个仅在方法内部使用而不暴露的列表,我会毫不犹豫地这样做。这是一种务实的选择。 - Martin Algesten
2
好的,我已经澄清了,你需要知道你在做什么。 - Martin Algesten
我同意,在某些情况下,如果你想更高效地使用更少的内存,这是可行的方法。话虽如此,我总是会内联这样的转换,以便不存在具有误导类型的本地变量。例如:callUglyLegacyCode((List) strings) - qben

6

个人而言,尽管目前排名靠前的两个答案在某种程度上都是正确的,但我认为它们没有以一种优雅、可重用的方式解决问题,特别是如果您经常需要这样做。

假设您有一些旧的遗留代码/依赖关系,您无法以任何方式更改它(因此它至少会接受 List<?extends Object>,就像 @ReverendGonzo 在他的评论中建议的那样)。同时,假设您需要频繁与此遗留模块通信。

我认为长期来看,无论是进行强制转换/复制还是仅仅进行强制转换都是难以承受的。这会使您的代码易受到阴险的错误和难以跟踪,或者稍微(或严重)低效和难以阅读。

为了拥有可读性好且高效的生产代码,最好将肮脏的部分封装在一个单独的模块中,该模块处理本来无害但却很难看的强制转换。

class ProductionCode {
    public void doJob() {
        List<String> strings = Arrays.asList("pear", "apple", "peach");
        StringMagicUtils.dealWithStrings(strings);
    }
}

class StringMagicUtils {
    @SuppressWarnings("unchecked")
    public static void dealWithStrings(List<String> strings) {
        ExternalStringMagic.dealWithStringsAsObjects((List) strings);
    }
}

// Legacy - cannot edit this wonderful code below ˇˇ
class ExternalStringMagic {
    public static void dealWithStringsAsObjects(List<Object> stringsAsObjects) {
        // deal with them as they please
    }
}

5

如果你想将一个可修改的列表转换为不可修改的List<Object>,你可以简单地使用Collections.unmodifiableList方法来包装你的列表。这是有效的,因为该静态方法对于包装列表的元素类型有一个合适的通配符类型? extends T(其中T是结果列表的类型)。

请注意,在大多数情况下,创建一个不可修改的视图是你应该做的,否则在原始列表中可能会添加与String以外的其他类型的对象(原始列表只应包含String)。


最佳解决方案,时间和空间复杂度均为O(1)。 - silverbullettt

4

这相当低效,但至少你不必写太多代码~

List<String> stringList = new ArrayList<String>();
List<Object> objectList = Arrays.asList(stringList.toArray());

谢谢。我认为这不会在内存中创建一个新的ArrayList,只是将原始stringList转换为List<Object>。 - Alexs
@Alex 它不会创建一个新的 ArrayList,但它会创建一个内部的不可修改的 private List 实现,这个实现几乎就像 ArrayList。效果非常类似,但如果你需要向该列表添加一个新元素,就会遇到问题。此外,你“认为”节省的内存在之后创建新数组时被使用:stringList.toArray() 之后会创建一个新的分配数组。 - OscarRyz

1
List<Object> ofObjects = new ArrayList<Object>(ofStrings);

就像这样:

import java.util.*;
class C { 
  public static void main( String[] args ) { 
     List<String> s = new ArrayList<String>();
     s.add("S");
     List<Object> o = new ArrayList<Object>(s);
     o.add( new Object() );
     System.out.println(  o );

  }
}

作为替代方案,如果对象列表已经存在,您可以尝试使用addAll方法。

0

model.class

公共类模型{

private List<String> stringList = new ArrayList<>();

public List<String> getStringList() {
    return stringList;
}

public void setStringList(List<String> stringList) {
    this.stringList = stringList;
}

}

MainActivity

公共类 MainActivity 扩展自 AppCompatActivity {

Model model = new Model();
Spinner spinner;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    spinner=findViewById(R.id.spinner);

    List<String> itemList = new ArrayList<String>();
    itemList.add("item1");
    itemList.add("item2");
    itemList.add("item3");


   model.setStringList(itemList);


    ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, model.getStringList());
    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    spinner.setAdapter(dataAdapter);

}

}


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