How to populate generic array to main - java

I've got a generic array class and I want to return an array in the main so I can use the sort method that I have ready in the main. I understand that the constructor has an array in it so I'm wondering if I can use that. Or do I need to set up a new method to return this.array ? Also it returns a generic array, how do I choose the type in main?
public class dynamicArray <T>{
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
Here I chose the integer type for the class. I'm not sure how can I extract the
array from the constructor.
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int [] arr = array.populate();
mergeSort(arr);
System.out.println(array.toString());
}

Unfortunately, arrays and generics don't work well together. Take a look at the source code of java's ArrayList - it is implemented with an Object[] and not a T[] - then every method will cast to T (which costs literally zero, it's just ugly and causes compiler warnings). I advise you do the same here: Arrays actually KNOW their component type (unlike a list of Ts, which does not, there is no method on a java.util.List that you can invoke to get the component type), and therefore casting Object[] to T[] is just wrong; java allows this solely for backwards compatibility reasons.
Basically, you can't work with T[] without things being subtly wrong and a lot of compiler errors.
In this specific case? I would strenuously advise you to use a private List<T> array; field instead of a T[] field.
Your call to array.populate() (that seems like a bizarre name for this method!) IS retrieving the array you created in the constructor. You are doing what you're asking for: "Extracting the array from the constructor" - invoking populate() on the object returned by the new dynamicArray<Integer>() is doing exactly that.
NB: You have a typo in your source code. it's new dynamicArray<Integer>();, not new<Integer>dynamicArray();. Perhaps that's causing some issues?
NB2: Java conventions dictate it's DynamicArray, and something like getBackingArray (instead of populate).

I think you ask two question :
How to set Integer type of that array object.
How to get Integer[] to int[]
Here is the code :
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
public void add(T x) {
array[++index] = x;
}
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int[] arr = Arrays.stream(array.populate())
.mapToInt(i -> i)
.toArray();
System.out.println(array.toString());
}
Answer for 1st question is you can not set Integer type because there wasn't any add method in your class. Answer for 2nd question is you try to convert Integer[] to int[] but there is no direct way to cast this. you just need to change Integer -> Object then Object -> int. This can be done easily using streams which is in Java 8 and i have used lambda here for showing power of lambda function.

Here is a possible alternative. Pass the type of array to the constructor. But essentially you are creating a limited form of ArrayList so you may just as well use that. Note that this still has the limitation that you can't use primitive arrays as the array type.
dynamicArray<Integer> array = new dynamicArray<>(new Integer[0]);
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
Integer[] a = array.getArray();
System.out.println(Arrays.toString(a));
}
class dynamicArray<T> {
private int size = 0;
private T[] array;
public dynamicArray(T[] a) {
array = a;
}
public void add(T value) {
if (array.length == size) {
array = Arrays.copyOf(array, size == 0 ? 10 : size*2);
}
array[size++] = value;
}
#SuppressWarnings("unchecked")
public T[] getArray() {
// need to copy the array since the length and size could be different.
T[] arrayCopy = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
System.arraycopy(array, 0, arrayCopy, 0, size);
return arrayCopy;
}
}

Related

Is it possible to return an array of type <E> in a method in Java rather than an array of objects when using Generics?

I have a method that takes an in an array and copies it in a random order into another array and returns the shuffled array.
However, if I want to make it generic, I can't create the second array of type E.
To get around this, I tried using an Arraylist and then using the .toArray() method and casting it to type E, but that returns an array of objects.
My current solution is to just modify the array directly and return that, but is there a way to return an array of the proper type, AKA the type of the array passed into the method?
import java.util.ArrayList;
import java.util.Arrays;
public class ShuffleArray
{
public static void main(String[] args)
{
String[] list = {"bob", "maryo", "john", "david", "harry"};
//doesn't work, can't store array of objects in array of strings
list = shuffle(list);
//works because I modify directly
shuffle(list);
}
public static <E> E[] shuffle(E[] list)
{
ArrayList<E> shuffledList = new ArrayList<>();
//shuffle the array
while (shuffledList.size() != list.length)
{
int randomIndex = (int)(Math.random() * list.length);
if (!shuffledList.contains(list[randomIndex]))
{
shuffledList.add(list[randomIndex]);
}
}
//overwrites the initial values of the array with the shuffled ones
for (int i = 0; i < list.length; i++)
{
list[i] = shuffledList.get(i);
}
//How do I make this return an array of type String?
return (E[]) shuffledList.toArray();
}
}
All arrays have a public clone() method, which returns the same type as the original array:
return shuffledList.toArray(list.clone());
You have a different problem, better described here: make arrayList.toArray() return more specific types
Change your return statement to the following
return shuffledList.toArray(E[]::new);
You could use Arrays.copyOf:
shuffledList.toArray(Arrays.copyOf(list, list.length));
although internally the method uses casting as well.
By the way, there is a built-in method Collections.shuffle. Maybe the best approach would be to work on Lists instead of raw arrays?
UPDATE: for the copyOf approach to work, you would need to bound the type parameter to Objects i.e. change it from <E> to <E extends Object>. The method wouldn't work for raw types (int, long etc.).
yeah why dont u just create an array of type E and store the values in it
E[] array = new E[list.length];
then just use that array to store the shuffled values and return it

How to write a generic function which accepts arrays of literals

I am unable to provide values of type int[], float[], etc. to a generic function. I get errors that say basically that float[] is the wrong type and Float[] is what the function actually takes.
Here's an example of a method I wrote, and I'm trying to give it values like new int[]{0,1} (created in library somewhere else).
private static <T> JSONArray encodeArray(T[] array) {
JSONArray arr = new JSONArray();
Collections.addAll(arr, array);
return arr;
}
Is it even possible to write my function signature to accept these arrays of literals?
I could go to the call site, and do a conversion of float[] to Float[], but I don't know how to do that either.
Is it even possible to write my function signature to accept these
arrays of literals?
It is possible, but the parameter type will have to be Object, because that is the only common superclass of "arrays of primitives" and "arrays of references" (e.g. it can't be Object[] since arrays of primitives are not subclasses of Object[]). (There are also some interfaces that all arrays implement, but I will ignore those for now.) Unfortunately, this means that you will lose type safety as the compiler will not be able to give an error at compile time if someone passes a non-array type in.
To do array operations on this Object value, you will need to use the methods in the reflection helper class java.lang.reflect.Array. So you can do something like this:
import java.lang.reflect.Array;
// ...
private static JSONArray encodeArray(Object array) {
JSONArray arr = new JSONArray();
for (int i = 0, n = Array.getLength(array); i < n; i++) {
arr.add(Array.get(array, i)); // primitives are automatically wrapped
}
return arr;
}
The method which accepts a generic array.
public <T> void printArray(T[] array){
for (T element: array){
System.out.println(element);
}
}
You can't use primitives in generic functions. When generic are compiled, you end up with Object[] in the above example as the implementing type. As int[] and byte[] etc, do not extend Object[] you cannot use them interchangeably even if the code involved would be identical (again generics are not templates)
Add on the solution from #Max-Reshetnyk, It is better if you check ArrayList for methods that help you add or remove... elements. Since primitive types are not meant to be used with generics, you should AutoBox them with their respective types and then use generics.
For instance:
class Main {
public static void main(String[] args) {
Integer[] x = new Integer[1];
x[0] = 1;
printArray(x);
}
public static <T> void printArray(T[] array){
for (T element: array){
System.out.println(element);
}
}
}

Create Static Array from dynamic array with Generics [duplicate]

This question already has answers here:
why does List<String>.toArray() return Object[] and not String[]? how to work around this?
(5 answers)
Closed 3 years ago.
I want to create a static array from a dynamic array of whatever generic type the dynamic array was. I saw List#toArray() which returns Object[] and it doesn't use generics. Is it just safe to cast it to T[] or does the entire array have to be instantiated from the type of class using it?
I went on to try and create my own method in case java didn't provide one but, I got stuck with a compile errors
public static <T> T[] toArray(List<T> list)
{
T[] li = (T[]) Array.newInstance(T.class, list.size());
int index = 0;
for(T obj : list)
{
li[index++] = obj;
}
return li;
}
First of all, you don't need that method. You can use:
List<String> list = new ArrayList<>();
list.add("ff");
list.add("bb");
String[] array = list.toArray (new String[list.size ()]);
In order for your method to work, you have to pass the Class of the generic type parameter:
public static <T> T[] toArray(List<T> list, Class<T> clazz)
{
T[] li = (T[]) Array.newInstance(clazz, list.size());
int index = 0;
for(T obj : list)
{
li[index++] = obj;
}
return li;
}
Then you can call the method with:
String[] array = toArray(list, String.class);
The method proposed by Eran doesn't work if you have a generic element type, because you can't get a Class<List<T>>, say.
Instead, pass an IntFunction<T[]>:
public static <T> T[] toArray(List<? extends T> list, IntFunction<T[]> arraySupplier)
{
T[] li = arraySupplier.get(list.size());
int index = 0;
for(T obj : list)
{
li[index++] = obj;
}
return li;
}
Or, easier, use streams:
return list.stream().toArray(arraySupplier);
Then call like:
String[] array = toArray(list, String[]::new);
List<List<String>> listOfLists = ...
List<?>[] arrayOfLists = toArray(listOfLists, List<?>::new);
Notice that whilst this does support generic array elements, you can only create arrays with a reified element type, so your array type has to be List<?>[]; it still can't be List<String>[].
If your business requirement/Use Case requires an array to be no longer dynamic then you should first create a static array of size equal to your size of dynamic array.
ArrayList<Integer> al = [............] // assuming that ArrayList named al is having some data
int[] arr = new int[al.size()];
// from here you can use a for loop and initialize your static array
for(int i=0; i<arr.length;i++) {
arr[i] = (int) al.get(i); // Unboxing will also be done but still you can type cast to be on safe side
}
// Now you can de-reference the ArrayList object and call garbage collection which will wipe it out of the Heap Memory of your JVM.
al = null; // de-referencing the object by making the reference variable null
System.gc(); // GC happens periodically but to boost performance you can explicitly call it right away.
You can create a method accepting the list of objects and can handle all sorts of arrays using instanceof operator.

How to declare and instantiate a new Generic array?

I'm brushing up on my data structure skills. I found a great free book online called Open Data Structures in Java. After reading through it, I'm trying to create all the stated data structures with the code provided so I can instill them in to my memory.
I ran in to an "error" and for the life of me I can't figure it out: in the resize() method for the ArrayStack (section 2.1.2), there is the line of code - T[] b = newArray(Math.max(n*2,1));. The point of this is so the array, which contains the elements, is neither too small or too large. If I use this line of code I get the following error message from Eclipse:
The method newArray(int) is undefined for the type ArrayStack<T>.
So, I'm thinking that it must have been a "typo" and what was meant was "new Array". But fixing that leaves me with the following error message from Eclipse:
Type mismatch: cannot convert from Array to T[].
I don't understand what I'm missing or doing wrong. So to sum up my question, how do you declare and instantiate a new generic array, particularly at a fixed size?
Given the class of T, let's call it klass...
For a one-dimensional array of length n:
T[] arr = (T[]) Array.newInstance(klass, n)
For a two-dimensional array of length n x m:
T[][] 2dArr = (T[][]) Array.newInstance(klass, n, m)
The above are actually two different functions, one takes an int argument and the second takes an int... argument, which you can also pass as an array. Both return an Object for which you need an unchecked cast.
If you want a jagged array of length n, second dimension undetermined, you will have to get the class of T[], let's call it klass2, and then do
T[][] 2dArr2 = (T[][]) Array.newInstance(klass2, n)
This is why you also need to pass in a type to collection.toArray(T[] arr), otherwise you get an Object[] for the vanilla toArray() method because it doesn't know the type.
What you would like is:
void resize() {
T[] b = new T[Math.max(n*2,1)];
for (int i = 0; i < n; i++) {
b[i] = a[i];
}
a = b;
}
But that does not work because T is not actually known at runtime, and it would have to be. However this can be written with a generic-safe constructor.
void resize() {
T[] b = (T[]) Array.newInstance( a.getClass().getComponentType(),
Math.max(n*2,1) );
for (int i = 0; i < n; i++) {
b[i] = a[i];
}
a = b;
}
It appears that the author meant to have a method, newArray in that class:
void T[] newArray(int size) {
return (T[]) Array.newInstance( a.getClass().getComponentType(), size);
}
Java does not make this a simple matter. Because of type erasure the class of T is not available at runtime (which is when you need to determine what type of array to create).
However, since you already have an array (a), you can use reflection to create a new array of that type.
It will look something like this:
import java.lang.reflect.Array;
public class Test {
public static void main(String args[]) throws Exception {
Object array[] = new Object[5];
array = resizeArray(array, 10);
for (Object o : array) {
System.out.println(o);
}
}
public static <T>
T[] resizeArray(T[] a, int newSize) throws Exception {
T[] b = (T[]) Array.newInstance(a.getClass().getComponentType(),
newSize);
for (int i = 0; i < a.length; i++) {
b[i] = a[i];
}
return b;
}
}

Arrays.asList() of an array

What is wrong with this conversion?
public int getTheNumber(int[] factors) {
ArrayList<Integer> f = new ArrayList(Arrays.asList(factors));
Collections.sort(f);
return f.get(0)*f.get(f.size()-1);
}
I made this after reading the solution found in Create ArrayList from array. The second line (sorting) in getTheNumber(...) causes the following exception:
Exception in thread "main" java.lang.ClassCastException: [I cannot be cast to java.lang.Comparable]
What is wrong here? I do realize that sorting could be done with Arrays.sort(), I'm just curious about this one.
Let's consider the following simplified example:
public class Example {
public static void main(String[] args) {
int[] factors = {1, 2, 3};
ArrayList<Integer> f = new ArrayList(Arrays.asList(factors));
System.out.println(f);
}
}
At the println line this prints something like "[[I#190d11]" which means that you have actually constructed an ArrayList that contains int arrays.
Your IDE and compiler should warn about unchecked assignments in that code. You should always use new ArrayList<Integer>() or new ArrayList<>() instead of new ArrayList(). If you had used it, there would have been a compile error because of trying to pass List<int[]> to the constructor.
There is no autoboxing from int[] to Integer[], and anyways autoboxing is only syntactic sugar in the compiler, so in this case you need to do the array copy manually:
public static int getTheNumber(int[] factors) {
List<Integer> f = new ArrayList<Integer>();
for (int factor : factors) {
f.add(factor); // after autoboxing the same as: f.add(Integer.valueOf(factor));
}
Collections.sort(f);
return f.get(0) * f.get(f.size() - 1);
}
You are trying to cast int[] to Integer[], this is not possible.
You can use commons-lang's ArrayUtils to convert the ints to Integers before getting the List from the array:
public int getTheNumber(int[] factors) {
Integer[] integers = ArrayUtils.toObject(factors);
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(integers));
Collections.sort(f);
return f.get(0)*f.get(f.size()-1);
}
there are two cause of this exception:
1
Arrays.asList(factors) returns a List<int[]> where factors is an int array
2
you forgot to add the type parameter to:
ArrayList<Integer> f = new ArrayList(Arrays.asList(factors));
with:
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(factors));
resulting in a compile-time error:
found : java.util.List<int[]>
required: java.util.List<java.lang.Integer>
Use java.utils.Arrays:
public int getTheNumber(int[] factors) {
int[] f = (int[])factors.clone();
Arrays.sort(f);
return f[0]*f[(f.length-1];
}
Or if you want to be efficient avoid all the object allocation just actually do the work:
public static int getTheNumber(int[] array) {
if (array.length == 0)
throw new IllegalArgumentException();
int min = array[0];
int max = array[0];
for (int i = 1; i< array.length;++i) {
int v = array[i];
if (v < min) {
min = v;
} else if (v > max) {
max = v;
}
}
return min * max;
}
I think you have found an example where auto-boxing doesn't really work. Because Arrays.asList(T... a) has a varargs parameter the compiler apparently considers the int[] and returns a List<int[]> with a single element in it.
You should change the method into this:
public int getTheNumber(Integer[] factors) {
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(factors));
Collections.sort(f);
return f.get(0) * f.get(f.size() - 1);
}
and possibly add this for compatibility
public int getTheNumber(int[] factors) {
Integer[] factorsInteger = new Integer[factors.length];
for(int ii=0; ii<factors.length; ++ii) {
factorsInteger[ii] = factors[ii];
}
return getTheNumber(factorsInteger);
}
Arrays.asList(factors) returns a List<int[]>, not a List<Integer>. Since you're doing new ArrayList instead of new ArrayList<Integer> you don't get a compile error for that, but create an ArrayList<Object> which contains an int[] and you then implicitly cast that arraylist to ArrayList<Integer>. Of course the first time you try to use one of those "Integers" you get an exception.
This works from Java 5 to 7:
public int getTheNumber(Integer... factors) {
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(factors));
Collections.sort(f);
return f.get(0)*f.get(f.size()-1);
}
In Java 4 there is no vararg... :-)
this is from Java API
"sort
public static void sort(List list)
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the list)."
it has to do with implementing the Comparable interface
As far as I understand it, the sort function in the collection class can only be used to sort collections implementing the comparable interface.
You are supplying it a array of integers.
You should probably wrap this around one of the know Wrapper classes such as Integer.
Integer implements comparable.
Its been a long time since I have worked on some serious Java, however reading some matter on the sort function will help.

Categories

Resources