I'm a little confused about the difference between the getFields method and the getDeclaredFields method when using Java reflection.
I read that getDeclaredFields gives you access to all the fields of the class and that getFields only returns public fields. If this is the case, why wouldn't you just always use getDeclaredFields?
Can someone please elaborate on this, and explain the difference between the two methods, and when/why you would want to use one over the other?
getFields()
All the public fields up the entire class hierarchy.
getDeclaredFields()
All the fields, regardless of their accessibility but only for the current class, not any base classes that the current class might be inheriting from.
To get all the fields up the hierarchy, I have written the following function:
public static Iterable<Field> getFieldsUpTo(#Nonnull Class<?> startClass,
#Nullable Class<?> exclusiveParent) {
List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
Class<?> parentClass = startClass.getSuperclass();
if (parentClass != null &&
(exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
List<Field> parentClassFields =
(List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
currentClassFields.addAll(parentClassFields);
}
return currentClassFields;
}
The exclusiveParent class is provided to prevent the retrieval of fields from Object. It may be null if you DO want the Object fields.
To clarify, Lists.newArrayList comes from Guava.
Update
FYI, the above code is published on GitHub in my LibEx project in ReflectionUtils.
From Java Reflection tutorials:
As already mentioned, Class.getDeclaredField(String) only looks at the fields from the Class in which you call it.
If you want to search a Field in the Class hierarchy, you can use this simple function:
/**
* Returns the first {#link Field} in the hierarchy for the specified name
*/
public static Field getField(Class<?> clazz, String name) {
Field field = null;
while (clazz != null && field == null) {
try {
field = clazz.getDeclaredField(name);
} catch (Exception e) {
}
clazz = clazz.getSuperclass();
}
return field;
}
This is useful to find a private field from a superclass, for example. Also, if you want to modify its value, you can use it like this:
/**
* Sets {#code value} to the first {#link Field} in the {#code object} hierarchy, for the specified name
*/
public static void setField(Object object, String fieldName, Object value) throws Exception {
Field field = getField(object.getClass(), fieldName);
field.setAccessible(true);
field.set(object, value);
}
public Field[] getFields() throws SecurityException
Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if the class or interface has no accessible public fields, or if it represents an array class, a primitive type, or void.
Specifically, if this Class object represents a class, this method returns the public fields of this class and of all its superclasses. If this Class object represents an interface, this method returns the fields of this interface and of all its superinterfaces.
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.
public Field[] getDeclaredFields() throws SecurityException
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if the class or interface declares no fields, or if this Class object represents a primitive type, an array class, or void.
And what if I need all fields from all parent classes?
Some code is needed, e.g. from https://stackoverflow.com/a/35103361/755804:
public static List<Field> getAllModelFields(Class aClass) {
List<Field> fields = new ArrayList<>();
do {
Collections.addAll(fields, aClass.getDeclaredFields());
aClass = aClass.getSuperclass();
} while (aClass != null);
return fields;
}
Related
I'm a little confused about the difference between the getFields method and the getDeclaredFields method when using Java reflection.
I read that getDeclaredFields gives you access to all the fields of the class and that getFields only returns public fields. If this is the case, why wouldn't you just always use getDeclaredFields?
Can someone please elaborate on this, and explain the difference between the two methods, and when/why you would want to use one over the other?
getFields()
All the public fields up the entire class hierarchy.
getDeclaredFields()
All the fields, regardless of their accessibility but only for the current class, not any base classes that the current class might be inheriting from.
To get all the fields up the hierarchy, I have written the following function:
public static Iterable<Field> getFieldsUpTo(#Nonnull Class<?> startClass,
#Nullable Class<?> exclusiveParent) {
List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
Class<?> parentClass = startClass.getSuperclass();
if (parentClass != null &&
(exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
List<Field> parentClassFields =
(List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
currentClassFields.addAll(parentClassFields);
}
return currentClassFields;
}
The exclusiveParent class is provided to prevent the retrieval of fields from Object. It may be null if you DO want the Object fields.
To clarify, Lists.newArrayList comes from Guava.
Update
FYI, the above code is published on GitHub in my LibEx project in ReflectionUtils.
From Java Reflection tutorials:
As already mentioned, Class.getDeclaredField(String) only looks at the fields from the Class in which you call it.
If you want to search a Field in the Class hierarchy, you can use this simple function:
/**
* Returns the first {#link Field} in the hierarchy for the specified name
*/
public static Field getField(Class<?> clazz, String name) {
Field field = null;
while (clazz != null && field == null) {
try {
field = clazz.getDeclaredField(name);
} catch (Exception e) {
}
clazz = clazz.getSuperclass();
}
return field;
}
This is useful to find a private field from a superclass, for example. Also, if you want to modify its value, you can use it like this:
/**
* Sets {#code value} to the first {#link Field} in the {#code object} hierarchy, for the specified name
*/
public static void setField(Object object, String fieldName, Object value) throws Exception {
Field field = getField(object.getClass(), fieldName);
field.setAccessible(true);
field.set(object, value);
}
public Field[] getFields() throws SecurityException
Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if the class or interface has no accessible public fields, or if it represents an array class, a primitive type, or void.
Specifically, if this Class object represents a class, this method returns the public fields of this class and of all its superclasses. If this Class object represents an interface, this method returns the fields of this interface and of all its superinterfaces.
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.
public Field[] getDeclaredFields() throws SecurityException
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if the class or interface declares no fields, or if this Class object represents a primitive type, an array class, or void.
And what if I need all fields from all parent classes?
Some code is needed, e.g. from https://stackoverflow.com/a/35103361/755804:
public static List<Field> getAllModelFields(Class aClass) {
List<Field> fields = new ArrayList<>();
do {
Collections.addAll(fields, aClass.getDeclaredFields());
aClass = aClass.getSuperclass();
} while (aClass != null);
return fields;
}
Suppose i have a class A:
class A
{
private String value;
private B field;
public C otherField;
}
class C
{
private String otherValue;
}
class B
{
private String name;
}
Now, if i do a A.class.getClasses(), ill get an array with one element (the one which is public, something that makes sense based on what javadoc of Class.java says).
My question is: is there a way to get return a list of public + private fields of a class?
Thanks
The getClasses() method is not the correct way to access the Fields that are part of the A class. You need to use the getDeclaredFields() method to access an array of Field objects representing the fields in the class. From there, you'll need to set the accessibility of the field to true with a call to setAccessible(). There is more information available by looking into the Java Reflection API as well as here
You should notice, that getDeclaredField will only return the fields of the class which are declared in the class. Fields which are inherited from a super class will not be returned. To get all fields of a class you have to iterate over the super classes (using Class.getSuperclass()).
To make a immutable class , Effective Java has one last condition.
To make a class immutable, follow these five rules:
5- Ensure exclusive access to any mutable components. If your class has any fields that refer to mutable objects, ensure that clients of the class cannot obtain references to these objects. Never initialize such a field to a client-provided object reference nor return the object reference from an accessor. Make defensive copies (Item 24) in contructors, accessors, and readObject methods
public final class ImmutableClass {
private MutableObject mutableObject;
// If I should not provide getter for this object. Then what is the use of this variable after I have
//initalised in the constructor
}
Can somebody explain me this point?
It's actually reasonably simple.
Basically, it's saying to not...
1- Make available any reference to any mutable object that your object might contain.
So if your Class contained a java.util.List as one of it's fields, there should be no way for any client using your Class to gain a reference directly to the List field, either via public deceleration or getter of some kind.
For example...
public class BadImmutableExample {
public List<String> myStrings; // This can not be referenced by the client
/*...*/
}
Would be bad, because the field myStrings is accessible to any body to make modifications to...
In the case you had to return the values in the List you would either be required to return a copy of the List (not a reference to it) or return an array of the values, for example.
For example...
public class BadImmutableExample {
private List<String> myStrings; // This can not be referenced by the client
/*...*/
public List<String> getMyStrings() {
return myStrings;
}
}
Would expose the List myStrings to any clients, which would allow them to modify it.
In this case, you could also use Collections.unmodifiableList(myStrings) to make the list unmodifiable, or return new ArrayList<String>(myStrings) or return an array of String instead...
2- Never initialise such a field to a client provided object...
Basically this means that if your Class requires the client to seed it with some kind of value or values, you should never maintain a reference directly them, instead, again, make a copy for you own reference...
For example...
public class BadImmutableExample {
private List<String> myStrings; // This can not be referenced by the client
public ImmutableExample(List<String> clientStrings) {
myStrings = clientStrings;
}
}
Would break this rule, as any changes to clientStrings would be immediately reflected within you class.
Instead, you could do something like...
public class BetterImmutableExample {
private List<String> myStrings; // This can not be referenced by the client
public ImmutableExample(List<String> clientStrings) {
myStrings = new ArrayList<String>(clientStrings);
}
}
Instead, which will make a copy of the client supplied list, but which will no longer reflect changes made to it (the client supplied list)
I'm having trouble grabbing the fields in a class using reflection in Java:
public class CraftLib
{
static List alloyRecipes = new ArrayList();
public static HashSet damageOnCraft = new HashSet();
public static HashMap damageContainer = new HashMap();
public static void addAlloyResult(ur output, Object[] input)
{
alloyRecipes.add(Arrays.asList(new Object[] { input, output }));
}
//file continues
I try to grab the fields like this:
try {
Field[] fields = Class.forName("class.path").getFields();
for(Field f : fields) {
System.out.println(f.getName());
} catch (ClassNotFoundException e) {
System.out.println("Damn.");
}
System.out.println(fields.length);
For some reason it is only able to grab the damageOnCraft and damageContainer fields, but the one I really need, alloyRecipes, is not grabbed. I can not edit the first file, so what would be the best way to get and edit that field?
getFields() won't give you private, package-protected or protected fields if they are inaccessible.
(getFields()) Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object
And apparently your package-protected alloyRecipes are not accessible in your case.
You need getDeclaredFields()
(getDeclaredFields()) Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
Put your class in the same package as the other one then it will be able to read package protected fields.
I am trying to get a list of objects from the Database based on a target object through reflection.
I don't have much experience with reflection so this doesn't work.
Is it even possible to achieve my goal?
public static List<Object> getObjectsFromDataBase(Object targetObj) {
....................
ResultSet rs = stat.executeQuery(queryToExecute);
while (rs.next()) {
Object obj = new Object();
for (Field property : targetObj.getClass().getFields()) {
property.set(obj, rs.getString(property.getName()));
}
objListToReturn.add(obj);
}
.....................
return objListToReturn;
}
If the fields in the target object's class are not public they won't show up in getFields(). Try this:
import java.lang.reflect.Field;
public class Test
{
public static class A
{
public String field1;
public String field2;
}
public static void main(String[] args) throws Exception
{
A a = new A();
Object b = a;
for (Field f : b.getClass().getFields())
{
System.out.println(f.getName());
}
}
}
If you remove public, getFields() returns an empty array.
The short answer is yes, this is possible, but not with the code you provided. This concept is called Object Relational Mapping and things like Hibernate or XStream do this for you. If you're just learning about reflection that's great too. You'll probably need a way to map the fields to the properties of the object, whether that's done with convention (matched names), straight code, annotations, or a mapping input file is up to you.
I can see two problems:
You are creating obj as type Object. the first argument of Field.set() needs to be the same type (or a subtype) as the class the containing the field. You need to use reflection to create an object of the same type as targetObj, by using obj = targetObj.getClass().newInstance() (assuming a default constructor is available)
Also your problem might be that the getFields() method only returns the public fields of the class.
targetObj.getClass().getFields()
If you want to get all the fields of the class, you will need to use the getDeclaredFields() method.