Generic array in java issue - java

I have this bit of code and it keeps saying that it cannot create a generic array, but, I don't have a generic in my Node class, just an Object field. The Node class is an inner class. Why is it doing this?
public class TernarySearchTrie<E> implements TrieInterface<E> {
private Node[] root = new Node[256];
private int size = 0;
private class Node {
char c;
Node left, mid, right;
Object value;
}
}

Add the static modifier to Node class:
private static class Node {
char c;
Node left, mid, right;
Object value;
}
Without static, it depends of the TernarySearchTrie class, that have generics.

What you do in the problematic new Node[256] is actually TernarySeachTrie<E>.Node[256]. One solution is to use raw type:
Node[] root = TernarySearchTrie.Node[256];
Of course the compiler gives you a warning for this.

Related

Cascading Generic Type declarations in Java

I am having a hard time finding this anywhere if this is a common problem but I am dealing with what is essentially a cascading type problem.
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
}
I want to do something like this, however I can't instantiate the generic array this way. Where the getNodes() returns the content of the Nodes, not the Nodes themselves, but I can't figure out how.
I was thinking that the Node generic being defined by the Graph generic would mean that the Node class always has the same type as the Graph class. Is that not the case?
The Node class looks like
public class Node<E> {
private LinkedList<Edge> edges;
private E obj;
public E getObject() {
return obj;
}
// other useful stuff
}
Thanks for any help!
EDIT: all that is needed now is to make the returned Array of the right type. Is there a way to get an Array from an ArrayList that has a generic type assignment?
You need some form of reification of E in your getThings method.
If you want to keep the signature of getThings as it is, you can add a construtor parameter to provide the actual class E. With that class you can create an array to pass to the toArray(E[]) method of List<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);
}
Someone else came up with an answer that did not work but gave me an idea that ended up working, but they also put it in the comments section of the question so I will reiterate here and answer my own question.
This code works to solve the problem. I more or less lifted the logic from the ArrayList source code for their toArray(E[] a) function (with some of the meat of it cut out of course).
#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;
}
Look at the ArrayList source code in order to see some logic that goes a step farther and accomplishes the same task in a way that is also Thread safe.

Java inner class using outer class' parameterized type

Im creating an inner class in Java that uses outer class' parameterized types as instance fields.
Now when I try to create an arrayof this innerclass, I get classcast exception
class ModdedSeperateChainingAlternate<Key, Value> extends SeperateChainingHashST<Key, Value> {
int N;
int M;
Node[] list = (Node[]) new Object[M]; // classcast exception
class Node {
Node next;
Key key;
Value value;
int n;
public Node(Key k, Value v, Node next) {
this.key = k;
this.value = v;
this.next = next;
}
......
}
Please advice me on how to get around this. Im a generics noob
You are casting an Object[] to a Node[]:
Node[] list = (Node[]) new Object[M]; // classcast exception
The straightforward solution is to just create a Node[] instead:
Node[] list = new Node[M];
However, this fails due to the reason explained here:
Cannot create a generic array of TWTestCase.ModdedSeperateChainingAlternate.Node
So, to achieve your goal, you need to use some Collection instead, preferably a List:
List<Node> list = new ArrayList<Node>(M);
And while you are at it, instance variables should be camel case according to Java standards:
int m;
And further, int m will have the default integer value, which is 0. In other words you will create a zero-length array. Make sure the varaible is initialized (e.g. int i = 5).
As for the generics part, Node derives its types from ModdedSeperateChainingAlternate<Key, Value>. You can read more about generics here.
Node is a non-static nested class. That means it is within the scope of the type parameter of the outer class, and is effectively "parameterized" by that type parameter even though it is not directly on Node.
When you write a bare Node inside ModdedSeperateChainingAlternate, it implicitly means ModdedSeperateChainingAlternate<Key, Value>.Node, which is a parameterized type. You cannot create an array of a parameterized type, e.g. You cannot do new ArrayList<String>[M]; for the same reason, you cannot do new Node[M] (which is equivalent to new ModdedSeperateChainingAlternate<Key, Value>.Node[M]).
Instead, you can do either:
create an array of the raw type, like new ArrayList[M]. But how do you write the raw type in this case? It is not Node as we have seen. Instead, you have to explicitly qualify it with the raw outer type:
Node[] list = new ModdedSeperateChainingAlternate.Node[M];
or, create an array of the type parameterized with all wildcards, like new ArrayList<?>[M]. In this case, it would be:
Node[] list = (Node[])new ModdedSeperateChainingAlternate<?, ?>.Node[M];

Declare and initialize in a method that has the same name as the class and data type

I am new to object oriented programming and I am trying to declare and initialize left, but I don't know how to do it. I tried
left = new Counter(4, left.mod);
But it Netbeans is saying that
incompatible types: int cannot be converted to Number
This is not the real program.
public class Number{
private int mod;
public Number(int modulus, Number left) {
mod = modulus;
//how to declare left?
}
It seems like you are trying to implement some sort of linked list etc. Obviously you want left to be remembered, so declare it just like any other normal property of the class.
public class Number{
private Number left;
private int mod;
public Number(int modulus, Number left) {
mod = modulus;
this.left = left;
}
}
If you really need to interact with two classes that have the same name in a class, you'll have to use the fully-qualified name to refer to one or the other. So, if for instance you want to refer to a java.lang.Number inside your own Number class, you'd do
public class Number{
private java.lang.Number left;
private int mod;
public Number(int modulus, java.lang.Number left) {
mod = modulus;
this.left = left;
}
}
(note that my emphasis on really is indicating that, as you can probably already guess, it's generally more trouble than it's worth to give a class the same name as a commonly-used library type).

Casting a string to an object

when I create an object of the class BinaryTreeNode , I want to pass two String in the Constructor rather than an object of the class BinaryTreeNode how can I do that.
BinaryTreeNode(BinaryTreeNode left,BinaryTreeNode right) {
this.left = left;
this.right = right;
}
BinaryTreeNode b = new BinaryTreeNode("B","A");
Write another constructor that takes two String parameters.
BinaryTreeNode(String left, String right) {
//whose knows why I want to do this...
}
You can't cast a String into a BinaryTreeNode, that would throw an Exception.
It is not possible to cast any object to a type which it is not.
But that is fine, and I suspect it is not the root of the problem, because it doesn't make sense to treat a String object as a BinaryTreeNode - they have naught in common except that which they both inherit from Object.
Thus, I would either make the "node/leaf value" part of the BinaryTreeNode type or, I may introduce a leaf node type such as:
class BinaryTreeLeafNode extends BinaryTreeNode {
public final String value;
public BinaryTreeLeafNode (String value) {
super(null, null); // got anything better? :|
this.value = value;
}
}
Then:
tree = new BinaryTreeNode(
new BinaryTreeLeafNode("Left"),
new BinaryTreeLeafNode("Right"));
And perhaps if I wanted to hide the details, then an overload could be introduced:
public BinaryTreeNode (String leftValue, String rightValue) {
this(new BinaryTreeLeafNode(leftValue), new BinaryTreeLeafNode(rightValue));
}
(I would advise against widening the left/right member and constructor types to to Object, as that will eliminate a good bit of type-safety.)

static final variables in a generic class causing unchecked & rawtype warnings

Is it a design flaw to have a static final variable in a generic class? Consider the class below, all references to Node.SOIL give rise to warnings. What is a good way of going about solving this problem?
public class Node<E> {
private static int nodeCounter = 0;
#SuppressWarnings({ "unchecked", "rawtypes" })
public static final Node SOIL = new Node(null, null); // <-- HERE
public static void resetSOIL(){
SOIL.children = null; // <-- HERE
}
private Node<E> parent;
private Set<Node<E>> children;
protected Set<Node<E>> isomorphs;
private E data;
private int id;
public Node(Node<E> parent, E data){
this.parent = parent;
this.data = data;
this.id = ++nodeCounter;
}
public boolean isRoot(){
return (this.getParent() == SOIL);
}
// utility methods
....
}
You've defined a type Node<E> which represents a node in a tree of E's. For example, Node<Integer> is a node in a tree of Integers, and Node<String> is a node in a tree of Strings.
Now you want a variable SOIL that contains all the roots of these various trees of different types (hehe, soil, I get it now). Set aside the static field issue for now. What should the class of SOIL be? In other words, how do we declare and create the SOIL instance?
Node</*something1*/> SOIL = new Node</*something2*/>(null, null);
Since SOIL is going to have children that are Node<Integer> and Node<String> then it has to be something like Node<?> or Node<Object>. You can't instantiate an object using a wildcard type argument, so the best you can do is something like this:
Node<?> SOIL = new Node<Object>(null, null);
(If you use the Java 7 diamond construct new Node<>(...) it ends up using Object in this case anyway.)
The problem is, this still doesn't work. The way the Node<E> type is defined is as a homogeneous tree of E's. But one subtree of SOIL is a tree of Integers and another subtree is a tree of Strings, so SOIL wants to be a heterogeneous tree. Therefore, SOIL cannot be a Node<E> for any E.
At least, not in a type-safe fashion. You could write the code to do this, but you'd have to add some casts, and you'd get unchecked warnings. These warnings would tell you that this approach isn't working. For example, consider some code that takes a Node<E> and operates on all of its siblings (that is, the other children of its parent). Some code that took a Node<Integer> could call this and end up with a bunch of instances of Node<String> and start throwing ClassCastExceptions.
You might consider making SOIL a Set<Node<?>> and not making it be the parent of all the roots. You could make it a static field somewhere, but make it private.
It's not a design flaw to have a static final variable. The warning appears because you are declaring an instance of a generic type without providing a type parameter:
public static final Node SOIL = new Node(null, null); // <-- HERE
when the compiler is expecting something like:
public static final Node<SomeType> SOIL = new Node<SomeType>(null, null);
You could use this to avoid suppressWarnings and it works well:
private static final Node<Object> SOIL = new Node<Object>(null, null);
To answer to your other question:
Is it a design flaw to have a static final variable in a generic class?
No itsnt, it is even a good common practice to use it as default for null variables of type Node, aka the NULL object in Effective Java Programming

Categories