当前位置: 首页 > 面试题库 >

枚举特定于常量的类主体是静态的还是非静态的?

巴宏恺
2023-03-14
问题内容

我有一个枚举类型类:

public enum Operation {
    PLUS() {
        @Override
        double apply(double x, double y) {       
            // ERROR: Cannot make a static reference
            // to the non-static method printMe()...
            printMe(x);
            return x + y;
        }
    };

    private void printMe(double val) {
        System.out.println("val = " + val);
    }

    abstract double apply(double x, double y);
}

如您在上面看到的,我定义了一种enum具有value的类型PLUS。它包含一个特定于常数的主体。在其主体中,我尝试调用
printMe(val);,但出现编译错误:

无法静态引用非静态方法printMe()。

为什么会出现此错误?我的意思是我在PLUS体内重写了一种抽象方法。为什么在static范围内?如何摆脱它?

我知道在上添加static关键字printMe(){...}可以解决问题,但是我想知道是否还有其他方法可以保持printMe()非静态状态吗?

另一个问题,与上面的问题非常相似,但是这次错误消息听起来是相反的,即PLUS(){...}具有非静态上下文:

public enum Operation {
    PLUS() {
        // ERROR: the field "name" can not be declared static
        // in a non-static inner type.
        protected static String name = "someone";

        @Override
        double apply(double x, double y) {
            return x + y;
        }
    };

    abstract double apply(double x, double y);
}

我尝试声明一个PLUS-specific static变量,但最终出现错误:

在非静态内部类型中,不能将字段“名称”声明为静态。

PLUS如果PLUS是匿名类,为什么不能在内部定义静态常量?这两个错误消息听起来彼此矛盾,因为第一个错误消息说PLUS(){...}具有
静态 上下文,而第二个错误消息说PLUS(){...}具有 非静态 上下文。我现在更加困惑。


问题答案:

好吧,这是一个奇怪的情况。

看来问题是:

  • 在这种情况下, 应该可以访问 私有成员(6.6.1):

否则,将声明成员或构造函数private,并且仅当且仅当它发生在包含成员或构造函数的声明的顶级类的主体内时,才允许访问。

  • 但是,私有成员不会被继承(8.2):

声明的类的成员private不被该类的子类继承。

  • 因此,printMe它不是匿名子类的成员,并且编译器在超类* Operation(15.12.1)中搜索它:

如果有一个封闭的类型声明 ,该方法是该方法的成员 ,则让T为最里面的这种类型声明。搜索的类或接口是T。

该搜索策略称为“梳子规则”。 它在嵌套类及其父类层次结构中查找方法之前,可以有效地在嵌套类的父类层次结构中查找方法。

  • 这就是奇怪的地方。因为printMe是在 也包含 在内的类中找到的PLUS,所以调用该方法的对象被确定为的包含实例Operation,该实例不存在(15.12.4.1):

否则,令T为方法是其成员的封闭类型声明,令 n 为整数,使得T为该类的第 n 个词法封闭类型声明,其声明立即包含方法调用。 目标引用是的第
n 个词法包围实例this

如果 不存在第 n 个按词法包围的实例,this则是编译时错误。

简而言之,因为printMe仅是Operation(且未继承)成员,所以编译器被迫printMe 在不存在的外部实例上 调用。

但是,该方法仍然可以访问,我们可以通过限定调用来找到它:

@Override
double apply(double x, double y) {
//  now the superclass is searched
//  but the target reference is definitely 'this'
//  vvvvvv
    super.printMe(x);
    return x + y;
}

两条错误消息听起来彼此矛盾。

是的,这是语言的一个令人困惑的方面。一方面,匿名类永远不会是静态的(15.9.5),另一方面,匿名类表达式可以
出现在静态上下文中
,因此没有封闭的实例(8.1.3)。

匿名类始终是内部类。从来没有static

内部类I的声明发生在静态上下文中的实例没有词法包围的实例。

为了帮助理解其工作原理,下面是一个格式化示例:

类示例{
     _public static void main(String ... args){_
        **new Object(){
            我
            无效的m(){}
        } **_;
    }_
}

里面的一切_italics_ 都是静态的。从in中的表达式派生的匿名类**bold**
被视为内部且非静态的(但没有的封闭实例Example)。

由于匿名类是非静态的,因此尽管它本身是在静态上下文中声明的,但它无法声明静态的非常量成员。

*除了稍微掩盖问题之外,Operation作为枚举的事实是完全不相关的(8.9.1):

枚举常量的可选类主体隐式定义了一个匿名类声明,该声明扩展了立即封闭的枚举类型。类主体由匿名类的通常规则html" target="_blank">控制。



 类似资料:
  • 问题内容: Java中的静态和非静态枚举有什么区别?两种用法是相同的。 正确吗 所有静态的都在启动时加载到内存中,非静态的则按需加载 ? 如果是,那么哪种方法更好?将某些数据始终保留在内存中还是每次使用服务器资源加载它们? 问题答案: 所有的都是有效的。如果您有嵌套的枚举,则它与相同。 所有类都是延迟加载的(枚举或其他),但是在加载时,它们会一次全部加载。也就是说,您不能加载一些常量,而不能加载其

  • 问题内容: public enum Operations { 在上面的代码中,两个操作的操作值都会更改。如何有两个具有不同操作类型的Operations.SINGLE实例? 问题答案: 是的,实例是隐式的和。这意味着代码是不明智的。想象两个线程都在调用;您将不会对自己的通话充满信心。 根据Java语言规范的8.9节: 枚举类型(§8.9)不能声明为抽象;这样做会导致编译时错误。 枚举类型是隐式最终

  • 问题内容: 按照标准书,构造函数是用于初始化对象的一种特殊类型的函数。由于构造函数被定义为一个函数,并且内部类函数只能具有两种类型的静态或非静态类型。我怀疑是什么构造函数? 我的疑问是如果构造函数是静态方法,那么我们如何在构造函数内部频繁使用此方法 输出是否意味着构造函数是非静态的? 问题答案: 您的第二个例子很重要。引用在构造函数中可用,这意味着构造函数是针对某个对象(当前正在创建的对象)执行的

  • 问题内容: 我正在查看公司其他部门维护的一些Java代码,顺便说一下,这是一些前C和C ++开发人员所维护的。普遍存在的一件事是使用静态整数常量,例如 除了缺少“最终”限定符外,这种代码也让我有些不安。我本来希望看到的是,从学校开始主要接受Java的培训,这会更像 但是,论点使我失望。为什么要比后者更好呢? 问题答案: 为什么要比后者更好呢? 这样做要好得多,因为它可以为您提供类型安全性并具有自记

  • 问题内容: 我似乎无法像从内部类内部那样从枚举内部访问周围类的实例成员。这是否意味着枚举是静态的?是否可以访问周围类的实例的范围,还是必须在需要的地方将实例传递给枚举的方法? 问题答案: 是的,嵌套枚举是隐式静态的。 嵌套枚举类型是隐式静态的。可以将嵌套枚举类型显式声明为静态。a