问题描述
我有一个接收 List 类型对象的方法。
它可以是字符串列表或字符串列表列表。
Java中有没有办法区分这两种对象?
我已经看到了 this 问题,但就我而言,AFAIK 在这两种情况下的对象都是 instanceof List
。
我还看到了几个关于 Python 中列表列表的类似问题,例如 this。
但是还是没看到Java中区分List of Strings和List of Strings Lists的方法。
解决方法
没有。具体来说,所有列表都只是列表,在运行时,泛型消失。如果编译器/编辑器无法告诉您,那么您也无法在运行时告诉您任何事情。
为了更具体一点,这两者之间有零区别:
void example() {
List<String> list1 = new ArrayList<String>();
List<List<String>> list2 = new ArrayList<List<String>>();
}
100% 相同 - 您无法以任何方式或形式使用这些列表来区分它们。
你可以绕过它 - 例如,给定一个 List<?>
,如果你运行 .get(0)
并且你得到的是 List
(同样,不可能告诉它是一个 List<String>
或一个 List<WhoKnowsWhat>
,只是它是一些列表),那么显然它不是一个字符串列表。可以是对象列表,也可以是字符串到整数映射列表的列表。没办法知道。
如果列表为空,则此 hack 不起作用。这不是个好主意。
那么解决方案是什么?
修复您的代码。在第一种情况下,您不应该出现在场景中。在您的代码库中的某个地方,您可以创建一个字符串列表或一个字符串列表列表,然后返回它。不要这样做,而是想出另一种方法。例如,对于类型层次结构:
public interface FullName {
public List<String> allNames();
public String rendered();
public List<String> get(int idx);
}
然后为各种“形式”中的每一种编写实现。以下是输入 List<String>
的实现:
private class SimpleName implements FullName {
private final List<String> name;
public SimpleName(List<String> name) {
this.name = name;
}
@Override public List<String> allNames() {
return name;
}
@Override public String rendered() {
return name.stream().collect(Collectors.joining(" "));
}
@Override public List<String> get(int idx) {
if (idx == 0) return name;
throw new IndexOutOfBoundsException();
}
}
关键是与这些交互的代码不需要关心你有什么样的名字;您可以想象必须对“名称”执行的任何操作都应该封装在此接口中,并且不同的实现可以包含有关如何执行这些任务的所有相关知识(以代码表示)。在调用代码确实需要知道的特殊情况下,他们可以 - 要么公开方法,要么只进行 instanceof 检查。