Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Acquiring reference to private final field in abstract class

I have a reference to object A, which is abstract. This object is also an instance of objects B, C, or D at any time.

Regardless of the extending class, I need a reference to a private final field of a certain type within A.

I do not know the name of the field, only its type, which is unique to all other fields in the abstract class. I cannot change the code of any of the four listed classes. Using getDeclaredFields() returns the fields within whatever extending class I have at the time.

How can I get a reference to this field?

like image 703
WildBamaBoy Avatar asked Nov 21 '25 10:11

WildBamaBoy


2 Answers

You need to call getDeclaredFields() on class A itself and then use reflection to set the field accessible thusly

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Test{

  public static void main(String args[]){
    B someB = new B();
    B otherB = new B();

    Field uniqueField = null;

    for(Field f : A.class.getDeclaredFields()){
      if(!Modifier.isFinal(f.getModifiers()))
        continue;
      if(!UNIQUE.class.isAssignableFrom(f.getType()))
        continue;

      uniqueField = f;
      break;
    }
    if(null == uniqueField)
      throw new NullPointerException();

    uniqueField.setAccessible(true);

    try{
      System.out.println(uniqueField.get(someB) != uniqueField.get(otherB));
    }catch(IllegalArgumentException | IllegalAccessException e){
      throw new RuntimeException(e);
    }
  }

}

class UNIQUE{
}

class A{
  private final UNIQUE u;
  private final String someOtherMember = "";

  A(){
    u = new UNIQUE();
  }

}

class B extends A{

}

if you don't have a direct reference to class A or if there is more than one superclass that has this unique field then you can loop over each one (making sure to check at each stop that you didn't climb all the way to object) by doing something more like this in the example above

  Class<?> clazz = someB.getClass();
  classClimb: do{
    for(Field f : clazz.getDeclaredFields()){
      if(!Modifier.isFinal(f.getModifiers()))
        continue;
      if(!UNIQUE.class.isAssignableFrom(f.getType()))
        continue;

      uniqueField = f;
      break classClimb;
    }
  }while(Object.class != (clazz = clazz.getSuperclass()));
  if(null == uniqueField)
    throw new NullPointerException();

  uniqueField.setAccessible(true);

  try{
    System.out.println(uniqueField.get(someB) != uniqueField.get(otherB));
  }catch(IllegalArgumentException | IllegalAccessException e){
    throw new RuntimeException(e);
  }

Remember that in that case you'll have to either do the reflection on every single object, do some caching, or have multiple reflection sites that are specific to each expected superclass.

like image 121
electroCutie Avatar answered Nov 22 '25 22:11

electroCutie


If you don't have direct to class it self then you can do something as follows -

Field[] fields = obj.getClass().getSuperclass().getDeclaredFields();
for(Field field : fields) {
    if(field.getType() == String.class) { //assume the type is String

    }
}

But if you have access to the class then it would be

Field[] fields = B.class.getSuperclass().getDeclaredFields();

Or even

Field[] fields = A.class.getDeclaredFields();
like image 32
Bhesh Gurung Avatar answered Nov 22 '25 23:11

Bhesh Gurung



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!