There is a multidimensional String array being passed in as an Object.
I'm supposed to "unfold" it and process each of its primitive entries.
There's no way to know the dimensions other than by looking at the Object itself.
The difficulty i'm having is in casting. I can look up the array dimension by invoking its getClass().getName() and counting the [-s there.
But then how to cast it?
String[] sa = (String[]) arr;
is giving
Exception in thread "main" java.lang.ClassCastException: [[Ljava.lang.String; cannot be cast to [Ljava.lang.String;
Can this casting be done without any use of reflection?
Note - The array can be of any dimension - not just 1 or 2.
TIA.
If you want to work with an array which dimension is not known at the compile time, I would suggest you to recursively process all of its entries instead of trying to cast it.
You can use object.getClass().isArray() method to check if the current entry is an array and then iterate over it using Array.getLength(object) and Array.get(object, i):
public static void main(String[] args) {
Object array = new String[][] {new String[] {"a", "b"}, new String[] {"c", "d"}};
processArray(array, System.out::println);
}
public static void processArray(Object object, Consumer<Object> processor) {
if (object != null && object.getClass().isArray()) {
int length = Array.getLength(object);
for (int i = 0; i < length; i ++) {
Object arrayElement = Array.get(object, i);
processArray(arrayElement, processor);
}
} else {
processor.accept(object);
}
}
If the size of the array is not known statically (at compile time), then it's logically impossible to get the length relying solely on static means, i.e. without use of dynamic means.
Perhaps this question has the solution you need:
Getting the field "length" in a Java array using reflection
Related
I'm relatively new to C# and the way it handles multidimensional arrays compared to Java is screwing with me.
I'm sure there's a simple solution and that I'm gonna feel really stupid for not realizing it, but I can't seem to find an answer online or figure it out myself.
Consider the following code snippet in java:
Object firstElement(Object[] arr) {
return arr[0];
}
This would return the first element of an array of any number of dimensions; however, in C# this will throw out an error for greater than one dimension because it doesn't recognize a multidimensional array as an object array. The only way to do this I found was by casting the multidimensional array to a System.Array and then using the following code:
object firstElement(Array arr) {
foreach (object obj in arr)
return obj;
}
Is it even possible to do this without a foreach loop in the function? I have tried returning the object using arr.GetValue(0) but this will throw an error again if the array is not one dimensional. Thanks for helping this C# newbie out!
C# expects you to address every dimension in a multidimensional array even if you are meaning to access, say, [0,0].
Object firstElement(Object[] arr) {
return arr[0];
}
For this reason, the code above will throw at compile time.
this code only takes one-dimensional arrays. Try this instead:
Object firstElement(Object[][] arr) {
return arr[0][0];
}
Adjust amount of brackets according to the amount of dimensions.
It is also more common to use the keyword-aliases for primitives like object or int. I do suspect you will replace the Object with an actual class / struct instance or primitive at some point.
object firstElement(object[][] arr) {
return arr[0][0];
}
What I would suggest you reading up on are the two different types of "multidimensional"-arrays: Jagged and actual multidimensional-arrays. The key difference is that each row has to have the same amount of columns in a multidimensional-array whereas the jagged array can be irregular in this regard.
/edit:
I seem have to misunderstood your intention. I believe you try to get every first element of each row. If that is the case then try this one:
List<object> firstElements(object[][] arr)
{
List<object> firsts = new List<object>();
for(int i = 0; i < arr.length; i++)
{
firsts.Add(arr[i][0]);
}
return firsts;
}
When I create a method to determine what value I want to return, usually I can return a value directly - like so:
return 0;
However, I've discovered that when returning arrays, I have to create a new instance of an array, and return it - like so:
String[] rtnArr = {"str1", "str2"};
return rtnArr;
Why is this? Am I creating two arrays here, or am I only specifying a type when I instantiate the method?
Edit: I should clarify that I am returning one or another array based on a preliminary condition. That is to say, I have a switch and each case returns an array of different strings.
You are not creating two arrays. Array initializers are only allowed when initiating a variable, so you can't use them directly in a return statement.
You don't actually need a variable to return an array. You can also return an array like this
return new String[] {"Hello", "World"};
When you declare an array you can initialize it as String test[] = {"Hello", "World"}; because the array is obviously a string array so you don't need to do new String[] {"Hello", "World"}, but otherwise, you need an explicit initialization of the array with a type for type safety.
I've discovered that when returning arrays, I have to create a new instance of an array, and return it Why is this ? Am I creating two arrays here, or am I only specifying a
type when I instantiate the method ?
You don't need to return a new instance of the array always, sometimes you might need to return an existing array object as shown in the below code:
public class MyArrayTest {
private String[] myArray;
public MyArrayTest(String[] myArray) {
this.myArray = myArray;
}
public String[] getMyArray() {
return myArray;//returning existing array object
}
}
We can determine the length of an ArrayList<E> using its public method size(), like
ArrayList<Integer> arr = new ArrayList(10);
int size = arr.size();
Similarly we can determine the length of an Array object using the length property
String[] str = new String[10];
int size = str.length;
Whereas the size() method of ArrayList is defined inside the ArrayList class, where is this length property of Array defined?
Arrays are special objects in java, they have a simple attribute named length which is final.
There is no "class definition" of an array (you can't find it in any .class file), they're a part of the language itself.
10.7. Array Members
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
The public method clone, which overrides the method of the same name in class Object and throws no checked exceptions. The return type of the clone method of an array type T[] is T[].
A clone of a multidimensional array is shallow, which is to say that it creates only a single new array. Subarrays are shared.
All the members inherited from class Object; the only method of Object that is not inherited is its clone method.
Resources:
JLS - Arrays
It's "special" basically, with its own bytecode instruction: arraylength. So this method:
public static void main(String[] args) {
int x = args.length;
}
is compiled into bytecode like this:
public static void main(java.lang.String[]);
Code:
0: aload_0
1: arraylength
2: istore_1
3: return
So it's not accessed as if it were a normal field. Indeed, if you try to get it as if it were a normal field, like this, it fails:
// Fails...
Field field = args.getClass().getField("length");
System.out.println(field.get(args));
So unfortunately, the JLS description of each array type having a public final field length is somewhat misleading :(
It's defined in the Java language specification:
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
Since there is a limitless number of array types (for every class there is a corresponding array type, and then there are multidimensional arrays), they cannot be implemented in a class file; the JVM has to do it on the fly.
Even though this is not a direct answer to the question, it is an addition to the .length vs .size() argument. I was researching something related to this question so when I came across it I noticed that the definition(s) provided here
The public final field length, which contains the number of components of the array.
is not "exactly" correct.
The field length contains the number of available places to put a component, not the number of components present in the array. So it represents the total available memory allocated to that array, not how much of that memory is filled.
Example:
static class StuffClass {
int stuff;
StuffClass(int stuff) {
this.stuff = stuff;
}
}
public static void main(String[] args) {
int[] test = new int[5];
test[0] = 2;
test[1] = 33;
System.out.println("Length of int[]:\t" + test.length);
String[] test2 = new String[5];
test2[0] = "2";
test2[1] = "33";
System.out.println("Length of String[]:\t" + test2.length);
StuffClass[] test3 = new StuffClass[5];
test3[0] = new StuffClass(2);
test3[1] = new StuffClass(33);
System.out.println("Length of StuffClass[]:\t" + test3.length);
}
Output:
Length of int[]: 5
Length of String[]: 5
Length of StuffClass[]: 5
However, the .size() property of the ArrayList does give the number of elements in the list:
ArrayList<Integer> intsList = new ArrayList<Integer>();
System.out.println("List size:\t" + intsList.size());
intsList.add(2);
System.out.println("List size:\t" + intsList.size());
intsList.add(33);
System.out.println("List size:\t" + intsList.size());
Output:
List size: 0
List size: 1
List size: 2
it's public final field , which contains the number of components of the array (length may be positive or zero)
An array thus has the same public fields and methods as the following class:
class A implements Cloneable, java.io.Serializable {
public final int length = X;
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e.getMessage());
}
}
}
more info at
10.7 Array Members
http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html
To answer it as it-is, where is this length property of array defined? In a special Object header.
Easy to see via JOL
int [] ints = new int[23];
System.out.println(ClassLayout.parseInstance(ints).toPrintable());
One of the lines from this output is going to be:
OFFSET SIZE TYPE DESCRIPTION
16 4 (object header) 17 00 00 00 (00010111 00000000 00000000 00000000) (23)
Usually Objects have two headers (mark and klass), arrays have one more that always occupy 4 bytes in length, as size is an int.
The keyword length acts like a data filed defined. When using in an array, we can use it to access how many elements in an array. Regarding to String[], we can invoke length() method defined in String class. With regard to ArrayList, we can use size() method defined in ArrayList. Note that when creating an array list with ArrayList<>(capacity), the initial size() of this array list is zero since there is no element.
Is there a more convenient way to initialize an array of objects than doing this?
SomeClass[] someArray = new SomeClass[100];
//...
for (int i = 0; i < someArray.length; i++) {
someArray[i] = new SomeClass();
}
// ...
Use Arrays.fill()
String[] stringArray = new String[100];
Arrays.fill(stringArray, "");
It's not any faster since it iterates over the array just like you did, but it is more convenient.
Arrays.fill() code
public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
rangeCheck(a.length, fromIndex, toIndex);
for (int i=fromIndex; i<toIndex; i++)
a[i] = val;
}
Because of the immutability of String in Java, your question is a bit strange. The primary thrust suggests you are looking for this:
String[] arr = new String[100];
Arrays.fill(arr, new String());//Array utility
However, this does not actually net you anything, because you will have to effectively create a new String object whenever you replace one of those array items with a different String. This means that the act of creating a new String() is redundant and therefore less efficient.
This begs the question: why are you doing this? Is it to ensure that there is a valid object being returned? Or that the object in the array is actually a String? If the latter, make use of generics:
List<String> arr = new ArrayList<String>();
This solves the same problem and nets you benefits of object-orientation. It is generally recommended you stay away from primitive arrays if you can: object-based arrays are far more usable, leading to cleaner code and often more efficient programs.
If you are using a mutable type, and the point of pre-filling is to ensure that an object exists when it's retrieved from the array, the best way to handle this is to actually use exceptions on the receiving end, for two reasons: the first being that you save memory by not allocating memory before you actually need it (and all the attendant savings that go along with that) and the second being that there is little stopping an array from having an element set to null, so you have to check anyway:
try {
SomeObject myObj = arr.get(idx);
myObj.doSomethingFun();//will fail if this is null!
} catch (NullPointerException e) {
//do something intelligent like return a fail case.
}
Note that while exceptions carry overhead if they catch an actual error, they have no overhead until that point. For this reason you don't want to use them for flow-of-control, but you do want to use them (more than you probably do) to catch edge cases that don't make sense.
This isn't quicker, but its less code:
String[] stringArray = new String[100];
Arrays.fill(stringArray, "");
So, you told you want to create array of distinct objects. Then there must be a default constructor or a factory that you pass in. I'll show code for first case - when you can call empty constructor with Class<...>.newInstance():
import java.lang.reflect.Array;
// ... in a class:
#SuppressWarnings("unchecked")
public static <T> T[] initializedArray(int size, Class<T> classHint) throws java.lang.Exception {
T[] result = (T[]) Array.newInstance(classHint, size);
for (int i = 0; i < size; ++i) {
result[i] = classHint.newInstance();
}
return result;
}
Example usage here: http://ideone.com/pbTFq9
you can declare like
String[] array;
...
array = new String[]{object1, object2};
This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
Closed last month.
I'm using Netbeans.
When I run the program below, I get this as output [I#de6ced! How come?
import java.util.Arrays;
import java.util.Vector;
public class Test {
public static void main (String[] args) {
int[] a = new int[1];
a[0] = 5;
Vector<Integer> a1 = new Vector(Arrays.asList(a));
System.out.println(a1.elementAt(0));
}
}
I also tried working around it but then I got a
Exception in thread "main" java.lang.ClassCastException: [I cannot be cast to java.lang.Integer
at TopCoder.Test.main(Test.java:13)
Java Result: 1
public static void main (String[] args) {
int[] a = new int[1];
a[0] = 5;
Vector<Integer> a1 = new Vector(Arrays.asList(a));
int b = a1.elementAt(0); /* EXCEPTION THROWN HERE */
System.out.println(b);
}
[I#de6ced can be broken down as:
- [ an array
- I of integers
- de6ced with this reference hash-code (which, in Sun Java, is basically the reference)
toString() for Object returns somethine like ClassName#HashCode, which is exactly what you're seeing happen here just with the (rather wierd) primitive-array classes.
The problem is that the wrong type is being inferred by the <T> List<T> asList(T...) method. Change your code to use Integer[] instead of int[]. This is a consequence of int being primitive, but int[] is an object.
You can see this directly:
System.out.println(Arrays.asList(new int[]{5}));
=> [[I#some reference
System.out.println(Arrays.asList(new Integer[]{5}).get(0));
=> 5
Integer[] a = new Integer[1];
a[0] = new Integer(5);
List list = Arrays.asList(a);
System.out.println(list.get(0));
The above works as you would expect.
So it looks like the "int" array is treated like an Object and not an array of Integers. In other words auto boxing doesn't seem to be applied to it?
I think I have figured out what was happening:
int[] a = new int[1];
a[0] = 5;
We now have an array of int.
Vector<Integer> a1 = new Vector(Arrays.asList(a));
The problem is in the way you are calling Arrays.asList.
The signature for asList is "public static <T> List<T> asList(T... a)". It does not apply with T == int because int is not an object type. And it cannot match with T == Integer because the base type of the array a is int not Integer. What is actually happening is that T is binding to int[], and Arrays.aslist(a) is returning a List<int[]> with one element that is the value of a!!!
Then you create a Vector from the List and get a Vector with one element ... the original int[] that was assigned to 'a'.
System.out.println(a1.elementAt(0));
Finally, a1.elementAt(0) fetches the int[], and you end up calling the Object implementation of the toString() method.
A couple of important lesson to learn from this:
it is a bad idea to mix raw types and
generic types as you do on the line
that declares a1, and
it is a bad idea to ignore, or turn
off the compiler's generic type-safety
warnings
It looks like the int's are becoming Integers using autoboxing so you are getting an object reference instead of the value. Still seems weird as it should call the correct toString and end up with "5".