Using Java reflections to get class variables - java

I have the following class:
public final class ClassMap {
public static final Class HELLO = HelloActivity.class;
}
I want to be able to access HelloActivity.class knowing the string "HELLO". I've tried the following:
Field classField = ClassMap.class.getField("HELLO");
But that returns a Field object. How can I get a Class object back?
Thanks!

Now that you have the Field object representing the field, ask for the value, i.e. call classField.get(Object obj).
Since your field is static, the obj parameter will be ignored, and you should just give a null value. Javadoc says so:
If the underlying field is a static field, the obj argument is ignored; it may be null.
So, do this:
Field classField = ClassMap.class.getField("HELLO");
Object value = classField.get(null);

Related

Android Java, How to get the value of class attribute?

I want to get the value a class attribute, But I am getting exception : java.lang.NoSuchFieldException
Person.class
public class Person {
public static final String name = "person name";
}
MainActivity.class
...
private void method() {
Class myClass = Person.class;
String name = myClass.getField("name");
}
...
I am getting a java.lang.NoSuchFieldException exception for the getField method.
I tried these solutions but with no avail ...
Change getField method to getDeclaredField
Surround the code by try/catch, and got another error (Incompatible types : java.lang.String and java.lang.reflect.Field)
Invalidate Android Studio caches and restart
I don't Know how to access this value, Any solutions or suggestions are welcomed.
Thanks in advance.
Change getField method to getDeclaredField
Surround the code by try/catch, and got another error (Incompatible
types : java.lang.String and java.lang.reflect.Field)
that because getDeclaredField will return object of type Field not String,
just change your code to this
Field field = myClass.getDeclaredField("name");
//do something with field
If you want to access the value of the field, you can use the get(...) method with a null argument - since it's a static field, it does not require any instance:
private void method() {
Class myClass = Person.class;
Field field = myClass.getField("name");
String name = field.get(null);
Log.d("Test", "field value: " + name);
}
In your case, it doesn't matter whether you use getField(...) or getDeclaredField(...). You would want to use the latter if you want to grab a field in its superclass or an interface implemented by your class.
For example, if Person were to extend from a class that has a field named sample, you would need to use getDeclaredField("sample") instead.
If your variable in the class "Person" is static:
(This is not the best solution in my opinion)Explanation: getField method returns a type "field" so you CAN NOT save into a variable from another type without a conversion.
YourField.get returns an object so you CAN NOT save into a variable from another type without a conversion.
try{
Class _person = Person.class;
Field field = _person.getField("name");
Object value = field.get(null);
String valueString = (String)value; /*The String you are looking for*/
}catch (Exception e) {
//TODO handle exception
}
If your variable in the class "Person" is static:
String valueString = Person.name /*The value you are looking for*/
If your variable isn't static but public:
IMPORTANT (If you have not set a default value to the variable): In this case the value will be an empty string because you are creating a new instance of your calss. You can set the "person name" in the constructor of your Person class another way you will get an empty string because the variable isn't static.
Person _person = new Person();
String personName = _person.name;
Since that's a constant you declared, access it directly with the class name as below,
String name = Person.name;
It's a static constant. Static means there is only one value at a time possible. Or say it like this: The class attribute 'name' is a class attribute, not an object attribute! The attribute belongs to the class!
So you don't need to create an instance of your Person class.
You just can use:
String name = Person.name;
Remember: this only works cause the name belongs to the class. And it does so, because you declared your name variable static.

retrieve field of type class

I have a class that is going to be passed into a function and it will be defined as follows:
class ayy{
String blah;
Class a;
Class b;
}
I want to be able to invoke the getSimpleName() method on the classes a and b. Currently I am doing it as follows:
Class c = (Class)argument; // Where argument is the "ayy" class
c.getField("a").getSimpleName();
But this gives me an error saying "getSimpleName()" is not defined for type field.
You cannot call a method directly on an object that results from reflection, such as you're doing with Field, as if it were a reference variable of the desired type.
Instead, you'll need to call getDeclaredField, because getField only gets public fields. Also, you'll need to get() the value of the Field, passing in an instance of the ayy class, which will return the value of the Field. Then you'll need to cast it to a Class, because get() returns an Object. Then you can call getSimpleName().
Class<?> classOfA = (Class<?>) c.getDeclaredField("a").get(anAyy);
String simpleName = classOfA.getSimpleName();
You'll also need to catch the various reflection-related exceptions that may be thrown.

Why doesn't calling a static variable chained from a static method that returns null throw a NPE?

I have the following code
public class Test {
static String mountain = "Everest";
static Test favorite() {
System.out.print("Mount ");
return null;
}
public static void main(String[] args) {
System.out.println(favorite().mountain);
}
}
I thought it would raise a NPE but it is giving Mount Everest as output can anyone clarify?
It just so happens that you can access static members on object references. In that case, the member is resolved according to the type of the reference, not its value.
The Java Language Specification says this about field access of static members
If the field is a non-blank final field, then the result is the value
of the specified class variable in the class or interface that is the
type of the Primary expression.
If the field is not final, or is a blank final and the field access
occurs in a constructor, then the result is a variable, namely, the
specified class variable in the class that is the type of the Primary
expression.
So the Primary, the instance, does not matter.
When you access a static member on an instance of a class, the Java compiler completely ignores the runtime value (and even class) of the variable and uses the member belonging to the declared class. In this case, your code is equivalent to:
favorite();
System.out.println(Test.mountain);
Even if you had code like this:
public class SubTest extends Test {
static String mountain = "Kilimanjaro";
}
...
Test foo = new SubTest();
System.out.println(foo.mountain);
you'll still get the value on the Test class.
favorite() is a static method that returns Test type. Then you use the static variable of this class (mountain). This all works as you never use (and do not need to use) an instance of this class so there can be no null pointer exception.

assign instance variable to a static variable

I have something like this:
public class Test {
public static MyObject o4All = null;
public MyObject o4This = null;
public void initialize() {
// create an instance of MyObject by constructor
this.o4This = new MyObject(/* ... */);
// this works, but I am wondering
// how o4All is internally created (call by value/reference?)
Test.o4All = this.o4This;
}
}
I know, I should assign or change a static variable only by a static method. But according to java-docs (http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html), I can use an object reference.
Class methods cannot access instance variables or instance methods
directly—they must use an object reference.
What if I change a property of o4This? Will the property of o4All also be changed indirectly?
What if I change a property of o4This? Will the property of o4All also
be changed indirectly?
Yes, it will be changed. Because now, both o4All and o4This are referring to the same instance. You did this by the following assignment: -
Test.o4All = this.o4This;
In the above assignment, you are not creating a copy of the instance referred to by o4This, rather, you are just copying the value of o4This in the o4All reference. Now, since o4This value is a reference to some instance. So, o4All now have reference to the same instance as that of o4This. And hence, any change you make to the instance using a reference, will be reflected in the other reference too.

Using reflection get a static private hashmap in java

I'm trying to find a way to extract a HashMap from a private static field within another class via Java.
eg.
Inside FooClass there is a static field that looks like this:
private Map entityRenderMap;
Then in its construct it has:
entityRenderMap = new HashMap();
How do you get the values within entityRenderMap via Reflection in Java? I've tried this but get errors:
cl = RenderManager.class.getDeclaredField("entityRenderMap");
cl.setAccessible(true);
Object foo = cl.get(this.entityRenderMap);
Mod.log(cl.getName());
The error I get is:
java.lang.IllegalArgumentException: Can not set java.util.Map field RenderManager.entityRenderMap to java.util.HashMap
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(Unknown Source
First, your code doesn't match your explanation. Is it really a static field or is it not (your code says it's not)?
If it is static, you should pass null as argument to cl.get() (you don't need an instance to access static members).
However, I suspect that your field is actually not static, and your passing the wrong instance to cl.get(). The JavaDocs to Field.get() state it would throw an IllegalArgumentException in this case. You need to pass a RenderManager instance to this method. Your code looks like your passing a Map (the entityRenderMap).
And last, is this code inside your RenderManager class? I suspect this, because your accessing a field with this with the same name as the field you want to set. In this case, don't use reflection at all!
Are you certain it is a static field. The javadoc of the get method clearly states:
If the underlying field is a static field, the obj argument is ignored; it may be null.
Otherwise, the underlying field is an instance field. If the specified obj argument is null, the method throws a NullPointerException. If the specified object is not an instance of the class or interface declaring the underlying field, the method throws an IllegalArgumentException.
So with a static field you would not get the IllegalArgumentException since the parameter is ignored. Further, the code you posted shows it is not a static field but a regular field (since it lacks the word static, and its initialized in the constructor).
If you want to access the field of a certain instance A, you should pass that instance A to the Field#get method, and not the A.field as you are trying to do with your cl.get(this.entityRenderMap) call.
You can take a look at this tutorial for some examples
If the field is really static, you should pass null as an argument to cl.get().
If the field is not static, then you must pass the instance of FooClass which you want to get the field value from:
FooClass fc = new FooClass(); // or whatever, provided that fc is a FooClass instance
Object foo = cl.get(fc);
I'm assuming cl is a java.lang.reflect.Field. The documentation states that Fields' get-method will throw:
IllegalArgumentException - if the specified object is not an instance
of the class or interface declaring the underlying field (or a
subclass or implementor thereof).
You should be passing the RenderManager-object to the get-method instead of the field (unless it's static, which it is not according to your example).
vim Test.java
import java.util.*;
import com.dp4j.*;
class FooClass{
private static Map entityRenderMap;
FooClass(){
entityRenderMap = new HashMap();
}
}
public class Test{
#Reflect
public static void main(String... args){
Map reflectEntityMap = FooClass.entityRenderMap;
}
}
javac -cp ~/ws/dp4j/dp4j.jar -Averbose=true Test.java
Test.java:16: Note:
import java.util.*;
import com.dp4j.*;
class FooClass {
private static Map entityRenderMap;
FooClass() {
entityRenderMap = new HashMap();
}
}
public class Test {
public Test() {
super();
}
#Reflect()
public static void main(String... args) throws java.lang.ClassNotFoundException, java.lang.NoSuchFieldException, java.lang.IllegalArgumentException, java.lang.IllegalAccessException {
java.lang.reflect.Field entityRenderMapField = null;
entityRenderMapField = Class.forName("FooClass").getDeclaredField("entityRenderMap");
entityRenderMapField.setAccessible(true);
Map reflectEntityMap;
reflectEntityMap = (.java.util.Map)entityRenderMapField.get("");
}
}

Categories

Resources