Arbitrary Java enum argument - java

I'm fairly new to java, and am used to enums essentially beeing nothing more than a named list of integers.
Now I'm writing an implementation where a parent class has a couple of methods that take an enum value as argument. The enum will be defined in child classes, and will differ slightly. Since enums basically seem to behave like classes, this doesn't work the way I expected it to. Each enum defined will be considered a different type of object and the parent class will have to pick one of the defined enums to take as argument.
Is there a good way to make the parent class accept any enum defined in it's child-classes? Or will I have to write a custom class for this?
Edit: Here is my example, fixed as per Jon Skeets answer, for anyone who is looking into how to do this later on:
class Parent {
protected interface ParentEvent {}
private HashMap<ParentEvent, String> actions = new HashMap<ParentEvent, String>();
protected void doStuff(ParentEvent e){
if(actions.containsKey(e)){
System.out.println(actions.get(e));
}
}
}
class Child extends Parent {
enum Event implements ParentEvent {EDITED, ADDED, REMOVED}
public void trigger(){
doStuff(Event.REMOVED);
}
}

You could make your enums implement an interface, then give your parent class method a parameter of that interface type.
As you say, enums are rather different in Java. They're not named numbers - they're a fixed set of values, but those values are object-oriented (i.e. they can use polymorphism etc). Java enums pretty much rock, except for a few tricksy issues around initialization ordering.

if i understand you correctly, you want to have a common base class for your enum and want to define several unrelated sets of enums for the sub classes. This is not possible with java's typesafe enums, because they don't allow you to define a base class.
Of course it is not an option just to have one enum defined and always extend its values because this clearly violates the open close principle.
For such a use case I have fairly good experience with Josh Bloch's Typesafe Enum Pattern he describes in Effective Java
Just introduce your super class here and make distinct sub classes for each of enum values your client classes need.

I'm not sure, but maybe this is what you want:
public abstract class EnumTest<E extends Enum<E>> {
public abstract void frobnicate(E value);
}
public class Derived extends EnumTest<Derived.DerivedEnum> {
public void frobnicate(DerivedEnum value) {
System.out.println(value);
}
public static enum DerivedEnum {
FOO, BAR,
}
}

You could define the enums in their own file if they're applicable to different classes. They don't need to be nested within a class.
You can't extend one set of enums from another though.
It took me a while to get out of the mindset of an enum 'just being an integer'.

Related

Why does Java not allow multiple inheritance but does allow conforming to multiple interfaces with default implementations

I am not asking this -> Why is there no multiple inheritance in Java, but implementing multiple interfaces is allowed?
In Java, multiple inheritance isn't allowed, but, after Java 8, Interfaces can have default methods (can implement methods itself), just like abstract classes. Within this context, it multiple inheritance should also be allowed.
interface TestInterface
{
// abstract method
public void square(int a);
// default method
default void show()
{
System.out.println("Default Method Executed");
}
}
Things are not so simple.
If a class implements multiple interfaces that defines default methods with the same signature the compiler will force you to override this method for the class.
For example with these two interfaces :
public interface Foo {
default void doThat() {
// ...
}
}
public interface Bar {
default void doThat() {
// ...
}
}
It will not compile :
public class FooBar implements Foo, Bar{
}
You should define/override the method to remove the ambiguity.
You could for example delegate to the Bar implementation such as :
public class FooBar implements Foo, Bar{
#Override
public void doThat() {
Bar.super.doThat();
}
}
or delegate to the Foo implementation such as : :
public class FooBar implements Foo, Bar {
#Override
public void doThat() {
Foo.super.doThat();
}
}
or still define another behavior :
public class FooBar implements Foo, Bar {
#Override
public void doThat() {
// ...
}
}
That constraint shows that Java doesn't allow multiple inheritancy even for interface default methods.
I think that we cannot apply the same logic for multiple inheritances because multiples issues could occur which the main are :
overriding/removing the ambiguity for a method in both inherited classes could introduce side effects and change the overall behavior of the inherited classes if they rely on this method internally. With default interfaces this risk is also around but it should be much less rare since default methods are not designed to introduce complex processings such as multiple internal invocations inside the class or to be stateful (indeed interfaces cannot host instance field).
how to inherit multiple fields ? And even if the language allowed it you would have exactly the same issue as this previously quoted : side effect in the behavior of the inherited class : a int foo field defined in a A and B class that you want to subclass doesn't have the same meaning and intention.
The language designers already thought about that, so these things are enforced by the compiler. So if you define:
interface First {
default void go() {
}
}
interface Second {
default void go() {
}
}
And you implement a class for both interfaces:
static class Impl implements First, Second {
}
you will get a compilation error; and you would need to override go to not create the ambiguity around it.
But you could be thinking that you can trick the compiler here, by doing:
interface First {
public default void go() {
}
}
static abstract class Second {
abstract void go();
}
static class Impl extends Second implements First {
}
You could think that First::go already provides an implementation for Second::go and it should be fine. This is too taken care of, thus this does not compile either.
JLS 9.4.1.3 : Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).
The last point I would bring in, to solidify that multiple inheritance is not allowed even with new additions in java, is that static methods from interfaces are not inherited. static methods are inherited by default:
static class Bug {
static void printIt() {
System.out.println("Bug...");
}
}
static class Spectre extends Bug {
static void test() {
printIt(); // this will work just fine
}
}
But if we change that for an interface (and you can implement multiple interfaces, unlike classes):
interface Bug {
static void printIt() {
System.out.println("Bug...");
}
}
static class Spectre implements Bug {
static void test() {
printIt(); // this will not compile
}
}
Now, this is prohibited by the compiler and JLS too:
JLS 8.4.8 : A class does not inherit static methods from its superinterfaces.
Java doesn't allow multiple inheritance for fields. This would be difficult to support in the JVM as you can only have references to the start of an object where the header is, not arbitrary memory locations.
In Oracle/Openjdk, objects have a header followed by the fields of the most super class, then the next most super class, etc. It would be a significant change to allow the fields of a class to appear at different offsets relative to the header of an object for different subclasses. Most likely object references would have to become a reference to the object header and a reference to the fields to support this.
default methods in interfaces pose a problem that :
If both of the implemented interfaces define a default method with
same method signature, then the implementation class does not know
which default method to use.
The implementation class should define explicitly specify which default method to use or define it's own one.
Thus default methods in Java-8 do not facilitate multiple inheritance. The main motivation behind default methods is that if at some point we need to add a method to an existing interface, we can add a method without changing the existing implementation classes. In this way, the interface is still compatible with older versions. However, we should remember the motivation of using Default Methods and should keep the separation of interface and implementation.
The main issues with multiple inheritance are ordering (for overriding and calls to super), fields and constructors; interfaces don't have fields or constructors, so they don't cause problems.
If you look at other languages they usually fall in two broad categories:
Languages with multiple inheritance plus a few features to disambiguate special cases: virtual inheritance [C++], direct calls to all superconstructors in the most-derived class [C++], linearization of superclasses [Python], complex rules for super [Python], etc.
Languages with a differente concept, usually called interfaces, traits, mixins, modules, etc. that impose some limitations such as: no constructors [Java] or no constructors with parameters [Scala until very recently], no mutable fields [Java], specific rules for overriding (e.g. mixins take precedence over base classes [Ruby] so you can include them when you need a bunch of utility methods), etc. Java has become a language like these.
Why just by disallowing fields and constructors you solve many issues related to multiple inheritance?
You can't have duplicated fields in duplicated base classes.
The main class hierarchy is still linear.
You can't construct your base objects the wrong way.
Imagine if Object had public/protected fields and all subclasses had constructors setting those fields. When you inherit from more than one class (all of them derived from Object), which one gets to set the fields? The last class? They become siblings in the hierarchy, so they know nothing about each other. Should you have multiple copies of Object to avoid this? Would all classes interoperate correctly?
Remember that fields in Java are not virtual (overridable), they are simply data storage.
You could make a language where fields behave like methods and could be overridden (the actual storage would be always private), but that would be a much bigger change and problably wouldn't be called Java anymore.
Interfaces can't be instantiated by themselves.
You should always combine them with a concrete class. That eliminates the need for constructors and makes the programmer's intent clearer too (that is, what is meant to be a concrete class and what's an accessory interface/mixin). This also provides a well-defined place to solve all ambiguities: the concrete class.
That is mostly related to "diamonds problem" i think. Right now if you implement multiple interfaces with the same method, compiler forces you to override method the one you want to implement, because it don't know which on to use. I guess Java creators wanted to remove this problem back when interfaces couldn't use default methods. Now they came up with idea, that is good to be able to have methods with implementation in interfaces, as you can still use those as functional interfaces in streams / lambda expressions and utilize their default methods in processing. You cannot do that with classes but diamond problem still exist there. That is my guess :)
class A{
void m1(){
System.out.println("m1-A");
}
}
class B{
void m1(){
System.out.println("m1-B");
}
}
class C extends A, B{ // this will give an error
// inheritance means making all variables and/or methods available to the child class, here child class will get confused as which m1() method to inherit, hence an error
}
JAVA DOES SUPPORT MULTIPLE INHERITANCE.
If you make a OVERALL COMPARISON OF THE PROGRAMMING LANGUAGE,JAVA,THEN YOU COME TO KNOW THAT I AM TRUE.
Java's topclass or the root class in the Ancestor Hierarchy is the Object class.
This class is a Superclass of all other classes. Hence, each class in Java that we declare or is predefined in the API itself inherits this Object class.
Moreover, Java provides us to inherit one more class of our choice.
Hence, we can say that we are performing INTERLOCKED BUT MULTIPLE INHERITANCE.
2ND Way
Java supports Multiple Inheritance of Interfaces. So you can use as many interface implementations you want. But note, implementing an interface does not define IS A relationship as in case of Inheritance of Classes is possible.

How can I restrict arguments of methods in abstract classes for subclasses that use them?

I've been trying to design a set of classes to model a classic RPG. I've found myself confused on how to solve this one issue, however: how do I force the use of character-type (e.g. Tank, Healer, DPS) specific spells/equipment, etc. in an abstract class. The example below better articulates what I mean.
I've got an abstract PlayableCharacter class which all character-types inherit from:
public abstract class PlayableCharacter {
private Set<Spell> mSpells;
...
public void addSpell(Spell spell) {
mSpells.add(spell);
}
}
For example:
public class Healer extends PlayableCharacter { ... }
public class Tank extends PlayableCharacter { ... }
Note the Set of Spell in the abstract class. I would like it if each subclass of PlayableCharacter could use its addSpell method but with the restriction that the type of Spell correspond to the PlayableCharacter subtype.
For example I have these Spell classes:
public abstract class Spell { ... }
public class HealerSpell extends Spell { ... }
public class TankSpell extends Spell { ... }
I only want Healers to use HealerSpells and Tanks to use TankSpells, etc. For example:
PlayableCharacter tank = new Tank();
tank.addSpell(new TankSpell()); // This is fine
tank.addSpell(new HealerSpell()); // I want to prevent this!
I thought of giving each subclass of PlayableCharacter it's own Set of subclass-specific Spells, but that creates a lot of code duplication.
I also tried making PlayableCharacter.addSpell marked as protected, then each subclass would have to implement an interface like this:
public interface Spellable<T extends Spell> { void addClassSpell(T spell); }
and each subclass that implements it would call super.addSpell(spell); but that lead to more code duplication and nothing was forcing those implementations to do the super call.
Is my strategy fundamentally flawed in some way? Any advice? I feel like this issue will keep getting worse as I add more character-type-specific equipment, traits, and so on.
I wouldn't do it that way (via type inheritance). It would be better to add characteristics to a Spell itself because it's a spell, which can be cast by a certain character only. Also, a specific spell can be cast to a certain character type only. These rules belong to a spell, not to a character.
Spell rules can be checked in a runtime by a separate class or by a Spell class itself inside a cast() method or another one.
so far what you have is good
the rest of the stuff, think more strategy pattern than super call
so abstract class can have algorithm that does step1, step2, step3 with possible parent implementation
child classes can override it, but only override parts that is different
when you call algorithm, it performs all steps
Steps themselves could be different class that has logic, if everything becomes too big
maybe have each subclass of playable character store the class (or classes) of subspells that are allowed. then do an if(spell instance of allowedSpell) ...

Interface method referencing a concrete class as parameter causes coupling?

I was thinking about programming to interfaces and not to concrete classes, but I had a doubt: should any interface method be able to hold references to concrete classes?
Suppose the following scenarios:
1)
public interface AbsType1 {
public boolean method1(int a); // it's ok, only primitive types here
}
2)
public interface AbsType2 {
public boolean method2(MyClass a); // I think I have some coupling here
}
Should I choose a different design here in order to avoid the latter? e.g.
public interface MyInterface {} // yes, this is empty
public classe MyClass implements MyInterface {
// basically identical to the previous "MyClass"
}
public interface AbsType2 {
public boolean method2(MyInterface a); // this is better (as long as the
// interface is really stable)
}
But there's still something that doesn't convince me... I feel uncomfortable with declaring an empty interface, though I saw someone else doing so.
Maybe and Abstract Class would work better here?
I am a little bit confused.
EDIT:
Ok, I'll try to be more specific by making an example. Let's say I'm desining a ShopCart and I want of course to add items to the cart:
public interface ShopCart {
public void addArticle(Article a);
}
Now, if Article were a concrete class, what if its implementation changes over time? This is why I could think of making it an Interface, but then again, it's probably not suitable at least at a semantic level because interfaces should specify behaviours and an Article has none (or almost none... I guess it's a sort of entity class).
So, probably I'm ending up right now to the conclusion that making Article an abstract class in this case would be the best thing... what do you think about it?
I would use interfaces because composition is much better than inheritance. "Should any interface method be able to hold references to concrete classes ?", why it shouldn't? Some classes within package are coupled, it's a fact and common use technique. When you marked this relation in interface then you see on which classes is dependent your implementation. Dependency or composition relations are not inheritance so a i would avoid abstract class.
In my opinion Interfaces are fine for all types where the implementation may vary. But if you define a module which introduces a new type, that isn't intended to have alternative implementations then there is no need to define it as an Interface in the first place. Often this would be over-design in my opinion. It depends on the problem domain and often on the way how support testing or AOP-weaving.
For example consider a 2D problem domain where you need to model a Location as a type. If it is clear that a Location is always represented by a x and y coordinate, you may provide it as a Class. But if you do not know which properties a Location could have (GPS data, x, y, z coordinates, etc.) but you rely on some behavior like distance(), you should model it as an Interface instead.
If there are no public methods which AbsType would access in MyClass then the empty interface is probably not a good way to go.
There is no interface declaration (contract) for static methods, which otherwise might make sense here.
So, if AbsType is not going to use any methods from MyClass/MyInterface, then I assume it's basically only storing the class object for some other purpose. In this case, consider using generics to make clear how you want AbsType to be used without coupling closely to the client's code, like
public class AbsType3<C extends Class<?>> {
public boolean method3(T classType) {...}
}
Then you can restrict the types of classes to allow if needed by exchanging the <C extends Class<?>> type parameter for something else which may also be an interface, like
<C extends Class<Collection<?>>>.
Empty interfaces are somewhat like boolean flags for classes: Either a class implements the interface (true) or it doesn't (false). If at all, these marker interfaces should be used to convey an significant statement about how a class is meant to be (or not to be) used, see Serializable for example.

Why can't a class extend an enum?

I am wondering why in the Java language a class cannot extend an enum.
I'm not talking about an enum extending an enum (which can't be done, since java doesn't have multiple inheritance, and that enums implicitly extend java.lang.Enum), but a class that extends an enum in order to only add extra methods, not extra enumeration values.
Something like:
enum MyEnum
{
ASD(5),
QWE(3),
ZXC(7);
private int number;
private asd(int number)
{
this.number=number;
}
public int myMethod()
{
return this.number;
}
}
class MyClass extends MyEnum
{
public int anotherMethod()
{
return this.myMethod()+1;
}
}
To be used like this:
System.out.println(MyClass.ASD.anotherMethod());
So, can anyone provide a rationale (or point me to the right JLS section) for this limitation?
You can't extend an enum. They are implicitly final. From JLS § 8.9:
An enum type is implicitly final unless it contains at least one enum constant that has a class body.
Also, from JLS §8.1.4 - Superclasses and Subclasses:
It is a compile-time error if the ClassType names the class Enum or any invocation of it.
Basically an enum is an enumerated set of pre-defined constants. Due to this, the language allows you to use enums in switch-cases. By allowing to extend them, wouldn't make them eligible type for switch-cases, for example. Apart from that, an instance of the class or other enum extending the enum would be then also be an instance of the enum you extend. That breaks the purpose of enums basically.
In ancient days of pre Java 1.5 you would probably do enums like this:
public class MyEnum {
public static final MyEnum ASD = new MyEnum(5);
public static final MyEnum QWE = new MyEnum(3);
public static final MyEnum ZXC = new MyEnum(7);
private int number;
private MyEnum(int number) {
this.number = number;
}
public int myMethod() {
return this.number;
}
}
There are two important things about this figure:
private constructor that will not allow to instantiate the class from outside
actual "enum" values are stored in static fields
Even if it's not final when you'll extend it, you'll realize that compiler requires an explicit constructor, that in other turn is required to call super constructor which is impossible since that one is private. Another problem is that the static fields in super class still store object of that super class not your extending one. I think that this could be an explanation.
The whole point of an enum is to create a closed set of possible values. This makes it easier to reason about what a value of that enum type is -- easier for you the programmer, and also easier for the compiler (this closedness is what lets it handle enums efficiently in switches, for instance). Allowing a class to extend an enum would open up the set of possible values; at that point, what does the enum buy you that a regular class wouldn't?
I think an answer to why they did it this way comes from this question:
In your example, how would you instantiate a MyClass? Enums are never explicitly instantiated (via a new MyEnum()) by the user. You'd have to do something like MyClass.ASD but not sure how that would work.
Basically, I don't know what syntax would work for your proposed addition. Which is probably why they made them final etc...
EDIT ADDED
If the author of the original Enum planned ahead (unlikely), and you are not worried too much abut thread safety, you could do something like this: (BTW, I'd probably scream at anybody who actually did this in production code, YMMV)
public enum ExtendibleEnum {
FOO, BAR, ZXC;
private Runnable anotherMethodRunme; // exact Interface will vary, I picked an easy one
// this is what gets "injected" by your other class
public void setAnotherMethodRunMe(Runnable r) { // inject here
anotherMethodRunme= r;
}
public void anotherMethod() { // and this behavior gets changed
anotherMethodRunme.run();
}
}
May I also add that we can emulate Extensible enums using interfaces.
From Joshua Bloch's brilliant book
http://books.google.com/books?id=ka2VUBqHiWkC&pg=PA165&lpg=PA165&dq=mulate+extensible+enums+with+interfaces&source=bl&ots=yYKhIho1R0&sig=vd6xgrOcKr4Xhb6JDAdkxLO278A&hl=en&sa=X&ei=XyBgUqLVD8-v4APE6YGABg&ved=0CDAQ6AEwAQ#v=onepage&q=mulate%20extensible%20enums%20with%20interfaces&f=false
or
http://jtechies.blogspot.com/2012/07/item-34-emulate-extensible-enums-with.html
The whole point of an enum is to create a closed set of possible values. This makes it easier to reason about what a value of that enum type is so the set of constants would still remain closed and unextended, but then again the enum would carry the extra methods provided by the extending class.

Is it a good idea to have a class nested inside an interface?

Is it possible to have an inner class inside the interface in java ???
You can. But here's what O'Reilly says about it:
Nested Classes in Interfaces?
Java supports the concept of nested classes in interfaces. The syntax and dynamics work just like nested classes declared in a class. However, declaring a class nested inside an interface would be extremely bad programming. An interface is an abstraction of a concept, not an implementation of one. Therefore, implementation details should be left out of interfaces. Remember, just because you can cut off your hand with a saw doesn't mean that it's a particularly good idea.
That said, I could see an argument for a static utility class nested into an interface. Though why it would need to be nested into the interface instead of being a stand-alone class is completely subjective.
I agree that this should be generally rare, but I do like to use inner classes in interfaces for services when the interface method needs to return multiple pieces of information, as it's really part of the contract and not the implementation. For example:
public interface ComplexOperationService {
ComplexOperationResponse doComplexOperation( String param1, Object param2 );
public static class ComplexOperationResponse {
public int completionCode;
public String completionMessage;
public List<Object> data;
// Or use private members & getters if you like...
}
}
Obviously this could be done in a separate class as well, but to me it feels like I'm keeping the whole API defined by the interface in one spot, rather than spread out.
Yes, it is possible but it is not common practice.
interface Test
{
class Inner
{ }
}
class TestImpl implements Test
{
public static void main(String[] arg)
{
Inner inner = new Inner();
}
}
Doesn't answer your question directly, but on a related note you can also nest an interface inside another interface. This is acceptable, especially if you want to provide views. Java's collection classes do this, for example Map.java in the case of the Map.Entry view:
public interface Map<K,V> {
...
public static interface Entry<K,V> {
....
}
}
This is acceptable because you're not mixing implementation details into your interface. You're only specifying another contract.
Yes. Straight from the language spec:
An inner class is a nested class that is not explicitly or implicitly declared static.
And (boldface mine):
A nested class is any class whose declaration occurs within the body of another class or interface.
One use case for this that I find quite useful is if you have a builder that creates an instance of the Interface. If the builder is a static member of the Interface, you can create an instance like this:
DigitalObject o = new DigitalObject.Builder(content).title(name).build();
It is legal, but I only really do it with nested interfaces (as already mentioned) or nested enums. For example:
public interface MyInterface {
public enum Type { ONE, TWO, THREE }
public Type getType();
public enum Status { GOOD, BAD, UNKNOWN }
public Status getStatus();
}

Categories

Resources