|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Here are a few common problems encountered by developers with explanations for why the occur and how to resolve them.
The
example will generate an
FieldTroubleIllegalArgumentException.
is invoked to set a field that is of the reference type Integer with a value of primitive type. In the non-reflection equivalent Integer val = 42, the compiler would convert (or box) the primitive type 42 to a reference type as new Integer(42) so that its type checking will accept the statement. When using reflection, type checking only occurs at runtime so there is no opportunity to box the value.
import java.lang.reflect.Field;
public class FieldTrouble {
public Integer val;
public static void main(String... args) {
FieldTrouble ft = new FieldTrouble();
try {
Class<?> c = ft.getClass();
Field f = c.getDeclaredField("val");
f.setInt(ft, 42); // IllegalArgumentException
// production code should handle these exceptions more gracefully
} catch (NoSuchFieldException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
$ java FieldTrouble
Exception in thread "main" java.lang.IllegalArgumentException: Can not set
java.lang.Object field FieldTrouble.val to (long)42
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
(UnsafeFieldAccessorImpl.java:174)
at sun.reflect.UnsafeObjectFieldAccessorImpl.setLong
(UnsafeObjectFieldAccessorImpl.java:102)
at java.lang.reflect.Field.setLong(Field.java:831)
at FieldTrouble.main(FieldTrouble.java:11)
To eliminate this exception, the problematic line should be replaced by the following invocation of :
f.set(ft, new Integer(43));
isAssignableFrom() will return false in this test which can be used programmatically to verify whether a particular conversion is possible:
Integer.class.isAssignableFrom(int.class) == false
Similarly, automatic conversion from primitive to reference type is also impossible in reflection.
int.class.isAssignableFrom(Integer.class) == false
The astute reader may notice that if the
$ java FieldSpy java.lang.String count
java.lang.NoSuchFieldException: count
at java.lang.Class.getField(Class.java:1519)
at FieldSpy.main(FieldSpy.java:12)
Class.getField() and
methods return the public member field(s) of the class, enum, or interface represented by the Class object. To retrieve all fields declared (but not inherited) in the Class, use the
method.
An
may be thrown if an attempt is made to get or set the value of a private or otherwise inaccessible field or to set the value of a final field (regardless of its access modifiers).
The
import java.lang.reflect.Field;
public class FieldTroubleToo {
public final boolean b = true;
public static void main(String... args) {
FieldTroubleToo ft = new FieldTroubleToo();
try {
Class<?> c = ft.getClass();
Field f = c.getDeclaredField("b");
// f.setAccessible(true); // solution
f.setBoolean(ft, Boolean.FALSE); // IllegalAccessException
// production code should handle these exceptions more gracefully
} catch (NoSuchFieldException x) {
x.printStackTrace();
} catch (IllegalArgumentException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
$ java FieldTroubleToo
java.lang.IllegalAccessException: Can not set final boolean field
FieldTroubleToo.b to (boolean)false
at sun.reflect.UnsafeFieldAccessorImpl.
throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:55)
at sun.reflect.UnsafeFieldAccessorImpl.
throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:63)
at sun.reflect.UnsafeQualifiedBooleanFieldAccessorImpl.setBoolean
(UnsafeQualifiedBooleanFieldAccessorImpl.java:78)
at java.lang.reflect.Field.setBoolean(Field.java:686)
at FieldTroubleToo.main(FieldTroubleToo.java:12)
final fields from being set after initialization of the class. However, Field is declared to extend
AccessibleObject which provides the ability to suppress this check.