A Question Asker
A Question Asker

Reputation: 3311

How to override/extend an inner class from a subclass?

I want to change how a method of a class executes without overriding the method, and only overriding (or ideally extending) the inner class. Assume that I cannot change the fact that I need to do this (I am modifying an existing open source code base and there would be friction to pulling out classes or whatnot).

public class A {
  static class Thing {
    public int value() { return 10+value2(); }
    public int value2() { return 10; }
  }

  public String toString() {
    Thing t = new Thing();
    return Integer.toString(t.value());
  }
}

public class B extends A {
  static class Thing {
    public int value2() { return 20; }
  }
}

My goal is, by changing only Thing, getting B's toString() to return "30", where currently it will return "20". The ideal would be to change only the method value2 (thus leaving any other methods unchanged), but I don't know if this is possible.

Thanks

Upvotes: 41

Views: 42861

Answers (3)

Nathaniel Flath
Nathaniel Flath

Reputation: 16015

It's not possible by only changing value2. The problem is that 'new' calls aren't dispatched dynamically - the 'new' in toString will always create A::Thing. You could fix this creating a factory : something like this:

public class A {
  static class Thing {
    public int value() { return 10+value2(); }
    public int value2() { return 10; }
  }

  private Thing makeThing() { return new Thing(); }


  public String toString() {
    Thing t = new Thing();
    return Integer.toString(t.value());
  }
}

public class B extends A {
  static class Thing extends A.Thing {
    public int value2() { return 20; }
  }

  private Thing makeThing() { return new Thing(); }

}

Upvotes: 2

dacwe
dacwe

Reputation: 43504

I think you need a factory method for this. Consider the following example (derived from your snippet):

static class A {
    static class Thing {
        public int value() {
            return 10 + value2();
        }
        public int value2() {
            return 10;
        }
    }
    protected Thing createThing() {
        return new Thing();
    }
    public String toString() {
        return Integer.toString(createThing().value());
    }
}

static class B extends A {
    static class Thing extends A.Thing {
        public int value2() {
            return 20; 
        }
    }
    @Override
    protected Thing createThing() {
        return new Thing(); // creates B.Thing
    }
}

public static void main(String[] args) {
    System.out.println(new B());
}

Output:

30

Upvotes: 48

Vala
Vala

Reputation: 5674

You should be able to just extend the inner class with Thing extends A.Thing. As long as it's visible in your scope it shouldn't be a problem.

Upvotes: 4

Related Questions