I have a class which has a bunch of Constant Strings.
I need to load this class via reflection and retrieve those constants.
I can get up to:
controllerClass = Class.forName(constantsClassName);
Object someclass = controllerClass.newInstance();
but I am confused on how to retrieve the fields in this class.
A quick sample on accessing fields --
Field[] fields = controllerClass.getDeclaredFields();
for ( Field field : fields ) {
field.setAccessible(true);
System.out.println(field.get(someClass));
}
Here's a little sample:
import java.lang.reflect.Field;
public class Test {
public static class X {
public static int Y = 1;
private static int Z = 2;
public int x = 3;
private int y = 4;
}
public static Object getXField(String name, X object) {
try {
Field f = X.class.getDeclaredField(name);
f.setAccessible(true);
return f.get(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
System.out.println(Test.getXField("Y", null));
System.out.println(Test.getXField("Z", null));
System.out.println(Test.getXField("x", new X()));
System.out.println(Test.getXField("y", new X()));
}
}
Running this little program outputs:
1
2
3
4
A few observations:
For static fields the supplied object to Field.get() can be null.
For brevity, I used an exception catch-all with the base Exception class - you should use explicit exception classes in your code.
While Field.get() usually works as expected, the same cannot be said for Field.set() and its friends. More specifically it will happily change the value of a constant (e.g. a final field, or a private field that is never modified in the class methods), but due to constant inlining the old value may remain in use.
Assuming these constants are in static fields:
import java.lang.reflect.*;
public class Reflect {
public static final String CONSTANT_1 = "1";
public static final String CONSTANT_2 = "2";
public static final String CONSTANT_3 = "3";
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("Reflect");
Field[] fields = clazz.getDeclaredFields();
for(Field f: fields) {
// for fields that are not visible (e.g. private)
f.setAccessible(true);
// note: get(null) for static field
System.err.printf("%s: %s\n",f, (String)f.get(null) );
}
}
}
The output is:
$ java Reflect
public static final java.lang.String Reflect.CONSTANT_1: 1
public static final java.lang.String Reflect.CONSTANT_2: 2
public static final java.lang.String Reflect.CONSTANT_3: 3
Note that to get the value of a static field, you supply null as the arg.
You get to know about the modifiers via the class and not the object reference.
http://download.oracle.com/javase/tutorial/reflect/class/classModifiers.html
Related
I am clear that accessing a private field in Java could be easily achieved by using Reflection. As is shown in posts as How to read the value of a private field from a different class in Java? and there are many.
To achieve that , the critical move is to set accessibility.
Field f = obj.getClass().getDeclaredField("aaa");
f.setAccessible(true);
But in my case, the situation is like:
class A{
private B b;
class B{
private String value;
}
}
and I want to get value of a.b.value in another class. When I was trying, I intended to do it as
A obj = createInstanceA();
Field f = obj.getClass().getDeclaredField("b");
f.setAccessible(true);
A.B b = f.get(obj);
Field f2 = b.getClass().getDeclaredField("value");
f2.setAccessible(true);
String value = f2.get(b);
Which doesn't work out because B could not be declared out of A.
Do I have other options if Class A can not be modified?
You have do like this,
public class A {
private B b = new B();
class B {
private String value = "String";
}
}
public class ClassB {
public static void main(String args[]) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
A obj = new A();
Field f = obj.getClass().getDeclaredField("b");
f.setAccessible(true);
A.B b = (B) f.get(obj);
Field f2 = b.getClass().getDeclaredField("value");
f2.setAccessible(true);
String value = (String) f2.get(b);
System.out.println(value);
}
}
What you are missing is to setAccessible(true) to inner class field.
As a first, in your example field b is null. Is this correct?
So, you try to get class of null.
As a second, in your example you use inner classes and there is a specific langugage mechanizm. You can create instance of class B only by some instance of class A. And all instances of class B has access to private field of it's parrent (class A). As in this example.
class OuterClass
{
// static member
static int outer_x = 10;
// instance(non-static) member
int outer_y = 20;
// private member
private int outer_private = 30;
// inner class
class InnerClass
{
void display()
{
// can access static member of outer class
System.out.println("outer_x = " + outer_x);
// can also access non-static member of outer class
System.out.println("outer_y = " + outer_y);
// can also access private member of outer class
System.out.println("outer_private = " + outer_private);
}
}
}
// Driver class
public class InnerClassDemo
{
public static void main(String[] args)
{
// accessing an inner class
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
innerObject.display();
}
}
May be inner classes can solves your problem? (You can read abou it here https://www.geeksforgeeks.org/nested-classes-java/)
Then reflecsoin is not needed.
In general - equivalent of final field in Java is the readonly field in C#. But the more I read about C# the more I see that there are some differences in details.
I've found myself two differences:
Fields marked as readonly assigned as part of definition can be reasigned in constructor
In Java it is not possible to do that with final fields. Examples:
Example - C Sharp
public class Foo
{
public readonly int a = 1;
public Foo()
{
a = 2;
}
}
and now
Foo f = new Foo();
Console.WriteLine(f.a);
will give us 2 as an output
(side question - is this behavior can be actualy used for something useful? As far as I know I cannot assign value to base class' readonly field in dervied class)
Example - Java
class Foo {
private final int i = 3;
public Foo() {
// compilation error
// i = 2;
}
}
Orders of initalization of readonly and final fields in class hierarchy are different in both languages
In Java it will go from base class to dervied.
In C# it will go from derived class to base.
Example - C Sharp
Based on article Eric Lippert: Why Do Initializers Run In The Opposite Order As Constructors? Part One:
public class Print
{
public Print(string text)
{
Console.WriteLine(text);
}
}
public class Base
{
private readonly Print #base = new Print("Base class");
}
public class Derived : Base
{
private readonly Print derived = new Print("Derived class");
}
In case of calling new Derived() we will see:
Derived class
Base class
As far as I understood - this order of initalization guarantees that readonly fields are always initalized before usage. In case of following code (based on second part of Eric's article - Why Do Initializers Run In The Opposite Order As Constructors? Part Two):
public class Foo
{
}
public class Base
{
public Base()
{
if (this is Derived)
{
((Derived)this).danger();
}
}
}
public class Derived : Base
{
private readonly Foo derived = new Foo();
public void danger()
{
Console.WriteLine("access: {0}", derived.GetHashCode());
}
}
Calling new Derived() is safe.
Example - Java
Similar code in Java:
class Print {
public Print(String text) {
System.out.println(text);
}
}
class Base {
private final Print base = new Print("Base class");
}
class Derived extends Base {
private final Print derived = new Print("Derived class");
}
Call new Derived() will result with:
Base class
Derived class
So in case of following code:
class Base {
public Base() {
if (this instanceof Derived) {
((Derived)this).danger();
}
}
}
class Derived extends Base {
private final Foo field = new Foo();
public void danger()
{
System.out.println("access: " + field.hashCode());
}
}
The call new Derived() will result with NullPointerException
Question
My question is: Are there other differences (even small ones) between Java's final fields and readonly fields in C# ? To make question more clear - I have in mind only final instance fields in Java (so no static finals, no final variables, no other final "thigs")
Presume we have two different packages... one package can't be accessed but we like to know the value of a complex field called b.
public class A {
private String whatever;
private B b;
private static class B {
final ArrayList<Z> c = new ArrayList<Z>();
private void addItem(Z z) {
this.c.add(z);
}
private Z getItem(int nr) {
return this.c.get(nr);
}
}
}
public class Reflect extends A {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Reflect ref = new Reflect();
Class getA = ref.getClass().getSuperclass();
Field getB = getDeclaredField("b");
getB.setAccessible(true);
Class bInst = getB.getClass();
Method bMeth = bInst.getMethod("getItem", Integer.TYPE);
Object zInst = bMeth.invoke(new Integer(123));
}
}
How can I get the value if I don't get the complex type B from the package ?
Still get java.lang.NoSuchMethodException: stackOver.A.getItem(int) even I set the field gstB accessible ....
The only thing you are missing is that getField only gives you public accessible fields.
Field getB = getA.getDeclaredField("b");
will give you any field of that class.
A longer example
class Main {
public static class A {
private String whatever;
private B b = new B();
private static class B {
final ArrayList<String> c = new ArrayList<String>();
private void addItem(String z) {
this.c.add(z);
}
private String getItem(int nr) {
return this.c.get(nr);
}
}
}
public static class Reflect extends A {
public static void main(String... ignored) throws Exception {
Reflect ref = new Reflect();
Class getA = ref.getClass().getSuperclass();
Field getB = getA.getDeclaredField("b");
getB.setAccessible(true);
Object b = getB.get(ref);
Method addItem = b.getClass().getDeclaredMethod("addItem", String.class);
addItem.setAccessible(true);
addItem.invoke(b, "Hello");
Method getItem = b.getClass().getDeclaredMethod("getItem", int.class);
getItem.setAccessible(true);
String hi = (String) getItem.invoke(b, 0);
System.out.println(hi);
}
}
}
prints
Hello
How can I get the value if I don't get the complex type B from the package ?
You can get it as an Object, and then use reflection to further discover the methods that it exposes.
Object bInst = ... // Get b through reflection
Class bClass = bInst.getClass();
Method[] bMeth = bClass.getMethod("getItem", Integer.TYPE);
Object zInst = bMeth.invoke(new Integer(123));
Use commons beanutils library and use following method, it is much cleaner than doing it yourself
PropertyUtils.getNestedProperty(ref, "b.propertyOfClassB");
replace propertyOfClassB with actual property name.
Consider this code:
class A {
static int i=3;
}
public class TT extends A {
public static void main(String[] args) {
System.out.println(new A().getClass().i);
}
}
Can the getClass() method be used to access static variables in this context?
Not like that, no. getClass() returns a Class<?>, and i isn't a member of Class. You could use getClass() followed by reflection to get the field value, but it's not at all clear what you're trying to achieve here - when in the example you've given (which is all we've got to go by) simply using A.i would be simpler and clearer.
Perhaps this code answers your question:
package com.cc.test;
import java.lang.reflect.Field;
public class TestMain {
public static void main(String[] args) throws Exception {
Class theClass = Class.forName("com.cc.test.TestMain$MyClass");
Field theField = theClass.getField("myField");
int theValue = theField.getInt(null); // null only works if myField is static
System.out.println(theValue); // prints 99
}
private static class MyClass {
public static int myField = 99;
}
}
Why can't enum's constructor access static fields and methods? This is perfectly valid with a class, but is not allowed with an enum.
What I'm trying to do is store my enum instances in a static Map. Consider this example code which allows lookup by abbreivation:
public enum Day {
Sunday("Sun"), Monday("Mon"), Tuesday("Tue"), Wednesday("Wed"), Thursday("Thu"), Friday("Fri"), Saturday("Sat");
private final String abbreviation;
private static final Map<String, Day> ABBREV_MAP = new HashMap<String, Day>();
private Day(String abbreviation) {
this.abbreviation = abbreviation;
ABBREV_MAP.put(abbreviation, this); // Not valid
}
public String getAbbreviation() {
return abbreviation;
}
public static Day getByAbbreviation(String abbreviation) {
return ABBREV_MAP.get(abbreviation);
}
}
This will not work as enum doesn't allow static references in its constructor. It however works just find if implemented as a class:
public static final Day SUNDAY = new Day("Sunday", "Sun");
private Day(String name, String abbreviation) {
this.name = name;
this.abbreviation = abbreviation;
ABBREV_MAP.put(abbreviation, this); // Valid
}
The constructor is called before the static fields have all been initialized, because the static fields (including those representing the enum values) are initialized in textual order, and the enum values always come before the other fields. Note that in your class example you haven't shown where ABBREV_MAP is initialized - if it's after SUNDAY, you'll get an exception when the class is initialized.
Yes, it's a bit of a pain and could probably have been designed better.
However, the usual answer in my experience is to have a static {} block at the end of all the static initializers, and do all static initialization there, using EnumSet.allOf to get at all the values.
Quote from JLS, section "Enum Body Declarations":
Without this rule, apparently reasonable code would fail at run time
due to the initialization circularity inherent in enum types. (A
circularity exists in any class with a "self-typed" static field.)
Here is an example of the sort of code that would fail:
enum Color {
RED, GREEN, BLUE;
static final Map<String,Color> colorMap = new HashMap<String,Color>();
Color() {
colorMap.put(toString(), this);
}
}
Static initialization of this enum type would throw a NullPointerException because the static variable colorMap is
uninitialized when the constructors for the enum constants run. The
restriction above ensures that such code won’t compile.
Note that the example can easily be refactored to work properly:
enum Color {
RED, GREEN, BLUE;
static final Map<String,Color> colorMap = new HashMap<String,Color>();
static {
for (Color c : Color.values())
colorMap.put(c.toString(), c);
}
}
The refactored version is clearly correct, as static initialization occurs top to bottom.
maybe this is what you want
public enum Day {
Sunday("Sun"),
Monday("Mon"),
Tuesday("Tue"),
Wednesday("Wed"),
Thursday("Thu"),
Friday("Fri"),
Saturday("Sat");
private static final Map<String, Day> ELEMENTS;
static {
Map<String, Day> elements = new HashMap<String, Day>();
for (Day value : values()) {
elements.put(value.element(), value);
}
ELEMENTS = Collections.unmodifiableMap(elements);
}
private final String abbr;
Day(String abbr) {
this.abbr = abbr;
}
public String element() {
return this.abbr;
}
public static Day elementOf(String abbr) {
return ELEMENTS.get(abbr);
}
}
The problem solved via a nested class. Pros: it's shorter and also better by CPU consumption. Cons: one more class in JVM memory.
enum Day {
private static final class Helper {
static Map<String,Day> ABBR_TO_ENUM = new HashMap<>();
}
Day(String abbr) {
this.abbr = abbr;
Helper.ABBR_TO_ENUM.put(abbr, this);
}
public static Day getByAbbreviation(String abbr) {
return Helper.ABBR_TO_ENUM.get(abbr);
}
When a class is loaded in the JVM then static fields are initialized in the order in which they appear in code. For e.g.
public class Test4 {
private static final Test4 test4 = new Test4();
private static int j = 6;
Test4() {
System.out.println(j);
}
private static void test() {
}
public static void main(String[] args) {
Test4.test();
}
}
The output will be 0. Note that test4 initialization takes place in static initialization process and during this time j is not yet initialized as it appears later. Now if we switch order of static initializers such that j comes before test4. The output will be 6.But in case of Enums we cannot alter order of static fields. The first thing in enum must be the constants which are actually static final instances of enum type.Thus for enums its always guaranteed that static fields wont be initialized before enum constants.Since we cannot give any sensible values to static fields for use in enum constructor, it would be meaningless to access them in enum constructor.