Java: Extending inner classes
Asked Answered
B

3

12

I am trying to understand extending inner classes in Java. I have read around but nothing I found quite answers my question. So here goes...

I have...

public class Pie{
    protected Slice[] slices;

    // Pie constructor
    public Pie(int n){
         sliceGenerator(n)
    }

    private void sliceGenerator(int n){
         slices = new Slice[n];
         final float sweepAngle = 360.0f/(float)n;
         float startAngle = 0;
         for (int i=0;i<n;i++){ 
             slices[i] = new Slice(startAngle);
             startAngle += sweepAngle;
         }
    }

    @Override
    public String toString(){
         for (Slice s:slices){  
             s.toString();
         }
    }

    // Inner class...
    public class Slice{
        public Slice(float startAngle){
             //set some private fields based on startAngle and generic pie 
        }

        @Override
        public String toString(){
             return **string based on private fields**
        }
    }
}

Then I extend this...

public class ApplePie extends Pie{
    protected Slice[] slices;

    // Apple Pie constructor
    public ApplePie(int n){
         super(n);
    }

    // Inner class...
    public class Slice extends Pie.Slice{
        public Slice(float startAngle){
            super(startAngle);
            //set some **additional** private fields based on startAngle **specific to apple pie** appleness or something
        }

        @Override
        public String toString(){
             return **string based on apple pie specific private fields**
        }
    }
}

Now, when I make an Apple pie and call its toString method, like so...

ApplePie ap = new ApplePie(8);
System.out.println(ap.toString());

I do not get information about the apple pie slices, but information about the pie slices. It ignores my toString override, or more likely ignores my apple pie Slice. How can I arrange it such that apple pie slices refer to ApplePie?

Any help much appreciated! Sorry for pie references - it is the actual class I am working with...

Bussey answered 26/1, 2013 at 6:15 Comment(2)
@VisionarySoftwareSolutions Citation please.Fallible
mindprod.com/jgloss/nestedclasses.html #2284896 c2.com/ppr/wiki/JavaIdioms/NoPublicInnerClasses.htmlDiscontinuance
D
7

I've changed your code to meet your requirements.

Your super class Pie is about to create a new instance of Slice, but the child class ApplePie's Slice does not override the Slice method of its super class'.

I added the functions below to enable the child class to create its own Slice.

protected void newSliceArray(int n) {
    slices = new Slice[n];
}

protected Slice newSlice(float startAngle) {
    return new Slice(startAngle);
}

Pie.java:

public class Pie {
  private int a = 1;
  protected Slice[] slices;

  // Pie constructor
  public Pie(int n) {
    sliceGenerator(n);
  }

  private void sliceGenerator(int n) {
    newSliceArray(n);
    final float sweepAngle = 360.0f / n;
    float startAngle = 0;
    for (int i = 0; i < n; i++) {
      slices[i] = newSlice(startAngle);
      startAngle += sweepAngle;
    }
  }

  protected void newSliceArray(int n) {
    slices = new Slice[n];
  }


  protected Slice newSlice(float startAngle) {
    return new Slice(startAngle);
  }

  @Override
  public String toString() {
    String t = "";
    for (Slice s : slices) {
      t += s.toString();
    }
    return t;
  }

  // Inner class...
  public class Slice {
    public Slice(float startAngle) {
      // set some private fields based on startAngle and generic pie
    }

    @Override
    public String toString() {
      return "" + a;
    }
  }
}

ApplePie.java:

public class ApplePie extends Pie {
  private int b = 2;

  // protected Slice[] slices;

  // Apple Pie constructor
  public ApplePie(int n) {
    super(n);
  }

  protected void newSliceArray(int n) {
    slices = new Slice[n];
  }

  protected Slice newSlice(float startAngle) {
    return new Slice(startAngle);
  }

  // Inner class...
  public class Slice extends Pie.Slice {
    public Slice(float startAngle) {
      super(startAngle);
      // set some **additional** private fields based on startAngle **specific to apple pie**
      // appleness or something
    }

    @Override
    public String toString() {
      return b + "";
    }
  }
}

Test:

public static void main(String[] args) {
    ApplePie ap = new ApplePie(8);
    System.out.println(ap.toString());
}

The code will print 22222222

Dose answered 26/1, 2013 at 6:36 Comment(2)
Hey, thanks. I just saw this answer but already replied to one below. This does the same thing(ish) as I ended up doing, but yours is neater methinks!Bussey
Is it possible to extend the inner class without creating a new outer class?Timeous
F
4

In your superclass, you are creating and storing Pie.Slice objects:

private void sliceGenerator(int n){
     slices = new Slice[n];
     final float sweepAngle = 360.0f/(float)n;
     float startAngle = 0;
     for (int i=0;i<n;i++){ 
         slices[i] = new Slice(startAngle);
         startAngle += sweepAngle;
     }
}

These are the same objects being used by Pie.toString (which ApplePie doesn't override by the way).

Extending Pie with ApplePie and extending Pie.Slice with ApplePie.Slice doesn't change this. The new Slice(startAngle) in the above code does not magically switch to instantiating something different.

Aside from that, your Pie.toString() isn't returning anything - it shouldn't even compile:

@Override
public String toString(){
     for (Slice s:slices){  
         s.toString();
     }
}

I'm guessing you want to return a String representing all the slices. This would be a quick solution for example:

@Override
public String toString() {
     return Arrays.toString(slices);
}

(Arrays.toString is just a utility method to get a String representing of an array.)

Fallible answered 26/1, 2013 at 6:30 Comment(1)
Thanks paul. Your point re. the 'generateSlices' method creates 'Pie.Slice', not 'ApplePie.Slice' seemed to be the crux of it. I fixed it by cutting and pasting this method unchanged into my ApplePie class. Seems to work - now my calling toString on ApplePie calls ApplePie.Slice toString, not Pie.toString. Magic! Thanks for heads up on the toString bit...not the actual methods or code I am using, was trying to keep it simple. My bad for being lazy.Bussey
D
1

The answer lies within your program. When you instantiate Slice class, it gives call to the super class and invokes sliceGenerator. This method internally creates instances of Pie.Slice and not ApplePie.Slice. To get around this, make sliceGenerator method protected and override it in Apple.Slice class. Create the instances of Apple.Slice and it should work.

Denaedenarius answered 26/1, 2013 at 6:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.