What are generic arrays in Java? - java

I have a code, whose MCVE is like this
import java.util.LinkedList;
public class Test
{
LinkedList<Node>[] arr;
Test(){
arr = new LinkedList<Node>[4];
}
public static void main(){
}
}
class Node{
}
where I get this error
error: generic array creation
arr = new LinkedList<Node>[4];
^
I looked for the error and found these two posts
How to create a generic array in Java?
and Error: Generic Array Creation
But I don't understand what a generic array is. I guess(from what I get from the two posts) it means array that does not know what type it's going to store, but in my case the array is specified to be of LinkedList<Node> type.
Can someone explain the concept?

Please check the following answer:
https://stackoverflow.com/a/18581313/303810
Since it is a bit large, I'll sum up the relevant part here.
LinkedList<Node>[] is a generic array as it has generic type of the component. The problem with this consruct is that you could do the following:
LinkedList<Node>[] listsOfNodes = new LinkedList<Node>[1];
Object[] items = listsOfNodes;
items[0] = new LinkedList<String>();
So at this point listsOfNodes[0] which should have had the type LinkedList<Node> would be an instance of LinkedList<String>.

Related

Java Array with the same name as a class name

I really can't find any information about it that's why I'm asking here.
I'm trying to figure out what is it type of Array if it has same name as a class... like:
public class ArrayOne {
int SomeInt;
ArrayOne [] arr;
public ArrayOne(SomeInt){
arr=new ArrayOne[1];
}
}
Maybe someone know where can I read about it. Thanks a lot
If you declare an array like this:
int[] myIntArray = new int[3];
you have an array of int (remember that int in java is not an object)
So if you write:
ArrayOne[] arr;
You will have an array of object from class ArrayOne.
If you are still in doubt, you can check an array type like this:
Class ofArray = o.getClass().getComponentType();
take a look here : http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getComponentType--
public Class getComponentType()
Returns the Class representing the component type of an array. If this class does not represent an array class this method returns null.
That would be an array of that classes objects.
Your arr variable will be of Array type, which contains objects of ArrayOne type.
If the question is around naming, then your array is named arr but not after the class which it is typed with.

Generic list conversion to an array

Assuming that I have the following class
public class A <T>{
private T [] datas;
// more code here ...
}
And I desire to take advantage of the constructor to initialize the array. Suppose that I have the following constructor
public A(T element){....}
Java does not allow me to use something like
datas = new T[10]
And it will complain that I cannot create a generic array of T
But I can still use a work around like:
#SuppressWarnings("unchecked")
public A(T element){
List<T> datasList = new ArrayList<T>();
datasList.add(element);
datas =(T[]) datasList.toArray();
}
I have a warning from the compiler that's why I had to add the #SuppressWarnings, but my point is related to the following comment from the toArray method documentation (Please take a look at the picture)
It talks about the returned array being safe. So does that means it is safe to use this method? If not why? And what would be a better way to do such an initialisation in a constructor? I would like to also consider the case of a variable list of T elements in an overloaded constructor like
public A(T... elements){....}.
You can create an instance of a generic array using the following:
public A(T element){
int length = 10;
datas = (T[])Array.newInstance(element.getClass(), length);
}
However, there's a problem if element would be a subclass of T, e.g. if you'd call it like this:
A<Number> numberA = new A<>( Integer.valueOf(1) );
Here T would be Number but the class of element would be Integer.
To mitigate that you could pass a vararg array of type T, e.g. like this:
//firstElement only exists to force the caller to provide at least one element
//if you don't want this then just use the varargs array
A(T firstElement, T... furtherElements){
int length = 10;
Class<?> elementClass = furtherElements.getClass().getComponentType();
datas = (T[])Array.newInstance( elementClass, length);
}
Since varargs always result in an array (even of length 0) you'll get an array of type T and can get the component type of that.
So in the case above numberA.datas would be a Number[] array and not an Integer[] array.
You can pass generics, but you can't call new T (or new T[ ]).
Keep in mind that generics are gone after compilation, so it actually only helps when writing the code. Knowing it's gone during runtime, it's also obvious that new T( ) can't be called as generic, T is removed in runtime.
It's safe to do, because you create that list in full control, accepting only objects of your generic type.
A nicer way (imho) is to create a static method as it is purely input-->output. You have to declare your generics before the method return type:
public < T > T[ ] toArray(T... objects) { ... }

how can I create a regular array that contain a generic type I created in java? [duplicate]

This question already has answers here:
How to create a generic array in Java?
(32 answers)
Closed 8 years ago.
I have for example the following class
public class MyClass<T> {
private int id;
T content;
}
and in other part of my project I want to create a method that return Myclass<byte[]>[]
I wrote this code
Myclass<byte[]>[] tempArray=new Myclass<byte[]>[4];
>
the eclipse says "cannot create a generic array of Myclass<byte[]
anyone knows how to solve it?
You cannot create arrays of parametrized types, as stated in the Java SE tutorial
(...)You cannot create arrays of parameterized types.
For example, the following code does not compile:
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error
The following code illustrates what happens
when different types are inserted into an array:
Object[] strings = new String[2];
strings[0] = "hi"; // OK
strings[1] = 100; // An ArrayStoreException is thrown.
If you try the same thing with a generic list, there would be a problem:
Object[] stringLists = new List<String>[]; // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>(); // OK
stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown,
// but the runtime can't detect it.
If arrays of parameterized lists were allowed,
the previous code would fail to throw the desired ArrayStoreException.(...)
It has nothing to do with primitive types or objects, as you can see from the example below
public class Generics<T> {
T x;
public static void main(String[] args) {
Generics<byte[]> g = new Generics<byte[]>();
g.x = new byte[10];
g.x[1] = 1;
}
Generics<T>[] getMyArray(){
Generics<Byte[]>[] array = new Generics<Byte[]>[1]; <<<<error
}
}
In java you cannot create an array of an generic type.
this question has good answers
But basically at runtime arrays need to information on its objects type, so you must know the array's type when you create the array. But since you have no idea what T is at runtime, you cannot create the array

HashTable generic array creation error [duplicate]

This question already has answers here:
How to create a generic array in Java?
(32 answers)
Closed 9 years ago.
This is a grade 12 java HashTable assignment.
So my teacher gave me the template for doing this assignment, but it does not work :(. And he expects us to get the template to work and then do the assignment.
Here's what he gave us:
class MyHashTable<T>{
private T[] vals;
private int load;
public MyHashTable(){
load = 0;
vals = new T[10];
}
public MyHashTable(int size){
load = 0;
vals = new T[size];
}
public void add(T obj){//don't care about negatives
int size = vals.length;
if((load+1.0)/size>0.6){
size*=10;
T[] tmp = new T[size];
for(int i=0;i<size/10;i++){
if(vals[i]!=null){
add(vals[i], tmp);
}
}
vals = tmp;
}
add(obj, vals);
}
public void add(T obj, T[]vals){
int loc = Math.abs(obj.hashCode())%vals.length;
while(vals[loc]!=null){
loc = (loc+1)%vals.length;
}
vals[loc] = obj;
}
/*public boolean contains(T obj){
} */
}
it gives an error: error: generic array creation
Can anyone tell me what does that mean? With examples hopefully.
Due to the way that generics are implemented in Java, it is not possible to use generics such that type information is needed at runtime. See this.
error: generic array creation
You can not create arrays from generic types.
See also What's the reason I can't create generic array types in Java?
As everybody said generic type is erased at runtime:
T becomes Object,
T extends SomeClass becomes SomeClass.
So you have at least two options
You can use same pattern that was used in ArrayList<T> and store items in Object[] array rather then T[] array
vals = (T[]) new Object[size];
If you want to create array of real T type you would have to make user to pass instance of Class<T> object that will correspond T and use it like
vals = (T[]) java.lang.reflect.Array.newInstance(clazzT, size);
where clazzT is Class<T> instance.

Java Is there any way to initialize a generic array that's type safe?

I have the following code
public class Container<T> {
private T element;
private T[] tarray;
public T getElement() {
return element;
}
public void setElement(T element) {
this.element = element;
}
public void add(T element) {
tarray[0] = element;
}
public void CreateArray(int size) {
//Can this be cleaned up better?
tarray = (T[]) new Object[size];
}
public T get() {
return tarray[0];
}
public Container(T someElement) {
this.element = someElement;
}
public Container() {
}
public static void main(String[] args) {
Container<String> myContaier1 = new Container<String>();
myContaier1.setElement("Hello");
myContaier1.CreateArray(1);
myContaier1.add("GoodBye");
System.out.println(myContaier1.get());
}
}
Is there no way to initialize a type safe generic array?
There is no way unless you provide a reified T in the form of an actual Class<T> object that represents a specific value of T. This is because the array type is reified, whereas the Generic type isn't.
There are two problems here:
First of all, the actual type of your array will always be Object[]. You cast it to T[], but this works only because T[] erases to Object[]. If your class definition said, for example, <T extends Number>, then (T[])new Object[] would fail with a ClassCastException.
You could get around this by passing Class<T> to the constructor of your collection and keeping it in a field:
private Class<T> componentClass;
...
tarray = (T[]) Array.newInstance(componentClass, size);
Now the actual in-memory type of tarray is T[], but you still get an unchecked cast error. Even though you have the component class, as far as I know there is no equivalent of Class.cast() for doing a checked cast of an array instance.
You can do private T[] tarray;, But you cannot assign it to (T[]) new Object[size];. How can an array of Object be same an array of any other class.
T is not even there after compilation.
It is called type erasure. E.g if you do
List<Person> persons = new ArrayList<Person>();
It becomes List persons = new ArrayList() after compilation.
It is similar to ask "Is there a way to initialize a generic object: new T()?"
Of course it is impossible, as the compiler does not know what the type is of it.
Array is the same, its type relies on its elements. If the type of its elements is unknown, the type of itself is unknown.
Those classes which can take generic types like List, Set, Map, etc. are different. They have their own classes as types and they are dynamic, so you can initialize one like new ArrayList<T>().
You can try on this:
public class Test {
public static void main (String args[]) {
int[] i = new int[3];
short[] s = new short[4];
ArrayList<String> a = new ArrayList<String>();
System.out.println(i.getClass().getName());
System.out.println(s.getClass().getName());
System.out.println(args.getClass().getName());
System.out.println(a.getClass().getName());
}
}
You will see the types of elements are already combined with the arrays, while not combined with ArrayList.
There are way to do this on the JVM, but to do something like this in Java would require writing a lot of boiler plate code. In Scala, you can use Manifests to get around type erasure, and can instantiate generic arrays without casting.
An example:
class Container[T : Manifest]() {
def createArray(size:Int) = Array.ofDim[T](size)
}
scala> val f = new Container[String]
f: Container[String] = Container#12f3aa66
scala> f.createArray(5)
res7: Array[String] = Array(null, null, null, null, null)
Scala code compiles to the same bytecode class files as Java (implying that this should be possible in Java if you jumped through enough hoops and maybe wrote your own manifests). Scala classes can be imported into Java projects... though I'm not sure how hard it is to instantiate a class like this from Java.
If you often find yourself wanting to be able to handle more complicated type situations, have a look at Scala, you might like it.

Categories