Java 中的级联泛型类型声明
Cascading Generic Type declarations in Java
如果这是一个常见问题,我很难在任何地方找到它,但我正在处理本质上是级联类型的问题。
public class Graph<E> {
private LinkedList<Node<E>> nodes;
public Graph() {
this.nodes = new LinkedList<>();
}
public E[] getNodes() {
ArrayList<E> list = new ArrayList<>();
for (Node<E> node : nodes)
list.add(node.getObject());
return list.toArray(new E[0]); // any way to make this line work?
}
// other important stuff
}
我想做这样的事情,但是我不能用这种方式实例化通用数组。其中 getNodes() returns 节点的内容,而不是节点本身,但我不知道如何。
我在想由 Graph 泛型定义的 Node 泛型将意味着 Node class 始终与 Graph class 具有相同的类型。不是这样吗?
节点 class 看起来像
public class Node<E> {
private LinkedList<Edge> edges;
private E obj;
public E getObject() {
return obj;
}
// other useful stuff
}
感谢您的帮助!
编辑:现在所需要做的就是使返回的数组具有正确的类型。有没有办法从具有泛型类型分配的 ArrayList 中获取数组?
您需要在 getThings
方法中对 E 进行某种形式的具体化。
如果你想保持 getThings
的签名不变,你可以添加一个构造函数参数来提供实际的 class E
。使用那个 class 你可以创建一个数组传递给 List<E>
的 toArray(E[])
方法
private final Class<E> type;
private final List<E> list;
public CustomClass(Class<E> type) {
this.type = type;
this.list = new ArrayList<>();
}
@SuppressWarnings("unchecked")
public E[] getThings() {
Object[] reference = (Object[]) Array.newInstance(type, list.size());
return (E[]) list.toArray(reference);
}
其他人提出了一个无效的答案,但给了我一个最终有效的想法,但他们也把它放在了问题的评论部分,所以我会在这里重申并回答我自己的问题。
这段代码可以解决问题。我或多或少地从 ArrayList 源代码中提取了他们的 toArray(E[] a)
函数的逻辑(当然其中的一些内容被删掉了)。
@SuppressWarnings("unchecked")
public E[] getNodes(E[] a) {
int size = nodes.size();
// creates an empty array of the right size and type
E[] arr =(E[]) java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
// fills that array with the correct data
for (int i = 0; i < size; i++)
arr[i] = nodes.get(i).getObject();
return arr;
}
查看 ArrayList 源代码,以了解更进一步的一些逻辑,并以线程安全的方式完成相同的任务。
如果这是一个常见问题,我很难在任何地方找到它,但我正在处理本质上是级联类型的问题。
public class Graph<E> {
private LinkedList<Node<E>> nodes;
public Graph() {
this.nodes = new LinkedList<>();
}
public E[] getNodes() {
ArrayList<E> list = new ArrayList<>();
for (Node<E> node : nodes)
list.add(node.getObject());
return list.toArray(new E[0]); // any way to make this line work?
}
// other important stuff
}
我想做这样的事情,但是我不能用这种方式实例化通用数组。其中 getNodes() returns 节点的内容,而不是节点本身,但我不知道如何。
我在想由 Graph 泛型定义的 Node 泛型将意味着 Node class 始终与 Graph class 具有相同的类型。不是这样吗?
节点 class 看起来像
public class Node<E> {
private LinkedList<Edge> edges;
private E obj;
public E getObject() {
return obj;
}
// other useful stuff
}
感谢您的帮助!
编辑:现在所需要做的就是使返回的数组具有正确的类型。有没有办法从具有泛型类型分配的 ArrayList 中获取数组?
您需要在 getThings
方法中对 E 进行某种形式的具体化。
如果你想保持 getThings
的签名不变,你可以添加一个构造函数参数来提供实际的 class E
。使用那个 class 你可以创建一个数组传递给 List<E>
toArray(E[])
方法
private final Class<E> type;
private final List<E> list;
public CustomClass(Class<E> type) {
this.type = type;
this.list = new ArrayList<>();
}
@SuppressWarnings("unchecked")
public E[] getThings() {
Object[] reference = (Object[]) Array.newInstance(type, list.size());
return (E[]) list.toArray(reference);
}
其他人提出了一个无效的答案,但给了我一个最终有效的想法,但他们也把它放在了问题的评论部分,所以我会在这里重申并回答我自己的问题。
这段代码可以解决问题。我或多或少地从 ArrayList 源代码中提取了他们的 toArray(E[] a)
函数的逻辑(当然其中的一些内容被删掉了)。
@SuppressWarnings("unchecked")
public E[] getNodes(E[] a) {
int size = nodes.size();
// creates an empty array of the right size and type
E[] arr =(E[]) java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
// fills that array with the correct data
for (int i = 0; i < size; i++)
arr[i] = nodes.get(i).getObject();
return arr;
}
查看 ArrayList 源代码,以了解更进一步的一些逻辑,并以线程安全的方式完成相同的任务。