Consider the method declaration:
String.format(String, Object ...)
The Object ... argument is just a reference to an array of Objects. Is there a way to use this method with a reference to an actual Object array? If I pass in an Object array to the ... argument - will the resultant argument value be a two-dimensional array - because an Object[] is itself an Object:
Object[] params = ....; // Make the array (for example based on user-input)
String s = String.format("%S has %.2f euros", params);
So the first component of the array (Which is used in the String.format method), will be an array and he will generate:
[class.getName() + "#" + Integer.toHexString(hashCode())]
and then an error because the array size is 1.
The bold sequence is the real question.
This is a second question: Does a ... array/parameter have a name?
From the docs on varargs:
The three periods after the final
parameter's type indicate that the
final argument may be passed as an
array or as a sequence of arguments.
So you can pass multiple arguments or an array.
The following works just fine:
class VarargTest {
public static void main(String[] args) {
Object[] params = {"x", 1.2345f};
String s = String.format("%s is %.2f", params);
System.out.println(s); // Output is: x is 1.23
}
}
You can just pass an array:
public void foo(String... args) {
}
String args[] = new String[10];
foo(args);
The situation you are describing is going to be fairly rare: most of the time, your varargs items will be Strings, or numbers, or Widgets... it will be unusual for them to be Objects (which could be anything) or arrays.
But if the varargs argument is a bunch of Objects or an array type, then your question does arise: you can pass it a single array and then how will the compiler know whether you meant to pass an array (the one you provided), or an series of 1 item which it should PUT into an array for you?
A quick test shows the answer:
public class TestClass {
public static void main(String[] args) {
Object anObject = new Object();
Object[] anArray = new Object[] {anObject, anObject};
System.out.println("object1 = " + anObject);
System.out.println("array1 = " + anArray);
takesArgs();
takesArgs(anObject, anObject);
takesArgs(anArray); // is this the same as array1?
takesArgs(anArray, anArray);
}
public static void takesArgs(Object... stuff) {
System.out.println("The array was " + stuff);
}
}
The result of executing (your exact numbers will vary:
object1 = java.lang.Object#3e25a5
array1 = [Ljava.lang.Object;#19821f
The array was [Ljava.lang.Object;#addbf1
The array was [Ljava.lang.Object;#42e816
The array was [Ljava.lang.Object;#19821f
The array was [Ljava.lang.Object;#9304b1
So the answer is that in ambiguous cases it treats what you passed as the array instead of creating a new array to wrap it. This makes sense as you could always wrap it in an array yourself if you wanted the other interpretation.
Related
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.
Why does this work, displaying array in sorted order?:
Integer[] array={7,5,9,3,6,0,2,4};
MergeSort.mergeSort(array,0,7);
System.out.println(Arrays.toString(array));
Specifically, why does passing array to a public static void method mergeSort end up modifying the array itself? I thought that Java protected from this. For example this code:
public static void main(String[] args){
int c=2;
change(c);
System.out.print(c);
}
public static void change(int c){
c=4;
}
returns 2 instead of 4. I am confused why Java allows you to modify an array passed as a parameter, but not an int
Because Java is pass by value, and when you pass an Object (and array is an Object) you pass the value of the reference to the Object. In contrast, a primitive has no reference so you just pass the value.
Edit
Similarly, you could have used the built in Arrays.sort() method to sort your array. Java arrays are not primitive types. In Java, the primitive wrapper types are immutable (like String). Consider,
private static void change(String in) {
in = in + " World"; // <-- modifies in here, can't change caller's reference.
}
private static void change(StringBuilder in) {
in.append(" World"); // <-- uses reference from caller.
}
public static void main(String[] args) {
String str = "Hello";
StringBuilder sb = new StringBuilder(str);
change(str);
change(sb);
System.out.println("one: " + str);
System.out.println("two: " + sb);
}
When using an array, taken as a parameter or not, consider that arr[i] is a pointer to some location of the memory. Then, when receiving an array as a parameter, you have a new reference pointing to the same array object. That means that in your method, instructions such as :
myParameterArray = new int[5];
won't modify the input array, because you are just changing the value of a reference, not the value pointed by it. Nevertheless, instructions such as :
myParameterArray[i] = 5;
will directly modify your input array. That is how methods like Arrays.sort work.
I am trying to write a generic method printAll which prints an array of integer or character.
Here's the code:
public static void main(String[] args) {
char cArray[] = {'a','b','c','d'};
int iArray[] = {1,2,3,4};
printAll(iArray); // Error at this line--refer below the code
}
public static <T> void printAll(T[] t){
for(T x:t) {
System.out.println(x);
}
}
Error: Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - Erroneous tree type: <.any>
printAll(T[] t) will not accept primitive type arrays. You need to pass arrays of the respective wrapper types:
Character cArray[] = {'a','b','c','d'};
Integer iArray[] = {1,2,3,4};
But, you don't need to frame your own method. Just use the already existing - Arrays.toString() method, which is overloaded for different types of primitive arrays, and Object[] array.
Do not reinvent the wheel, use Arrays.toString or Arrays.deepToString. The former already is overloaded to support arrays of primitive (as noted in the first link that receives a char[]), the latter works only on arrays of class references objects.
You cannot use primitive types with generics. Use Integer (or the corresponding reference type)
Integer iArray[] = {1,2,3,4};
printAll(iArray);
You can always overload the printAll method for each of the primitive types.
I don't believe in doing peoples work for them, more to inform and teach how it can be done.
one easy and simple way to print arrays in java will be done through converting the array to a string then print. This works best as array lists. This can then be manipulated to print in a better format.
for example make an array list and add some values:
ArrayList<String> Array = new ArrayList<String>();
Array.add(1)
Array.add(2)
Array.add(3)
Array.add(4)
Array.add(5)
Then from here this can be printed by changing it to a string:
String str = Array.toString()
System.out.println(str);
this will print the following:
[1,2,3,4,5]
you can then change the format of this by using replaceALL on the string before you print it:
String str = Array.toString().replaceAll("[\\[\\]]","")
This will now give:
1,2,3,4,5
That is pretty much it, from here you could add extra things like System.lineSeparator which you would use to replace thhe "," with a new line.
String str = Array.toString().replaceAll("[\\[\\]]","").replaceAll(",",System.lineSeparator());
This would make it print out like:
1
2
3
4
5
class Generic {
public static<T> void printArray(T[] list) {
for(T in : list) {
System.out.println(in);
}
}
public static void main(String[] args) {
String[] lit=new String[3];
lit[0]="aiq";
lit[1]="abusov";
lit[2]="java";
printArray(lit);
}
}
class VarArgs {
public static void printArray(Object... args) {
for (Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args) {
printArray( new Integer[] { 1, 2, 3 });
}
}
The console's output is:
[Ljava.lang.Integer;#1888759
just want to know what is this output. The supposed castiing was via Object[] and that gives 1,2,3 as output, but when I use Object for casting I get this output
You can use
Arrays.toString(new Integer[]{1,2,3});
to view the actual contents of the array.
Or cast new Integer[]{1,2,3} to Object[] instead of Object, i.e:
printArray((Object[])new Integer[]{1,2,3});
Explanation of what is happening in your code:
When you are calling the printArray method you are casting your array to an Object so in fact you are passing just one object (not an array).
The foreach loop in the printArray method iterates only once as only one argument has been passed to the printArray method - the Integer[] {1,2,3} array.
Therefore When your code is calling toString, the toString from the Array class is called, not the toString from the Integer class as you might expect.
Finally the result you got: [Ljava.lang.Integer;#1888759 is caused by the lack of the implementation of the toString method in the array classes in Java.
To fix the issue in your code:
Replace:
printArray((Object)new Integer[]{1,2,3});
with:
printArray((Object[])new Integer[]{1,2,3});
To print the content of an array call:
Arrays.toString(new Integer[]{1,2,3});
As Marco said, this uses the default toString method of an Object, which is its (virtual) memory address.
I would recommend using the Arrays.toString method here
With regards to your use of variable arguments - try disassembling the class file by running
javap -verbose VarArgs
to see what this compiles down into - you should see that your integer array is being passed as the single element of an array.
That is not the same as passing an array! That is the same as passing a variable length of parameters, so the method treats the array as one object, not an array of objects, hence the printout.
public static void printArray(Object[] args) {
for (Object o : args) {
System.out.println(o);
}
}
Object[] objects = new Integer[] { 1, 2, 3, 4 };
printArray(objects);
Notice that you need to use the wrapper for int, primitive types are not subclasses of object.
I have the following function.
func(ArrayList `<String>`[] name) { ........ }
The function fills the ArrayList[]. (I don't want to return the ArrayList[])
However, in the caller function the ArrayList[] obtained has all ArrayLists as null.
For eg.
name = new ArrayList[num];
func(name);
System.out.println(name[0]);
I get NullPointerException at line 3. Is this because of line 1, i.e. I am not parametrizing? If yes, is there another way this can be done? Because java does not allow creating a generic array of parametrized ArrayList.
That is obviously not your real code, but you're creating an array of ArrayLists, which probably isn't what you want. You can probably just do:
ArrayList<String> name = new ArrayList(num);
func(name);
System.out.println(name.get(0));
Note that when you create the ArrayList, you're only specifying the initial capacity, not the size (number of initial items). It will have an initial size of 0. Your func can just call add to add items.
Even better (no typing errors):
ArrayList<String> name = new ArrayList<String>();
I recommend not bothering with the initial capacity argument (num) - just leave it blank and it will work perfectly. But do bother with the generic type of String in the constructor, or the compiler will complain.
If you want to know how to use the ArrayList (for example, why to use the get() function), you should look at the documentation.
For arrays in Java when you create it all of the elements are either 0, false, or null depending in their type.
So:
final List<String>[] foo;
foo = new ArrayList<String>[10];
foo[0].add("hello"); // crash
that crashes because foo = new ArrayList<String>[10]; allocates enough room to hold 10 ArrayList<String> but it sets all of the values to null. So you need one additional step:
for(int i = 0; i < foo.length; i++)
{
foo[i] = new ArrayList<String>();
}
I haven't compiled the code, but pretty sure it is all correct. You would do that between step 1 and 2 of your program.
I am guessing a bit because your code isn't quite accurate (it would not generate a null pointer as written as near as I can tell).
EDIT:
You would do the new in the method and the for loop with the assignments could be done inside of the method. I prefer to allocate and initialize in the same place (less confusing) but you can split it up if you needed to.
The problem you are encountering is due to the fact that in Java, parameters to methods are passed by value. What this means, is that every parameter is effectively "copied" into the method, meaning that any assignments you make to the parameters are only visible within the method, and cannot be seen by the caller.
Going by your example, you're passing in a null reference to an array of List<String>'s. This reference is then "copied" into the func() method, and when func then assigns something to this variable, it is only the local variable that is being updated, and not the reference held by your calling code.
Here's some compilable code (based on your example) that demonstrates the problem:
public class Main {
public static void main(String[] args) {
List<String>[] array = null;
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
The println in fill prints the correct value, because the array variable has been assigned to something within the fill method, however the println in the main method throws an NPE because only the "copy" of the array variable was changed by func, and not the "real" variable.
There are two ways to get around this: either instantiate the array within your calling code, or change the fill() method to return a reference to the array is has created.
Below is the first approach:
public class Main {
public static void main(String[] args) {
List<String>[] array = (List<String>[])new List[10];
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
You may be wondering why this works, because you're still assigning ArrayList's to the elements of the array, however these objects are visible outside of the calling method. The reason for this is that although the fill method is getting a "copy" of the reference to the array, the reference itself is still referencing the same array object. This means that you can modify the internal state of the array object, and any changes you make will be seen by the caller because it referencing that same object.
Below is the second approach:
public class Main {
public static void main(String[] args) {
List<String>[] array = fill();
System.out.println("In main(): " + array[0].get(0));
}
public static List<String>[] fill() {
List<String>[] array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
return array;
}
}
(As an aside, you should generally try to avoid creating arrays of generic collections, a better idea would be to use a list to store the lists themselves. E.g:
List<List<String>> list = new ArrayList<List<String>>();
list.add(new ArrayList<String>());
list.get(0).add("test");
new ArrayList<?>[10] give me incompatible type. However, new ArrayList[10] works for me.