Create array of objects at run time using class name in java - java

We all know we can create an object with the help of class name in the string format. Like i have a class name "Test". Using
Class.forName("Test").newInstance()
We can create the object of that class.
My question is that is there any way to create an array or array list of the objects using class name ?? OR lets suppose we have an object of the class and can with this object we create the array or array list of the that object.

To create an array, you can use java.lang.reflect.Array and its newInstance method:
Object array = Array.newInstance(componentType, length);
Note that the return type is just Object because there's no way of expressing that it returns an array of the right type, other than by making it a generic method... which typically you don't want it to be. (You certainly don't in your case.) Even then it wouldn't cope if you passed in int.class.
Sample code:
import java.lang.reflect.*;
public class Test {
public static void main(String[] args) throws Exception {
Object array = Array.newInstance(String.class, 10);
// This would fail if it weren't really a string array
String[] afterCasting = (String[]) array;
System.out.println(afterCasting.length);
}
}
For ArrayList, there's no such concept really - type erasure means that an ArrayList doesn't really know its component type, so you can create any ArrayList. For example:
Object objectList = new ArrayList<Object>();
Object stringList = new ArrayList<String>();
After creation, those two objects are indistinguishable in terms of their types.

You can use Array
Object xyz = Array.newInstance(Class.forName(className), 10);
It has a method newInstance(Class, int):
Creates a new array with the specified component type and length. Invoking this method is equivalent to creating an array as follows:
int[] x = {length};
Array.newInstance(componentType, x);

Related

Different Java behavior for Generics and Arrays

Why does java allows inconsistent type to be entered into a generic object reference but not in an array?
For Eg:
When initializing array:
int[] a = {1, 2, 3};
And, if I enter:
int[] a = {1, 2, "3"}; //Error for incompatible types
While for generics,
import java.util.ArrayList;
public class Test {
private static ArrayList tricky(ArrayList list) {
list.add(12345);
return list;
}
public static void main(String[] args) {
int i = 0;
ArrayList<String> list = new ArrayList<>();
list.add("String is King");
Test.tricky(list);
}
}
The above code will let you add any Type in the list object, resulting in a run time exception in some cases.
Why is there such a behavior?? Kindly give a proper explanation.
When you use the tricky method to insert data into your ArrayList Collection, it doesn't match the specified type i.e String, but still This is compatible because of Generics compatibility with older Legacy codes.
If it wouldn't have been for this i.e if it would have been the same way as of arrays, then all of the pre-java generic code would have been broken and all the codes would have to be re-written.
Remember one thing for generics, All your type-specifications are compile time restrictions, so when you use the tricky method to insert data in your list reference, what happens is the compiler thinks of it as a list to which ANYTHING apart from primitives can be added.
Only if you would have written this:
...
public class Test {
private static ArrayList tricky(ArrayList<String> list) {
list.add(12345); //Error, couldn't add Integer to String
return list;
}
...
}
I have written a documented post on this, Read here.
The method's parameter has no generic so all classes are allowed.
You may google 'type erasure' for more information.
If you add the generic type to your method you will get a compiler error:
private static ArrayList<String> tricky(ArrayList<String> list) { // ...
By the way, you do not need to return the list because you modify the same instance.
Here's why:
The reason you can get away with compiling this for arrays is because
there is a runtime exception (ArrayStoreException) that will prevent
you from putting the wrong type of object into an array. If you send a
Dog array into the method that takes an Animal array, and you add only
Dogs (including Dog subtypes, of course) into the array now referenced
by Animal, no problem. But if you DO try to add a Cat to the object
that is actually a Dog array, you'll get the exception. Generic
Methods (Exam Objectives 6.3 and 6.4) 615 616 Chapter 7: Generics and
Collections
But there IS no equivalent exception for generics, because
of type erasure! In other words, at runtime the JVM KNOWS the type of
arrays, but does NOT know the type of a collection. All the generic
type information is removed during compilation, so by the time it gets
to the JVM, there is simply no way to recognize the disaster of
putting a Cat into an ArrayList and vice versa (and it becomes
exactly like the problems you have when you use legacy, non-type safe
code)
Courtesy : SCJP Study guide by Kathy Sierra and Bert Bates
When you declare you ArrayList like ArrayList list = ... you do not declare the type of object your list will contain. By default, since every type has Object as superclass, it is an ArrayList<Object>.
For good practices, you should declare the type of your ArrayList<SomeType> and, thereby, avoid adding inconsistant elements (according to the type)
Because you haven't defined the generic type of your list it defaults to List<Object> which accepts anything that extends Object.
Thanks to auto-boxing a primitive int is converted to an Integer, which extends Object, when it is added to your list.
Your array only allows int's, so String's are not allowed.
This is because in your method parameter you did not specify a particular type for ArrayList so by default it can accept all type of objects.
import java.util.ArrayList;
public class Test {
//Specify which type of objects you want to store in Arraylist
private static ArrayList tricky(ArrayList<String> list) {
list.add(12345); //This will give compile time error now
return list;
}
public static void main(String[] args) {
int i = 0;
ArrayList<String> list = new ArrayList();
list.add("String is King");
Test.tricky(list);
}
}

Casting Object array to generic type

I am creating a stack of generic type that is backed by an array. When I try to make a generic type array, Java does not let me. I've been told that I must create an array of type Object and cast it to a generic type. I've casted my Object array to type , but how can I deal with the Unchecked Type error that Java keeps giving me?
public class AStack<T>{
// Create a stack with the default capacity 10. The stack expands
// its internal array when the number of elements pushed() into it
// would exceed the internal capacity.
Object arr[];
int top=-1;
public AStack(){
int defSize=10;
arr = (T[])new Object [defSize];
}
This is where I am so far.
UPDATE:
I am creating an Object array, then casting the return types to type T at the end of the method.
The simplest way is to use the type variable to cast array of objects to desired type.
public class AStack<T> {
T arr[];
int top=-1;
public AStack() {
int defSize=10;
arr = (T[]) new Object [defSize];
}
}
You could use an interface or a class that is extended to all the other classes you want to make generic and then use the interface or the class as the type of the array and now you could insert your specific types into the array.
GenericType[] array = { new specificType1(), new specificType2(), new specificType3() }

Creating an object variable out of its meta-object

I have a method (in a class which represent a set of objects) that receive as a parameter a Class object, and I need to find all the objects in the set that have this Class object as their meta-object.
The problem is that i need to return them as an array of their type, and i don't know how to get the objects type.
So in other words, i need to create an array, which his type is depends on the Class object, for example:
public Object[] getAllFromType(Class meta){
Object[] temp = new meta.getDynamicType[fullCells];
...
...
...
return temp;
}
Is it possible?
Thanks.
Well, as you've shown you're going to return it as Object[] anyway, so you won't get a compile-time benefit here, but you can create an array of the right type easily enough:
Object[] array = (Object[]) Array.newInstance(meta, fullCells);
Note that the cast to Object[] is required because Array.newInstance returns Object - the cast will fail for int[] for example, because an int[] isn't an Object[]. It will work if the array element type is any class or interface type, however.

Why does this constructor that uses generics fail?

I am creating a class that, at present, stores lists of various types in an internal object called genericTable. Each list (composed of either Double, or Long) are all held in an object which is an instance of class GenericList.
Question: Why doesn't the method addVector work?
The error under the red underline says the constructor Test<V>.GenericList<V>(List<List<V>>) is undefined.
If I was working in a main method (but had the same GenericList class) and created genericTable within the main method (using List<GenericList<?>> Table = new ArrayList<GenericList<?>>();) and did genericTable.add(new GenericList<Long>(Arrays.asList(genericVector))); (where genericVector in this case is a List<Long>), it works perfectly.
public class Test<V> {
private final List<GenericList<?>> genericTable = new ArrayList<GenericList<?>>();
public void addVector(List<V> genericVector) {
genericTable.add(new GenericList<V>(Arrays.asList(genericVector)));
}
private class GenericList<K> {
private final List<K> listGeneric;
public GenericList(List<K> input) {
listGeneric = input;
}
}
}
You're unnecessarily using Arrays.asList(), when you already have a list. Consequently you get a list of lists, which is not what the constructr accepts.
See this from the javadocs:
This method also provides a convenient way to create a fixed-size list
initialized to contain several elements:
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
So in your case you're getting a list of lists, instead of a list of strings.
I've added this bit from the comments, for clarity:
The method signature for asList() is like this:-
public static <T> List<T> asList(T... a)
So because T... a is a vararg, when you pass in "Larry", "Moe", "Curly", the compiled method actually receives an array of ["Larry", "Moe", "Curly"], and returns them as a List.
So because you passed in a List, rather than an array, the method takes the vararg array like this: [genericVector], and returns that array as a list, and you constructor breaks.

Java generics and arrays construction

Suppose I have a generic class with a generic parameter T which is a Number subclass. I would like to initialize an array of T during class construction. Is it possible? If yes how? If not why?
public class AClass<T extends Number>{
private T array[];
private int arrayOfInt[];
public AClass(int size){
arrayOfInt = new int[size];
array = ? //what should I put here?
}
}
T is only know at compile time. It is not know at runtime and thus you cannot initilise the contents of the array. However you can create the array, every value will be null.
array = (T[]) new Number[size];
EDIT: The problem with creating instances of any type is you need to know what is the default value you want and which constructor you want to call. e.g. there is no new Double()
As mentioned below, double[] will be more efficient and faster than Number[] and unless you need large long values, it will be able to store every possible value.
If you want to use arrays, there are two options:
Peter Lawrey's answer, array = (T[]) new Number[size];. You have to make sure never to return or pass this variable to code outside of the class that expect it to be an array of a particular type, which will cause an exception.
Declare array as type Number[], then just do array = new Number[size];. The downside of this is that when you get anything out of it you will need to explicitly cast to T to use it as such.
The two are the same after type erasure, and they will both cause unchecked cast warning, so it's really a matter of personal preference. The former is more convenient, while the latter is more formally correct (you are not pretending it's a type it's not).
Alternately, some people will tell you to use an ArrayList<T> instead. But internally, an ArrayList is still implemented using one of these two options.
This is not possible.
Because Java generics use type erasure, the type of T isn't known at runtime, so you can't create an array of it.
Other options than mentioned are to use toArray(T[]) or java.lang.reflect.Array:
public class AClass<T extends Number>{
private T array[];
public AClass(final int size, T[] a){
array = (new ArrayList<T>() {{
for (int i = 0; i < size; i++) {
add(null);
}
}}).toArray(a);
}
public AClass(int size, Class<T[ ]> clazz) {
array = clazz.cast(java.lang.reflect.Array.newInstance(
clazz.getComponentType( ), size));
}
public static void main(String[] args) {
System.out.println("toArray: "
+ new AClass<Double>(42, new Double[]{}).array.length);
System.out.println("java.lang.reflect.Array: "
+ new AClass<Double>(42, Double[].class).array.length);
}
}
PS. solution using reflection is close to one suggested in Langer's Generics FAQ (Utilities.createBuffer): How do I generically create objects and arrays?

Categories

Resources