【问题标题】:Overload enum abstract method重载枚举抽象方法
【发布时间】:2017-04-19 19:51:15
【问题描述】:

Enum 抽象方法可以重载吗?

我已经在我的代码中尝试过,但没有任何效果。 授课类

public class Test {
    public void test(String string){
        System.out.println(string);
    }

    public void test(Object object){
        System.out.println("Test1");
    }

    public static void main(String[] args) {
        Object object = new Object();
        test.test(object);
        test.test("what if?");
    }
}

给出预期的结果

Test1
what if?

而枚举

public enum TestEnum {
    TEST1{
        public void test(String string){
            System.out.println(string);
        }

        public void test(Object object){
            System.out.println("Test1");
        }
    },
    TEST2{
        public void test(Object object){
            System.out.println("Test2");
        }
    };

    public abstract void test(Object object);
}

public class Test {
    public static void main(String[] args) {
        Object object = new Object();
        TestEnum.TEST1.test("what if?");
        TestEnum.TEST1.test(object);
    }
}

返回

Test1
Test1

是否有可能重载枚举方法或者我做错了什么?或者也许我应该检查覆盖方法内部的类型,然后采取相应的行动?但后来我删除 switch 语句只是为了引入另一个 switch 语句。

【问题讨论】:

  • 这与枚举无关。这就是一般调用哪个方法是在编译时根据对象的类型决定的,而不是具体的对象。如果你想要这样的东西——无论是枚举还是任何其他类型——你必须在运行时使用instanceof明确检查类型。
  • @LouisWasserman 或使用显式双重调度
  • 关于枚举的事情是带有主体的值被实现为TestEnum的匿名子类;所以它们看起来像TestEnum TEST1 = new TestEnum() { /* body */ }。因此,虽然TEST1 的具体类是TestEnum$1,但引用的类型是TestEnum,因此您的代码只能访问在TestEnum 上定义的方法。
  • @AndyTurner 知道了。
  • 顺便说一下,在你被覆盖的方法上使用@Override

标签: java enums overloading overriding


【解决方案1】:

关于枚举的事情是带有主体的值被实现为TestEnum 的匿名子类;所以它们看起来像这样:

final TestEnum TEST1 = new TestEnum() { /* body */ };

虽然TEST1 的具体类是TestEnum$1(或编译器决定给它的任何名称),但引用的类型是TestEnum,因此TEST1 主体之外的任何代码只能在TestEnum 上定义的访问方法。

【讨论】:

    【解决方案2】:

    是的,这是可能的,你没有以某种特定的方式实现它....

    你应该 使用要覆盖的方法定义接口

    interface Ifoo {
        public void test(Object object);
    
        public void test(String object);
    }
    

    然后删除枚举的抽象方法并使枚举实现该接口,但在枚举器的每个常量中覆盖这些方法...

    enum TestEnum implements Ifoo {
        TEST1 {
        @Override
        public void test(String string) {
            System.out.println(string);
        }
    
        @Override
        public void test(Object object) {
            System.out.println("Test1");
        }
        },
        TEST2 {
        @Override
        public void test(Object object) {
            System.out.println("Test2");
        }
    
        @Override
        public void test(String string) {
            System.out.println(string);
        }
        };
    }
    

    最终像这样实现它>

    Object object = new Object();
    TestEnum.TEST1.test("what if?");
    TestEnum.TEST1.test(object);
    TestEnum.TEST2.test("why not?");
    TestEnum.TEST2.test(object);
    

    您的结果应如下所示:

    如果呢?

    测试1

    为什么不呢?

    测试2

    【讨论】:

    • 这个接口不是必须的,没有它也可以工作。但是,我认为 OP 只是试图为特定的枚举值重载该方法。
    • ohhh....现在我以不同的方式看到了这个问题....感谢@radoh 的评论
    • 除非你需要通过超类型引用枚举,否则接口方法是多余的。接口用于建立类型,这在此处不太可能是必需的。枚举本身中的抽象方法方法几乎是您所需要的。
    【解决方案3】:

    您正在展示一个带有类的示例,然后您正在展示一个带有枚举的示例。我相信您认为这些示例是等价的,但是,它们彼此完全不同。

    为了使您的类示例与您的枚举示例等效,您应该修改您的 Test 类,使其扩展抽象 AbstractTest 类:

    public abstract class AbstractTest {
    
        public abstract void test(Object object);
    }
    
    public class Test extends AbstractTest {
    
        public void test(String string) {
            System.out.println(string);
        }
    
        @Override
        public void test(Object object) {
            System.out.println("Test1");
        }
    }
    

    现在,如果您尝试在第一个 main 中尝试过的相同行:

    AbstractTest test = new Test();
    Object object = new Object();
    test.test(object);
    test.test("what if?");
    

    你会注意到现在的输出变成了:

    Test1
    Test1
    

    这是意料之中的事情,因为 Java 不提供名为 dynamic dispatch 的功能。非正式地,动态分派意味着要执行的重载方法是在运行时根据参数的多态类型决定的。相反,Java 会根据要调用其方法的对象的 已声明 类型(在本例中为 AbstractTest)来决定要在编译时执行的方法。

    使用枚举,这正是发生的事情。枚举的所有元素(在您的示例中为TEST1TEST2)都属于枚举的类型(在您的示例中为TestEnum),因此编译器总是选择声明为抽象的方法。

    【讨论】:

      【解决方案4】:

      你得到两次“Test1”的原因是你只声明了这个方法
      public abstract void test(Object object);
      准确地说,此方法将“捕获”所有带有任何类型参数的调用。 String (间接)扩展了 Object,因此 String 是 Object,我们调用了这个方法。
      换句话说,接收参数String的方法将被接收参数Object的方法隐藏。

      解决方法是在枚举中添加下一个方法声明
      public abstract void test(String string);
      您必须将此方法的实现添加到TEST2 常量。

      代码

      public enum TestEnum {
          TEST1 {
              public void test(String string) {
                  System.out.println(string);
              }
      
              public void test(Object object) {
                  System.out.println("Test1");
              }
          },
          TEST2 {
              public void test(Object object) {
                  System.out.println("Test2");
              }
      
              @Override
              public void test(String string) {
                  // TODO Auto-generated method stub
              }
          };
      
          public abstract void test(Object object);
      
          public abstract void test(String string);
      }
      

      这段代码给出了输出

      what if?
      Test1
      

      【讨论】:

        猜你喜欢
        • 2011-08-31
        • 2011-11-16
        • 2022-06-25
        • 2022-01-15
        • 1970-01-01
        • 2011-07-29
        • 1970-01-01
        • 2016-02-13
        • 1970-01-01
        相关资源
        最近更新 更多