Reputation: 7405
How would I modify this so the resulting Collection (newNodes) is the same type as the incoming one (nodes)?
public void setNodes(Collection<NodeInfo> nodes) {
Collection<NodeInfo> newNodes = new TreeSet<NodeInfo>();
for (NodeInfo ni: nodes) {
newNodes.add(ni.clone());
}
}
I suspect it's something like...
public void setNodes(<T extends Collection<NodeInfo>> nodes) {
Collection<NodeInfo> newNodes = new T<NodeInfo>()
Is this possible?
Upvotes: 1
Views: 1675
Reputation: 81684
Note that many of the Collection
implementations in the JDK implement Cloneable
themselves. One "best effort" approach might be like this:
public Collection<NodeInfo> setNodes(Collection<NodeInfo> nodes) throws CloneNotSupportedException {
Collection<NodeInfo) newNodes;
if (nodes instanceof Cloneable)
newNodes = (Collection<NodeInfo>) newNodes.clone();
else
// Fallback in case we have a non-cloneable collection
newNodes = new TreeSet<NodeInfo>();
newNodes.clear();
for (NodeInfo ni: nodes) {
newNodes.add(ni.clone());
}
return newNodes;
}
This returns the same kind of collection for many inputs, but will fall back to returning a TreeSet
as a default if it can't do any better.
Upvotes: 0
Reputation: 12766
Close, but no cigar. If I understand what you want to do, your method should look like:
public <T extends NodeInfo> void setNodes(Collection<T> nodes) {
Collection<T> newNodes = new TreeSet<T>();
for(T t : nodes) {
newNodes.add(t);
}
}
Upvotes: 2
Reputation: 7447
Unfortunately, you cannot do new T
in Java: Since generics are implemented in Java via type erasure, the type information that is provided by a type parameter is only statically usable information, i.e. no longer available at runtime. Hence Java does not permit generic creation of objects (cf. Angelika Lange's Generics FAQ).
Alternatively, you could use:
Class<T>
object as parameter to make the type available at runtimevoid setNodes(Collection<NodeInfo> nodes, Collection<NodeInfo> newNodes)
if you are able to create the suitable Collection elsewhereArrayList<NodeInfo>
deep clone nodes
, e.g. using The Cloning Library:
Cloner cloner=new Cloner();
@SuppressWarnings("unchecked") Collection<NodeInfo> newNodes = cloner.deepClone(nodes);
Upvotes: 1
Reputation: 14025
Unfortunately, it's not possible as you've written it in Java. If you need this effect, you've got a few choices:
If you're trying to optimize for a particular kind of collection, you can use an instanceof
check to detect it. (For instance the Guava libraries often do this to detect immutable collections and handle them specially.)
If you really just need one collection to populate, you can ask the caller to provide you one.
public <C extends Collection<NodeInfo>> void setNodes(C nodes, C newNodes) {
for (NodeInfo ni : nodes) {
newNodes.add(ni);
}
}
If you need the ability to make an arbitrary number of these collections on demand, then you can define a factory interface and make the caller provide an instance of it:
interface Factory<C extends Collection<NodeInfo>> {
C newCollection();
}
public <C extends Collection<NodeInfo>> void setNodes(C nodes, Factory<C> factory) {
C newNodes = factory.newCollection();
for (NodeInfo ni : nodes) {
newNodes.add(ni);
}
}
Upvotes: 2