简体   繁体   中英

Casting objects in enum abstract methods

I have this kind of enum

   public enum MyEnum {
        member1(MyClass1.class){
            @Override
            public void doStuff(Object obj) {
                ...
            }
        },
        member2(MyClass2.class){
            @Override
            public void doStuff(Object obj) {
                ...
            }
        };
        ...
        public abstract void doStuff(Object obj);
    }

What I would like to do is call the method in the enum like this:

MyEnum.member1.doStuff(myObject);

And have the methods in enum which object it has to cast to. Lets say the myObject that I pass in is MyClass1. The member1 should know automatically that it is only expecting MyClass1 which is also defined in the enum member description.

Is something like this even possible or I am walking a completely wrong path?

public enum MyEnum {
   member1(String.class){
      @Override
      public void doStuff(Object obj) {
         this.checkArgumentType(obj);
         String stringObj = (String) obj;
         //...
      }
   },
   member2(Integer.class){
      @Override
      public void doStuff(Object obj) {
         this.checkArgumentType(obj);
         Integer stringObj = (Integer) obj;
         //...
      }

   };

   private final Class<?> clazz;

   MyEnum(Class<?> clazz) {
      this.clazz = clazz;
   }

   void checkArgumentType(Object obj) {
      if (!clazz.isAssignableFrom(obj.getClass())) {
         throw new IllegalArgumentException("Wrong class");
      }
   }

   //...
   public abstract void doStuff(Object obj);
}

Something similar is possible, but it gets messy and complex real quick, up to the point where you should think about creating separate classes. But as an example, what you could do:

public enum Foo {

    member1(new Bar<String, Long>(Long.class){

        @Override
        void doStuff(String aString) {

        }

    });

    private final Bar<?,?> bar;

    private Foo(Bar<?,?> bar) {
        this.bar = bar;
    }

    private static abstract class Bar<A,B> {

        private final Class<B> type;

        Bar(Class<B> type) {
            this.type = type;
        }

        abstract void doStuff(A a);
    }
}

This is not possible with an enum in the way that you have it in mind.

Ideally you want to have compile-time type safety. Passing Object and then casting is not type-safe; nothing prevents you from passing a wrong kind of object, and you won't know it until runtime, when you get a ClassCastException when you try to cast the object to something that it's not.

Enums cannot have type parameters, so you cannot do anything with type parameters, like this:

// This is not valid Java!
public enum MyEnum<T> {
    member1<MyClass> {
        @Override
        public void doStuff(MyClass obj) { ... }
    }

    // ...
    public abstract void doStuff(T obj);
}

If you want type-safety, just use a bunch of constants instead of an enum :

interface MyConstant<T> {
    void doStuff(T obj);
}

public final class MyConstants {

    public static final MyConstant<MyClass1> MEMBER_1 = new MyConstant<MyClass1>() {
        @Override
        public void doStuff(MyClass1 obj) {
            // ...
        }
    };

    // etc.

    private MyConstants() {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM