Getting the field "length" in a Java array using reflection - java

class Test {
public static void main(String[] args) throws Exception {
Test t = new Test();
System.out.println(t.field);
System.out.println(t.getClass().getField("field").get(t));
int[] ar = new int[23];
System.out.println(ar.length);
System.out.println(ar.getClass().getField("length").get(ar));
}
public int field = 10;
};
When I run the above code, I get the following result on the command line --
10
10
23
Exception in thread "main" java.lang.NoSuchFieldException: length
at java.lang.Class.getField(Class.java:1520)
at Test.main(Test.java:9)
How come I am unable to access the field "length" in the array?

There is an special java.lang.reflect.Array Class. length is no normal field. To access it there is a special method getLength.

I think this might be a bug in the JVM implementation. Here is my reasoning:
According to the documentation for Class.getField, getField should, as part (1) of its search algorithm, find length if it was declared as a public field: "If C declares a public field with the name specified, that is the field to be reflected."
According to the Java Language Specification, every array has length declared as "The public final field length, which contains the number of components of the array."
Since this field is declared as having name length, getField should either throw a SecurityException as documented, or should return the Field object.
Now interestingly, the Class.getFields method explicitly mentions that "The implicit length field for array class is not reflected by this method. User code should use the methods of class Array to manipulate arrays." This does not seem to parallel getField, so this could either be a misreading on my part or just bad documentation.
Hope this helps!

In Java, arrays are just simple objects. Object don't have any field called length. That's why the reflection is failing.
Please see http://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html for more information on how arrays are implemented.
From the documentation ...
An array's length is not part of its type.

Related

Why can't we access static content via uninitialized local variable?

Take a look at below code:
class Foo{
public static int x = 1;
}
class Bar{
public static void main(String[] args) {
Foo foo;
System.out.println(foo.x); // Error: Variable 'foo' might not have been initialized
}
}
As you see while trying to access static field x via an uninitialized local variable Foo foo; code foo.x generates compilation error: Variable 'foo' might not have been initialized.
It could seem like this error makes sense, but only until we realize that to access a static member the JVM doesn't actually use the value of a variable, but only its type.
For instance I can initialize foo with value null and this will let us access x without any problems:
Foo foo = null;
System.out.println(foo.x); //compiles and at runtime prints 1!!!
Such scenario works because compiler realizes that x is static and treats foo.x as if it was written like Foo.x (at least that is what I thought until now).
So why compiler suddenly insists on foo having a value which it will NOT use at all?
Disclaimer: This is not code which would be used in real application, but interesting phenomenon which I couldn't find answer to on Stack Overflow, so I decided to ask about it.
§15.11. Field Access Expressions:
If the field is static:
The Primary expression is evaluated, and the result is discarded. If evaluation of the Primary expression completes abruptly, the field access expression completes abruptly for the same reason.
Where earlier it states that field access is identified by Primary.Identifier.
This shows that even though it seems to not use the Primary, it is still evaluated and the result is then discarded which is why it will need to be initialized. This can make a difference when the evaluation halts the access as stated in the quote.
EDIT:
Here is a short example just to demonstrate visually that the Primary is evaluated even though the result is discarded:
class Foo {
public static int x = 1;
public static Foo dummyFoo() throws InterruptedException {
Thread.sleep(5000);
return null;
}
public static void main(String[] args) throws InterruptedException {
System.out.println(dummyFoo().x);
System.out.println(Foo.x);
}
}
Here you can see that dummyFoo() is still evaluated because the print is delayed by the 5 second Thread.sleep() even though it always returns a null value which is discarded.
If the expression was not evaluated the print would appear instantly, which can be seen when the class Foo is used directly to access x with Foo.x.
Note: Method invocation is also considered a Primary shown in §15.8 Primary Expressions.
Chapter 16. Definite Assignment
Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.
It doesn't really matter what you try to access via a local variable. The rule is that it should be definitely assigned before that.
To evaluate a field access expression foo.x, the primary part of it (foo) must be evaluated first. It means that access to foo will occur, which will result in a compile-time error.
For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs.
There is value in keeping the rules as simple as possible, and “don’t use a variable that might not have been initialised” is as simple as it gets.
More to the point, there is an established way of calling static methods - always use the class name, not a variable.
System.out.println(Foo.x);
The variable “foo” is unwanted overhead that should be removed, and the compiler errors and warnings could be seen as helping leading towards that.
Other answers perfectly explain the mechanism behind what is happening. Maybe you also wanted the rationale behind Java's specification. Not being a Java expert, I cannot give you the original reasons, but let me point this out:
Every piece of code either has a meaning or it triggers a compilation error.
(For statics, because an instance is unnecessary, Foo.x is natural.)
Now, what shall we do with foo.x (access through instance variable)?
It could be a compilation error, as in C#, or
It has a meaning. Because Foo.x already means "simply access x", it is reasonable that the expression foo.x has a different meaning; that is, every part of the expression is valid and access x.
Let's hope someone knowledgeable can tell the real reason. :-)

Why can't we initialize local variable before declaring it unlike static variable?

Why can't i be initialized before declaring it in code 1 but it can be in code 2 :
class Code1 {
void methodOfCode1() {
// System.out.println(i); can't use a local field before it is defined
// i = 10; can't initialize a local field before it is defined
int i;
}
}
class Code2{
static
{
i = 10; //A field can be initialized before it is defined.
}
static int i;
}
The answer is order of execution.
Code executes sequentially, you must define what something is before you use it. Therefore in a method you must declare a variable before you use it.
In Java the compiler initializes your class in multiple passes. It first runs through and declares all of the static members, then it sets the default values for all static members. This all happens before any methods (static or not) are executed.
It's the scope of the variable & the lack of type prior to its use: you have yet to define i. You must define a variable before it can be used:
int i = 0;
System.out.println(i); // works
System.out.println(j); // will not work
byte j;
Here's the Java Language Specification giving you the detail.
During initialise a variable, some amount of memory is allocated based on datatype.
Unless you allocate memory, you can't initialize value.
Because compiler must know where this variable is stored and how many bytes it have to use. If I tell computer var=97 before initializing, it cannot know where this "var" variable is stored. Also if "var" is char , computer needs one byte to store in RAM. However it also can be an integer which is 4 bytes(depends on different systems). Therefore, there would be an ambiguous situation for the system.Compiler does not allow that , reasonably.
Java is strongly-typed, you can't use something that you don't know what it is. For instance, a method is different if it receives a String or if it receives an int, so the compiler must be able to know which is the proper method to be invoked
For instance, this is valid:
public void dealWithIt(int val){
val++
System.out.println(val);
}
public void dealWithIt(String val){
System.out.println(val);
}
The compiler can't assign a value to a variable before know what type of variable it is.
In Java, a variable's type must be declared before it can be used.
For example:
System.out.println(i); // for this statement i is unknown/undefined...
i = 10; // same for above...
EDITED :
First inside class Code1,
you haven't declare variable before use it, which is against of Java Standard API so obviously compiler will complain.
while into class Code2 case,
you have declare 'static' both instance as well as block.
so it does not required any instance to load it.
(review static concept in depth will let you to the correct direction)

Not understanding how my variables are initialized

so I think I'm missing something. I am aware that
If no constructor is supplied java makes one for you.
If there's a constructor defined, default constructor by java is not used.
Constructor is used to initialize variables
Here's some simple code:
class a {
int f; // a variable with no value
int c; // a variable later initialized by the constructor
int b = 5; // this will be second question, a less important one
a(){
c = 1; // Constructor initiatives C, but not F
}
public static void main(String[] args){
a var = new a();
System.out.print(var.f); // Please see my comment below
}
}
Here's what I do not understand. Why is var.f printed? I did not initialize f in the constructor, however, there's no compile error and 0 value is initialed. I don't understand how '0' is initialized to 'f' despite me not having used it in constructor
Regarding b = 5, I understand what this code leads to, however, I do not think I understand what/who does the initialization here, is it new operator or something else? Thanks.
Edit: since the answers so far are not addressing my question
I am aware of the default values. I thought it was the default constructor that assigned them, is it not? If not, what assigns default values?
Java like most of programming languages has default values for uninitialized variables. Every numeric type of variable is initialized to 0-related value.
Boolean is false as default.
Strings and all of the objects have null as their default value.
Check docs for more info: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
int is a primitive data type. By definition, primitives cannot be null as they are not objects and will have a default value if not initialized. See here: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
If you want to be able to have a variable that is not initialized, you can use the object equivalent of an int java.lang.Integer
Instance variables that are declared but not initialised are given a default value.
References take a default value of null.
Primitives take a default value of zero
In regards to your query on your primitive int variable b, the new operator is not required, the new operator is used when instantiating a reference. When an instantiating a reference an object is created and memory is allocated on the JVM for that object.
Strings are a reference variable, but may be instantiated using the new keyword for example:
String example = new String("abc");
System.out.println(example); // prints abc.
Usually you would just write:
String example = "abc";
In the latter the literal is placed in to the 'string pool'...
You can read more about the string pool here: http://examples.javacodegeeks.com/core-java/lang/string/java-string-pool-example/
If no constructor is supplied java makes one for you.
Correct.
If there's a constructor defined, default constructor by java is not used.
It is not generated.
Constructor is used to initialize variables
Correct.
c = 1; // Constructor initiatives C, but not F
Untrue. Your code initializes c. The generated constructor initializes both.
I did not initialize f in the constructor
No, but Java did.
Java generates the following code for a constructor:
A super call.
Default initialization code for all variables declared without initializers. The default values are false, zero, or null as appropriate to the type.
Calls to all anonymous initializer blocks. (2) and (3) happen in textual order and can therefore be interleaved with each other.
Regarding b = 5, I understand what this code leads to, however, I do not think I understand what/who does the initialization here, is it new operator or something else?
See above.
I am aware of the default values. I thought it was the default constructor that assigned them, is it not?
No.
If not, what assigns default values?
The constructor. Any constructor.

length field in array

As well known in java String class there is a length() method (why not getLength()?). If we look into this method we can see:
public int length() {
return value.length;
}
and value is an array. Why do we access a field? I know that this field is final and nobody can change it, but still what about polymorphism? And where can I see that field? In which class? I've found java.lang.reflect.Array,
but there is no such field as length.
Where can i see that field? In which class?
If you are looking for char array declaration
That's a char array declared on top. You can see that.
The value is used for character storage.
112
113 private final char value[];
And if you are looking for length field of an array
Array's are the part JVM implementation. You need to get the source code of JVM to analyze/see it.
And why we access a field?
That's how the length of an array can be known .
How about polymorthism? I know that this field is final and nobody can change it, but still what about polimorthis?
Never heard of it and if you mean Polymorphism, nothing to do here about it.
I think you might be expecting Java to be a pure OO language... It's not... It's a mixture of Objects and primitives. Primitives do not behave like objects and have language level native stuff, like public length fields etc.
Consider the following... a character array... Its length field is NOT a field in the traditional sense, it is baked into the language at the JVM level. This difference means that you cannot use reflection to access it via Field.getDeclaredField(). Java provides a special mechanism for this case - java.lang.reflect.Array.getLength(Object)
Object obj = new char[] { 'a', 'b' };
int length = ((char[]) obj).length; // .length looks like a field access but done by JVM
int lengthViaRelection = Array.getLength(obj);
This is very different from a standard field on a class where reflection can be used.
private static class ClassWithField {
public int length;
}
ClassWithField obj = new ClassWithField();
int length = obj.length; // .length is normal field access
int lengthViaRelection = (int) ClassWithField.class.getDeclaredField("length").get(obj);
value is an array of char (primitive, not java.lang.Character) and arrays of primitive types have a field named length:
final char[] chars = new char[1];
final int length = chars.length;
String is a final class, so extending String is not possible / permitted and the compiler won't let you do so.
The Strings private member(!) value is an array of chars (the primitive). This can be considered an implementation detail and you should not mess with it.
All arrays in Java got a field named length. It is accessible via property-access, there is no need for something like a "getter".
The length field of an array is not static; so each array will have its own field with its own value. The fact that it is readily has nothing to do with polymorphism; it's just a convenient way to find out information about the array.
The class java.lang.reflect.Array does not describe an array; it is a class that provides static methods to dynamically create and access Java arrays. So it is correct that there is no field length in that class.

What does "public Weatherman(Integer... zips) {" mean in java

I am trying to read some Java code from a tutorial, I don't understand the line:
public Weatherman(Integer... zips) {
I don't understand what the ... represents if it was just (Integer zips) I would understand that there is a variable of class Integer called zips. But the ... are confusing me.
Those are "varargs," syntactic sugar that allows you to invoke the constructor in the following ways:
new Weatherman()
new Weatherman(98115);
new Weatherman(98115, 98072);
new Weatherman(new Integer[0]);
Under the covers the arguments are passed to the constructor as an array, but you do not need to construct an array to invoke it.
That’s a “vararg”. It can handle any number of Integer arguments, i.e.
new Weatherman(1);
is just as valid as
new Weatherman();
or
new Weatherman(1, 7, 12);
Within the method you access the parameters as an Integer array.
You are seeing the varargs feature of Java, available since Java 1.5.
zips is an array of Integer inside the constructor, but the constructor can be called with a variable number of arguments.
From the Java tutorials:
You can use a construct called varargs to pass an arbitrary number of values to a method. You use varargs when you don't know how many of a particular type of argument will be passed to the method. It's a shortcut to creating an array manually (the previous method could have used varargs rather than an array).
To use varargs, you follow the type of the last parameter by an ellipsis (three dots, ...), then a space, and the parameter name. The method can then be called with any number of that parameter, including none.
public Polygon polygonFrom(Point... corners) {
int numberOfSides = corners.length;
double squareOfSide1, lengthOfSide1;
squareOfSide1 = (corners[1].x - corners[0].x)*(corners[1].x - corners[0].x)
+ (corners[1].y - corners[0].y)*(corners[1].y - corners[0].y) ;
lengthOfSide1 = Math.sqrt(squareOfSide1);
// more method body code follows that creates
// and returns a polygon connecting the Points
}
You can see that, inside the method, corners is treated like an array. The method can be called either with an array or with a sequence of arguments. The code in the method body will treat the parameter as an array in either case.
If I remember good it is used when there is a variable number of parameters

Categories