开发者

Make a subclass out of a existing superclass field

开发者 https://www.devze.com 2023-03-15 02:10 出处:网络
I need to create a sub-class of a existing class, which I know how to do, but I need to be able to create the subclass based off a existing super class without modifying the super class.

I need to create a sub-class of a existing class, which I know how to do, but I need to be able to create the subclass based off a existing super class without modifying the super class.

For example:

public class Foo
{
    public Foo(int a)
    {
        _a = a;
    }
    private int _a;
}
public class Bar extends Foo
{
    public Bar(int a, int b)
    {
        super(a);
        _b = b;
    }
    public Bar(Foo foo, int b)
    {
        ???? //<----What do I do here?
        _b = b;
    }
    private int _b;
}
public static class Baz
{
    static void Main(String[] args)
    {
        Foo foo = new Foo(1);
        Bar bar = new Bar(foo, 2); //<---- How do I set this up?
    }
}

So in the above example it would use the existing instance of Foo and turn it in to a Bar and set the _b field to 2.

EDIT

Important constraint, I did not think everyone would tell me to edit Foo. I can not change Foo, that class is in a library I can not edit, so what I want to do needs to be done without editing Foo.

EDIT2

Here is the actual Foo, it is the ChunkProvider class from Minecraft.

public class ChunkProvider
    implements IChunkProvider
{

    public ChunkProvider(World world, IChunkLoader ichunkloader, IChunkProvider ichunkprovider)
    {
        chunkSet = new HashSet();
        chunkMap = new HashMap();
        chunkList = new ArrayList();
        field_28064_b = new EmptyChunk(world, new byte[32768], 0, 0);
        field_28066_g = world;
        field_28069_d开发者_开发技巧 = ichunkloader;
        field_28070_c = ichunkprovider;
    }

    //(Snip) There are no GetXXX members for the below fields.

   private Set chunkSet;
    private Chunk field_28064_b;
    private IChunkProvider field_28070_c;
    private IChunkLoader field_28069_d;
    private Map chunkMap;
    private List chunkList;
    private World field_28066_g;

}


There is a way around this, and it is not to inherit Foo, but to compose it and delegate to its methods.

I noticed that the "real" Foo implements an interface. If you could design your code around that interface and not around the concrete Foo, Bar can be like this:

public class Bar implements IFoo {
  public Bar(IFoo foo, ...) {
    _foo = foo;
  }
  private IFoo _foo;
  // implement IFoo delegating all calls to _foo...
}


If Foo's private variable _a does not have an accessor method and you can't change Foo then there is no way, short of some reflection, to do what you describe. You simple do not have access to Foo._a.


Iterate through Foo.class.getDeclaredFields(), looking for one with the name _a. Call Field.setAccessible(true) on the field, then Field.getValue() will give you the value you need.

I keep this more general code

@SuppressWarnings("unchecked")
public static <T> T getFieldValue(Object target, String name) throws NoSuchFieldException, IllegalAccessException {
    Class<? extends Object> c = target.getClass();
    Field field = findField(c, name);
    if (field == null)
        throw new NoSuchFieldException(name);
    field.setAccessible(true);
    return (T) field.get(target);
}

public static Field findField(Class<? extends Object> clas, String name) {
    if (clas == null)
        return null;
    Field[] declaredFields = clas.getDeclaredFields();
    for (Field field : declaredFields) {
        if (field.getName().equals(name))
            return field;
    }
    return findField(clas.getSuperclass(), name);
}

lying around for just such eventualities.


just call

super(foo.getA()) // assuming you have a getA method

where your question marks are.

you cannot make the new Bar instance be foo. (If you can, I will definitely have learned something today).


Add a Foo constructor that takes a Foo as an argument and makes a copy of _a, then invoke that constructor where you have indicated.

EDIT:

public class Bar extends Foo
{
    public Bar(int a, int b)
    {
        super(a);
        _b = b;
    }
    public Bar(Foo foo, int b)
    {
        super(foo.getA(),b);  <------
        _b = b;
    }
    private int _b;
}


If you have the source to Foo, copy it adding the methods you need to access its fields etc, and then place your copy in the classpath ahead of the original.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号