I am trying convert method to generic for CharSequence[] and for Set. Well I am not experienced in that.
This is the method where the second argument/return value should be generic (T). Is it possible?
private CharSequence[] remove(String string, CharSequence[] charSequences)
{
ArrayList<CharSequence> newArray = new ArrayList<CharSequence>();
int foundPlace = -1;
CharSequence[] v = charSequences;
for (int i = 0; i < v.length; i++) {
if (foundPlace != -1 && v[i].equals(string))
foundPlace = i;
else
newArray.add(v[i]);
}
return newArray.toArray(new CharSequence[newArray.size()]);
}
What I tried. Replaced everywhere where CharSequence[] occurs to T but it didn't work when I placed T in line T.length.
More clarification (sorry). I would like to convert second argument and return value to T - so everywhere where is CharSequence[] to T.
Maybe this is what you want:
private <T> T[] remove(T string, T[] charSequences)
{
ArrayList<T> newArray = new ArrayList<T>();
int foundPlace = -1;
T[] v = charSequences;
for (int i = 0; i < v.length; i++) {
if (foundPlace != -1 && v[i].equals(string))
foundPlace = i;
else
newArray.add(v[i]);
}
#SuppressWarnings("unchecked")
T[] ret = (T[]) Array.newInstance(v.getClass().getComponentType(), newArray.size());
return newArray.toArray(ret);
}
Or, if the containing class should also be generic of type T just remove <T> from above. So this line,
private <T> T[] remove(T string, T[] charSequences)
would then become,
private T[] remove(T string, T[] charSequences)
If the type of string doesn't matter, you may change its type to a plain Object,
private T[] remove(Object string, T[] charSequences)
{
ArrayList<T> newArray = new ArrayList<T>();
int foundPlace = -1;
T[] v = charSequences;
for (int i = 0; i < v.length; i++) {
if (foundPlace != -1 && v[i].equals(string))
foundPlace = i;
else
newArray.add(v[i]);
}
...
}
You might also want to rename string to something else afterwards.
I should also note that in your logic, foundPlace will always be -1.
You use an integer for foundPlace but a boolean is enough since you just test if it has been initialized and never use its value.
You don't even need this boolean, and your equals test is never evaluated since ̀foundPlace will always be equal to -1 (so the array you return is always a copy of charSequences)
You don't need an intermediary variable v, you can simply iterate over charSequences
Here is a version with Object, if it is what you are looking for :
private Object[] remove(Object val, Object[] array)
{
ArrayList<Object> newArray = new ArrayList<Object>();
for (Object o : array)
if(!o.equals(val))
newArray.add(o);
return newArray.toArray(new Object[newArray.size()]);
}
Generics and arrays can be a quite painful combination. I would stick to the List interface, if that is an option for you (ie. change return type to List and simply return newArray which would also be of type List).
Otherwise I recommend this post to better understand Generics and Arrays:
How to create a generic array in Java?
EDIT: Oh, and you definitely don't want to replace "CharSequence[]" with "T", but possibly with "T[]" if you really need to work with arrays here.
To implement a generic collection, use:
int length; // ...
T[] array = (T[])new Object[length];
So, the return statement will look like this:
return (T[])newArray.toArray(new Object[newArray.size()]);
Here is how you can implement a remove routine. Notice that you do not even need a separate remove method. I hope, I am not missing a use case that requires you to create a separate remove method.
package com.anupam;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class SO31535852 {
public static void main(String args[]) {
String[] arr = {"1", "2", "3"};
// Create a copy of the orginal array if you do not want to modify it.
Set<String> test = new HashSet<>(Arrays.asList(Arrays.copyOf(arr, arr.length)));
// In fact you do not even need a remove method. I could not understand why you are using
// foundPlace variable it's not doing much.
System.out.println(remove("1", test));
System.out.println(remove("1", test));
}
/**
* Removes a specific value from the underling collection
*
* #param toRemove the object to be removed
* #param myCollection the colelction from which to be removed
* #return the removed value or null.
*/
private static <T> T remove(T toRemove, Set<T> myCollection) {
return myCollection.remove(toRemove) ? toRemove : null;
}
}
Related
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;
}
}
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.
I am doing some tests with generic-methods and I'd like to transform these two methods below (convertFloatListToArray and convertShortListToArray) in just one (convertListToArray):
public class Helper{
public static float[] convertFloatListToArray(List<Float> list){
float[] array = new float[list.size()];
for(int i = 0; i<list.size(); i++){
array[i] = list.get(i);
}
return array;
}
public static short[] convertShortListToArray(List<Short> list){
short[] array = new short[list.size()];
for(int i = 0; i<list.size(); i++){
array[i] = list.get(i);
}
return array;
}
}
But when I try to use generics, as below, I have some errors:
public class Helper{
public static <T, E> T convertListToArray(List<E> list){
T array = new T[list.size()];
for(int i = 0; i<list.size(); i++){
array[i] = list.get(i);
}
return array;
}
}
I can understand java limitations about generics, but I wonder if someone know any solution, using generic-method, that I am not seeing.
As of the current version (Java 12), primitive types can't be represented with Java generics. More specifically, we can't provide a primitive type as a type argument. (We can't do e.g. Foo<int>.) We also can't use type variables as the type in a new expression, so we can't do new T[n] to create an array. Therefore, there's no ideal way to do this.
It is possible to do this reasonably using some reflection (java.lang.reflect.Array), but we need to provide a Class as an argument. Here's an example of how it might be done:
/**
* Unboxes a List in to a primitive array.
*
* #param list the List to convert to a primitive array
* #param arrayType the primitive array type to convert to
* #param <P> the primitive array type to convert to
* #return an array of P with the elements of the specified List
* #throws NullPointerException
* if either of the arguments are null, or if any of the elements
* of the List are null
* #throws IllegalArgumentException
* if the specified Class does not represent an array type, if
* the component type of the specified Class is not a primitive
* type, or if the elements of the specified List can not be
* stored in an array of type P
*/
public static <P> P toPrimitiveArray(List<?> list, Class<P> arrayType) {
if (!arrayType.isArray()) {
throw new IllegalArgumentException(arrayType.toString());
}
Class<?> primitiveType = arrayType.getComponentType();
if (!primitiveType.isPrimitive()) {
throw new IllegalArgumentException(primitiveType.toString());
}
P array = arrayType.cast(Array.newInstance(primitiveType, list.size()));
for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i));
}
return array;
}
Example call:
List<Integer> list = List.of(1, 2, 3);
int[] ints = toPrimitiveArray(list, int[].class);
Note that Array.set will perform a widening primitive conversion, so the following works:
List<Integer> list = List.of(1, 2, 3);
double[] doubles = toPrimitiveArray(list, double[].class);
But it won't perform a narrowing conversion, so the following throws an exception:
List<Integer> list = List.of(1, 2, 3);
byte[] bytes = toPrimitiveArray(list, byte[].class); // throws
If you wanted, that code could also be used to make duplication easier:
public static int[] toIntArray(List<Integer> list) {
return toPrimitiveArray(list, int[].class);
}
public static double[] toDoubleArray(List<Double> list) {
return toPrimitiveArray(list, double[].class);
}
...
(Having multiple methods like that isn't really generic, though.)
One solution that you'll sometimes see places looks something like this:
public static <P> P toPrimitiveArray(List<?> list) {
Object obj0 = list.get(0);
Class<?> type;
// "unbox" the Class of obj0
if (obj0 instanceof Integer)
type = int.class;
else if (obj0 instanceof Double)
type = double.class;
else if (...)
type = ...;
else
throw new IllegalArgumentException();
Object array = Array.newInstance(type, list.size());
for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i));
}
return (P) array;
}
There are a variety of problems with that, though:
We don't know what type of array to create if the list is empty.
Doesn't work if there's more than one type of object in the list.
Unchecked casting of the result array to P, so there's a danger of heap pollution.
It's much better to just pass in a Class as an argument.
Also, while it's possible to just write many overloads which unbox arrays:
public static int[] unbox(Integer[] arr) {...}
public static long[] unbox(Long[] arr) {...}
public static double[] unbox(Double[] arr) {...}
...
Because of the effects of type erasure, it's impossible to write overloads which unbox many different types of List, as in the following:
public static int[] unbox(List<Integer> list) {...}
public static long[] unbox(List<Long> list) {...}
public static double[] unbox(List<Double> list) {...}
...
That won't compile, because we aren't allowed to have more than one method in the same class with the same name and erasure. The methods would have to have different names.
As a side-note, here are some non-generic solutions:
As of Java 8 we can unbox Lists of Integer, Long and Double using the Stream API:
List<Long> list = List.of(1L, 2L, 3L);
long[] longs = list.stream().mapToLong(Long::longValue).toArray();
Google Guava has Collection unboxing methods in their com.google.common.primitives classes, for example Doubles.toArray:
List<Double> list = List.of(1.0, 2.0, 3.0);
double[] doubles = Doubles.toArray(list);
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;
}
}
I would like to take a passed List that I know is homogeneous and from it create an array of the same type as the elements within it.
Something like...
List<Object> lst = new ArrayList<Object>;
lst.add(new Integer(3));
/// somewhere else ...
assert(my_array instanceof Integer[]);
The conversion would happen runtime, while the type is lost at compile time. So you should do something like:
public <T> T[] toArray(List<T> list) {
Class clazz = list.get(0).getClass(); // check for size and null before
T[] array = (T[]) java.lang.reflect.Array.newInstance(clazz, list.size());
return list.toArray(array);
}
But beware that the 3rd line above may throw an exception - it's not typesafe.
This method is type safe, and handles some nulls (at least one element must be non-null).
public static Object[] toArray(Collection<?> c)
{
Iterator<?> i = c.iterator();
for (int idx = 0; i.hasNext(); ++idx) {
Object o = i.next();
if (o != null) {
/* Create an array of the type of the first non-null element. */
Class<?> type = o.getClass();
Object[] arr = (Object[]) Array.newInstance(type, c.size());
arr[idx++] = o;
while (i.hasNext()) {
/* Make sure collection is really homogenous with cast() */
arr[idx++] = type.cast(i.next());
}
return arr;
}
}
/* Collection is empty or holds only nulls. */
throw new IllegalArgumentException("Unspecified type.");
}
java.lang.reflect.Array.newInstance(Class<?> componentType, int length)
If you need to dynamically create an array based on a type known only at runtime (say you're doing reflection or generics) you'll probably want Array.newInstance