I am creating a list data structure and am having trouble with the generics syntax for actually using it. All I am trying to do is create an instance of ArrayLinearList<String> and of size 2 and put some strings in it. I have been trying to figure out why setting the first slot to "one" is not correct. This is the error and my code snippet.
myList[0] = "one";
The error message is: error: incompatible types: String cannot be converted to ArrayLinearList<String>
public class ArrayLinearList<E> implements LinearListADT<E> {
private Object[] array;
int currentSize = 0;
//Constructor (no arguments)
public ArrayLinearList() {
currentSize = 2;
// array = (ArrayLinearList[]) new Object[2]; //Start with a container of size 2
array = new Object[2];
}
public static void main(String[] var0) {
ArrayLinearList<String>[] myList;
myList = new ArrayLinearList[2];
myList[0] = "one";
}
}
I am having quite a bit of trouble with the syntax with using generics in java. In my mind I have an array of size 2 where I am going to be placing strings. I will add more methods later but I want to understand why my current syntax is incorrect for placing this string in the array.
Here:
ArrayLinearList<String>[] myList;
you define an array that holds ArrayLinearList<String> elements, not Strings, this is why you get the error message.
Your code here
ArrayLinearList<String>[] myList;
myList = new ArrayLinearList[2];//you have defining array myList of type ArrayLinearList
myList[0] = "one";//you are trying to store String to array which can hold ArrayLinearList
Here ArrayLinearList<String> means that your list will hold values of type String (provided we define it correctly in the code). But ArrayLinearList<String>[] will hold only reference of type ArrayLinearList and not String itself.
You need to use
myList.array[0] = "one";
Because myList is not an array. It's an object which you use to store an array within.
Related
I am trying do something like this:-
public static ArrayList<myObject>[] a = new ArrayList<myObject>[2];
myObject is a class. I am getting this error:- Generic array creation (arrow is pointing to new.)
You can't have arrays of generic classes. Java simply doesn't support it.
You should consider using a collection instead of an array. For instance,
public static ArrayList<List<MyObject>> a = new ArrayList<List<MyObject>();
Another "workaround" is to create an auxilliary class like this
class MyObjectArrayList extends ArrayList<MyObject> { }
and then create an array of MyObjectArrayList.
Here is a good article on why this is not allowed in the language. The article gives the following example of what could happen if it was allowed:
List<String>[] lsa = new List<String>[10]; // illegal
Object[] oa = lsa; // OK because List<String> is a subtype of Object
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[0] = li;
String s = lsa[0].get(0);
There is a easier way to create generic arrays than using List.
First, let
public static ArrayList<myObject>[] a = new ArrayList[2];
Then initialize
for(int i = 0; i < a.length; i++) {
a[i] = new ArrayList<myObject>();
}
You can do
public static ArrayList<myObject>[] a = (ArrayList<myObject>[])new ArrayList<?>[2];
or
public static ArrayList<myObject>[] a = (ArrayList<myObject>[])new ArrayList[2];
(The former is probably better.) Both will cause unchecked warnings, which you can pretty much ignore or suppress by using: #SuppressWarnings("unchecked")
if you are trying to declare an arraylist of your generic class you can try:
public static ArrayList<MyObject> a = new ArrayList<MyObject>();
this will give you an arraylist of myobject (size 10), or if u only need an arraylist of size 2 you can do:
public static ArrayList<MyObject> a = new ArrayList<MyObject>(2);
or you may be trying to make an arraylist of arraylists:
public static ArrayList<ArrayList<MyObject>> a = new ArrayList<ArrayList<MyObject>>();
although im not sure if the last this i said is correct...
It seems to me that you use the wrong type of parenthesis. The reason why you can't define an array of generic is type erasure.
Plus, declaration of you variable "a" is fragile, it should look this way:
List<myObject>[] a;
Do not use a concrete class when you can use an interface.
If I can declare an Array of FloatLists: FloatList [][] values = new FloatList[3][3];
Why doesn’t it work to declare an Array of ArrayLists holding FloatLists like this: ArrayList<FloatList> [][] values = new ArrayList<FloatList>() [3][3];? OR EVEN: ArrayList<FloatList> [][] values = new ArrayList<FloatList> [3][3]();
How can this be achieved? Will it be hard to refer to the floats buried deep under its crusty texture?
Work from the inner-most type to the outer-most type. You start with FloatList:
FloatList
Then wrap that in an ArrayList:
ArrayList<FloatList>
Then you want an array of that:
ArrayList<FloatList>[]
Or a 2D array:
ArrayList<FloatList>[][]
That gives you the type for the declaration, but then you have to initialize the variable by giving it a value. Start with the array by giving it a size:
ArrayList<FloatList>[] array = new ArrayList[10];
This gives you an array of ArrayList<FloatList> objects, but they start out as null. To give them a value, you'd loop over every index in the array and use the new keyword to set the value of the index to an instance of ArrayList<FloatList>:
for(int i = 0; i < array.length; i++){
array[i] = new ArrayList<FloatList>();
}
For a 2D array, you'd use the same logic, just in a nested for loop.
Then to add a FloatList to an ArrayList at a specific index of the array, you'd do this:
array[i].add(new FloatList());
Finally, to add a float to a FloatList in an ArrayList at an index in the array, you'd do this:
array[x].get(y).append(0.5);
And to get a float out of an index in the FloatList in an ArrayList at an index in the array, you'd do this:
float f = array[x].get(y).get(z);
Putting it all together, it looks like this:
ArrayList<FloatList>[] array = new ArrayList[10];
for(int i = 0; i < array.length; i++){
array[i] = new ArrayList<FloatList>();
}
array[1].add(new FloatList());
array[1].get(0).append(0.25);
array[1].get(0).append(0.5);
array[1].get(0).append(0.75);
float f = array[1].get(0).get(2);
println(f);
ArrayList<FloatList> [][] values = new ArrayList[3][3];
Basically, you're declaring that you want an object that is a 3D array of ArrayLists, and not generating actual ArrayList objects.
Afterwards, you have to instantiate each of them, so for example:
values[0][0] = new ArrayList<>();
And so on.
It doesn't work because of the way the JVM provides Generics. Generics in Java is a front-end compiler feature that becomes raw type usages and casts at execution time.
What is the compiler doing when I use generics?
Here's a terribly-contrived example. Let's say I want to create a List<String> to store command line arguments that I will later use to kick off a new process with, like so:
List<String> cmd = new ArrayList<>();
cmd.add("java");
cmd.add("-jar");
cmd.add("path/to/my.jar");
...
String args = cmd.get(0)+" "+cmd.get(1)+" "+cmd.get(2);
At compile time, the compiler will check to make sure that I am using the String type every time I use a generic List method via cmd and throw an error if I try to use instances of an incompatible type. However, there's a little thing called erasure that happens during compilation, before execution. Effectively, under the hood, the compiler converts the code above into something like this:
List cmd = new ArrayList();
cmd.add("java");
cmd.add("-jar");
cmd.add("path/to/my.jar");
...
String args = (String)cmd.get(0)+" "+(String)cmd.get(1)+" "+(String)cmd.get(2);
So why doesn't my generic array code compile?
In your example, you wanted to create an array of a generic type, like so:
ArrayList<FloatList>[][] array = new ArrayList<FloatList>[n][m]; //Doesn't compile? What gives?
The problem is, because of type erasure, the ArrayList<FloatList> class type doesn't really exist, and now you've asked the JVM to create a 2-dimensional array of that non-existent type.
Okay, so what's the alternative?
Well ... it isn't pretty, but you could do something like this:
class ArrayListOfFloatList extends ArrayList<FloatList>{
...
}
//Somewhere else in your code:
ArrayListOfFloatList[][] myArray = new ArrayListOfFloatList[n][m];
//This will compile because ArrayListOfFloatList is a real class.
The only other way around this would be to not use arrays. Ugly, perhaps, but it's unfortunately a limitation of how Java is currently implemented.
I need to get three levels down into an array list. Here is my code on how I create the final product "rowList":
ArrayList<ArrayList> rowList = new ArrayList<ArrayList>();
ArrayList<ArrayList<String>> appList =new ArrayList<ArrayList<String>>();
ArrayList<String> arr = new ArrayList<String>();
int Id = -1;
int cc = rsmd.getColumnCount();
while(rs.next()){
if(Id == -1){
arr.add(rs.getString("name"));
Id= Integer.parseInt(rs.getString("Id"));
}
if(Id!= Integer.parseInt(rs.getString("Id"))){
Id= Integer.parseInt(rs.getString("Id"));
rowList.add(appList);
appList = new ArrayList<ArrayList<String>>();
arr.add(rs.getString("name"));
}
for(int i=2; i < rsmd.getColumnCount();i++){
arr.add(rs.getString(rsmd.getColumnName(i)));
}
appList.add(arr);
arr = new ArrayList<>();
}
rowList.add(appList);
So in the end rowlist will look something like this:
[0]
[0]
[0]Property 1
[1]Property 2
[2]Property 3
[1]
[0]Property 1
[1]Property 2
[2]Property 3
[1]
[0]
[0]Property 1
[1]Property 2
[2]Property 3
[1]
[0]Property 1
[1]Property 2
[2]Property 3
So my question would be how to get to the properties, the last level in the nested array? I can use rowList.get(0).get(0).toString() to return the string array, but rowList.get(0).get(0).get(0) doesn't work, and instead gives the error: cannot find symbol.
I would also like to be able to remove a property after I've retrieved it and set it to a string. That part can easily be worked around though, so it isn't vital.
This is because you're using a raw type:
ArrayList<ArrayList> rowList = new ArrayList<ArrayList>();
rowList.get(0) returns an ArrayList. Antoher .get(0) will return an Object, because you're using a raw type. And Object does not have a get method.
But Object does have a toString method, so you can call toString.
You simply have to change the declaration. This can be made easier using the diamond:
ArrayList<ArrayList<ArrayList<String>>> rowList = new ArrayList<>();
ArrayList<ArrayList<String>> appList = new ArrayList<>();
ArrayList<String> arr = new ArrayList<>();
Okay, let's think about the type of each result in the chained calls rowList.get(0).get(0).get(0). The easiest way to do this is to break each call into its own line so that we can figure out the type we need for the variable declaration. First of all, look at the declaration of rowList:
ArrayList<ArrayList> rowList = new ArrayList<ArrayList>();
This tells us that rowList.get(0) will return an ArrayList:
ArrayList arr = rowList.get(0);
Now rowList.get(0).get(0) is equivalent to arr.get(0). But this returns an Object:
Object obj = arr.get(0);
So rowList.get(0).get(0).get(0) is equivalent to obj.get(0). However, Object does not have a method named get(). This is why you get an error message.
In general, you should be very careful when chaining method calls. Typically this syntax is only used when a method returns a reference to the calling object. That way the return type is always the same and much easier to keep track of. When the return type differs on each successive method call, it can be difficult to keep track of.
The problem is that the ArrayList returned by rowList.get(0) is a raw type. So another get() call only returns an Object. You should use generics to specify the type of object in the "rows":
ArrayList<ArrayList<ArrayList<String>>> rowList = new ArrayList<>();
As you see here, generics can be used as the type inside of any <> just like you already did for the outermost level of ArrayList in your originaly code. (Note that in JDK 7+, you can use the diamond operator when creating an ArrayList. This greatly reduces duplicating the type information that already appears in the declaration.)
Better yet, you can declare your variables using the List interface in order to provide some flexibility in the concrete type used:
List<List<List<String>>> rowList = new ArrayList<>();
public class Sonnet29 implements Poem {
private String[] poem;
public Sonnet29() {
poem = { "foo", "bar" , "baz"};
}
#Override
public void recite() {
//...
}
}
Line poem = { "foo", "bar" , "baz"}; is giving compilation error.
Any specific reason why this is not allowed?
How do I initialize a String array with array constants?
EDIT: Thank you folks for your answers. Now I'm clear what is allowed and what is NOT.
But can I ask you why this is NOT allowed?
String[] pets;
pets = {"cat", "dog"};
After googling a bit, I found this link, where in, it is told that coding like this leaves the compiler in ambiguity - whether the pets should be array of Strings or array of Objects. However from the declaration, it can very well figure out that it is a String array, right???
This will do what you're looking for:
public Sonnet29() {
poem = new String[] { "foo", "bar", "baz" };
}
Initialization lists are only allowed when creating a new instance of the array.
From the Java language specification:
An array initializer may be specified in a declaration, or as part of an array creation expression (§15.10), creating an array and providing some initial values
In short, this is legal code:
private int[] values1 = new int[]{1,2,3,4};
private int[] values2 = {1,2,3,4}; // short form is allowed only (!) here
private String[][] map1 = new String[][]{{"1","one"},{"2","two"}};
private String[][] map2 = {{"1","one"},{"2","two"}}; // short form
List<String> list = Arrays.asList(new String[]{"cat","dog","mouse"});
and this is illegal:
private int[] values = new int[4];
values = {1,2,3,4}; // not an array initializer -> compile error
List<String> list = Arrays.asList({"cat","dog","mouse"}); // 'short' form not allowed
{"cat", "dog"}
Is not an array, it is an array initializer.
new String[]{"cat", "dog"}
This can be seen as an array 'constructor' with two arguments. The short form is just there to reduce RSI.
They could have given real meaning to {"cat", "dog"}, so you could say things like
{"cat", "dog"}.length
But why should they make the compiler even harder to write, without adding anything useful? (ZoogieZork answer can be used easily)
I am trying to create an array of the generic class "DataStruct".
The code is the following:
public class DataArray<T> {
DataStruct<T>[] array;
int index;
public DataArray(int capacity) {
array = (DataStruct<T>[]) new Object[capacity]; // !!!
this.index = 0;
}
}
I get a java.lang.ClassCastException (Ljava.lang.Object; cannot be cast to [LArrayBased.DataStruct;) at the line marked with three exclamation marksat the end, while testing it.
Can you please tell me the correct way to create it?
Why not declare
array = new DataStruct[capacity];
Object[] can not be cast to DataStruct[].
Because arrays are refiable in nature that means arrays know their type at runtime so If you convert it to Object [] like below you will again run in to problems
Object[] array = new DataStruct[capacity];
array[0] = 10;//Array Store exception
So it is wise to declare it as DataStruct[capacity]