简体   繁体   中英

How can I instantiate a member class through reflection on Android

I have a saving/loading framework that is supposed to save arbitrary object graphs. This includes instances of non-static nested classes.

Nested classes require are owned by the instance of their parent class that created them, and the nested class knows what instance it belongs to using a synthetic field.

As a simple example, I present this class:

public class Foo implements Savable {
  private class Bar implements Savable {
    public void saveState(Saver saver) {
      saver.putInt(3);
    }
  }
  private Bar myBar = new Bar();
  public void saveState(Saver saver) {
    saver.putSavable(myBar);
  }
}

On the "standard" compiler, the following code works just fine to take in an object ( myBar ), find its parent (a particular instance of Foo ), and keep a reference of it with the child:

if (objectClass.isMemberClass()) {
  //We are a member class, which means we are a non-static inner class, and therefore must save our parent.
  Field[] fields = objectClass.getDeclaredFields();
  //We loop through each of our fields to find the synthetic field created by the compiler that points to our parent.
  for (Field f : fields) {
    String name = f.getName();
    //The synthetic field pointing to the parent is named something like "this$0".  At least, with the "standard" compiler it is.
    if (name.startsWith("this$")) {
      f.setAccessible(true);
      Savable parent = (Savable)f.get(objectClass);
      saver.putSavable("_parent", parent);
      break;
    }
  }
  if (!saver.containsKey("_parent")) {
    throw new RuntimeException("Could not find the owner of inner class: " + objectClass);
  }
}

So, like I said, this works just fine in on the "standard" compiler. Then at load time, something similar happens, except I look for a constructor that takes in an instance of the parent class and instantiate it, passing in the parent.

But!

It doesn't work on the Android VM. There are no synthetic fields, and the constructors all look normal, like they don't take in a parent instance.

Am I SOL here? This VM obviously does not like my approach. Is there anything I can do here without requiring inner classes to know that they need to save a reference to their parent class instance?

Okay, turns out I was barking up the wrong tree. The method I've outlined works perfectly well on Android just as well as anywhere else. The problem was that the class I was trying to instantiate in this case was a static internal class. So, while it was a member class, it didn't have a reference to its outer class. I just have to check if (!Modifier.isStatic(objectClass.getModifiers())) before looking for a synthetic constructor/field.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM