Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: an enum in an extending class

I have a class that extends another one. It should have an enum that should have certain values for the extending class, so I have the following:

public class Shepherd extends Dog {

    public enum Color {
        BLACK,
        GREEN,
        INVISIBLE
    }

    // ...

}

This enum should be a part of the extending class, as another class that extends Dog should have its own enum with its own values, that's why I can't make the Color enum a part of the Dog class. For example:

public class Corgi extends Dog {

    public enum Color {
        RED,
        BLACK,
        SABLE
    }

    // ...

}

Also, I have a constructor:

public class Shepherd extends Dog {

    public enum Color {
        // ...
    }

    public Shepherd(Color color) {
        super(color);
    }

    // ...

}

I need the base class (Dog) to have the color field that would be accessible from other methods of the same base class (Dog).

public class Dog {

    public enum Color { } // not sure in that :-(

    private Color color;

    public Dog(Color color) {
        this.color = color;
    }

    public Color getColor() {
        return this.color;
    }

    // ...

}

Obviously, it won't work, as Dog.Color is not the same type as Shepherd.Color. OK, let's do it another way:

public class Shepherd extends Dog<Shepherd> {

    // ...

    public Shepherd(Color color) {
        super(color);
    }

    // ...

}
public class Dog<T extends Dog> {

    public enum Color { } // ???

    private T.Color color;

    public Dog(T.Color color) {
        this.color = color;
    }

    public T.Color getColor() {
        return this.color;
    }

    // ...

}

And I'm still getting incompatible types: Shepherd.Color cannot be converted to Dog.Color. :-( Why doesn't Java accept it? The parameter has type T.Color, which should mean Shepherd.Color or Corgi.Color dependent on the class we use, isn't it?

Would anyone be so kind as to show me the correct way with an example? Thanks in advance!

like image 206
Volodymyr Melnyk Avatar asked Mar 25 '26 10:03

Volodymyr Melnyk


2 Answers

Enums in Java cannot be extended with new elements. If you want two distinct classes to use two very similar Enums, the right approach is to make them both use the same single Enum class (Color).

Your best option for restricting the subset of Colors allowed for each type of Dog is runtime validation using an inherited superclass method - named, say, getValidColors(); and marking color as final so the validation cannot be (easily) bypassed.

public enum Color {
    BLACK, GREEN, INVISIBLE, RED, SABLE
}

public abstract class Dog {
    protected final Color color;
    public Dog(final Color color) {
        if (!this.getValidColors().contains(color)) {
            throw new IllegalArgumentException(color);
        }
        this.color = color;
    }
    public abstract List<Color> getValidColors();
}

public class Shepherd extends Dog {
    public Shepherd(final Color color) {
        super(color);
    }
    @Override
    public List<Color> getValidColors() {
        return Arrays.asList(Color.BLACK, Color.GREEN, Color.INVISIBLE);
    }
}

public class Corgi extends Dog {
    public Corgi(final Color color) {
        super(color);
    }
    @Override
    public List<Color> getValidColors() {
        return Arrays.asList(Color.RED, Color.BLACK, Color.SABLE);
    }
}
like image 90
Alex Walker Avatar answered Mar 27 '26 01:03

Alex Walker


It might not be exacly what you want, but this is a way to solve it, but again it might not be what you want. Because I am using the Color as the generic field instead of the Dog Child itself.

Color interface

public interface IColor<C> {
    C getColor();
}

Dog.class

public class Dog<C extends IColor<? extends Enum<?>>> {

  private C color;

  public Dog(C color) {
      this.color = color;
  }

  public C getColor() {
      return color;
  }
}

Dog child color:

public enum ShepherdColor implements IColor<ShepherdColor> {
  BLACK,
  GREEN,
  INVISIBLE;

  @Override
  public ShepherdColor getColor() {
      return this;
  }
}

Dog Child class

public class Shepherd extends Dog<ShepherdColor> {
  public Shepherd(ShepherdColor color) {
      super(color);
  }
}

Main

public static void main(String[] args) {
  Shepherd s = new Shepherd(ShepherdColor.GREEN);
  Dog<?> d = s;
  System.out.println(s.getColor());
  System.out.println(d.getColor());
}
like image 27
Maxdola Avatar answered Mar 27 '26 01:03

Maxdola



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!