枚举常量特定的类主体是静态的还是非静态的? [英] Is an enum constant-specific class body static or non-static?

查看:26
本文介绍了枚举常量特定的类主体是静态的还是非静态的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个枚举类型类:

公共枚举操作{加号(){@覆盖双申请(双x,双y){//错误:无法进行静态引用//到非静态方法 printMe()...打印我(x);返回 x + y;}};私人无效printMe(双VAL){System.out.println("val = " + val);}抽象双申请(双x,双y);}

如上所示,我定义了一个 enum 类型,其值为 PLUS.它包含一个特定于常量的主体.在它的主体中,我试图调用 printMe(val);,但我得到了编译错误:

<块引用>

不能对非静态方法printMe()进行静态引用.

为什么会出现这个错误?我的意思是我在 PLUS 主体中覆盖了一个抽象方法.为什么它在 static 范围内?如何摆脱它?

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

<小时>

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

公共枚举操作{加号(){//错误:字段名称"不能声明为静态//在非静态内部类型中.protected static String name = "someone";@覆盖双申请(双x,双y){返回 x + y;}};抽象双申请(双x,双y);}

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

<块引用>

不能在非静态内部类型中将字段name"声明为静态.

如果PLUS 是匿名类,为什么我不能在PLUS 中定义静态常量?这两条错误消息听起来相互矛盾,因为第一条错误消息表示 PLUS(){...} 具有 static 上下文,而第二条错误消息表示 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 个词法封闭其声明立即包含方法调用的类的类型声明.目标引用是this的第n个词法封闭实例.

    如果this的第n个词法封闭实例不存在,则这是一个编译时错误.

所以简而言之,因为printMe只是Operation的成员(并没有被继承),编译器被迫调用printMe 在一个不存在的外部实例上.

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

@Override双申请(双x,双y){//现在搜索超类//但目标引用肯定是 'this'//vvvvvvsuper.printMe(x);返回 x + y;}

<小时><块引用>

这两条错误消息听起来相互矛盾 [...].

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

<块引用>

匿名类总是内部类;它永远不是static.

<块引用>

内部类 I 的实例,其声明出现在静态上下文中,没有词法封闭实例.

为了帮助理解这是如何工作的,这里有一个格式化的例子:

<前>类示例{public static void main(String... args) {新对象(){国际我;无效 m() {}};}}

italics 中的所有内容都是静态上下文.从 bold 中的表达式派生的匿名类被认为是内部和非静态的(但没有 Example 的封闭实例).

由于匿名类是非静态的,它不能声明静态非常量成员,尽管它本身是在静态上下文中声明的.

<小时>

* 除了稍微模糊一点之外,Operation 是一个枚举的事实是完全不相关的(8.9.1):

<块引用>

枚举常量的可选类主体隐式定义了一个匿名类声明,该声明扩展了直接封闭的枚举类型.类主体由匿名类的通常规则控制 [...].

I have a enum type class:

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);
}

As you see above, I have defined one enum type which has value PLUS. It contains a constant-specific body. In its body, I tried to call printMe(val);, but I got the compilation error:

Cannot make a static reference to the non-static method printMe().

Why do I get this error? I mean I am overriding an abstract method in PLUS body. Why is it in static scope? How to get rid of it?

I know adding a static keyword on printMe(){...} solves the problem, but I am interested to know if there is another way if I want to keep printMe() non-static?


Another issue, quite similar as above one, but this time the error message sounds the other way around, i.e. PLUS(){...} has non-static context:

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);
}

I try to declare a PLUS-specific static variable, but I end up with error:

the field "name" can not be declared static in a non-static inner type.

Why can I not define static constant inside PLUS if PLUS is an anonymous class? The two error messages sound contradictory to each other, as the 1st error message says PLUS(){...} has static context while the 2nd error message says PLUS(){...} has non-static context. I am even more confused now.

解决方案

Well this is a strange case.

It appears that the problem is:

  • In this case, the private member should be accessible (6.6.1.):

    Otherwise, the member or constructor is declared private, and access is permitted if and only if it occurs within the body of the top level class that encloses the declaration of the member or constructor.

  • However, private members are not inherited (8.2):

    Members of a class that are declared private are not inherited by subclasses of that class.

  • Therefore, printMe is not a member of the anonymous subclass and the compiler searches for it within the superclass* Operation (15.12.1):

    If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or interface to search is T.

    This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking for methods in an enclosing class and its superclass hierarchy.

  • And here is where it gets strange. Because printMe is found in a class that also encloses PLUS, the object that the method is called on is instead determined to be an enclosing instance of Operation, which doesn't exist (15.12.4.1):

    Otherwise, let T be the enclosing type declaration of which the method is a member, and let n be an integer such that T is the n'th lexically enclosing type declaration of the class whose declaration immediately contains the method invocation. The target reference is the n'th lexically enclosing instance of this.

    It is a compile-time error if the n'th lexically enclosing instance of this does not exist.

So in short, because printMe is only a member of Operation (and not inherited), the compiler is compelled to invoke printMe on a non-existent outer instance.

However, the method is still accessible and we can find it by qualifying the invocation:

@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;
}


The two error messages sound contradictory to each other [...].

Yes, this is a confusing aspect of the language. On the one hand, an anonymous class is never static (15.9.5), on the other hand, an anonymous class expression can appear in a static context and therefore has no enclosing instance (8.1.3).

An anonymous class is always an inner class; it is never static.

An instance of an inner class I whose declaration occurs in a static context has no lexically enclosing instances.

To help understand how this works, here is a formatted example:

class Example {
    public static void main(String... args) {
        new Object() {
            int i;
            void m() {}
        };
    }
}

Everything in italics is the static context. The anonymous class derived from the expression in bold is considered inner and non-static (but has no enclosing instance of Example).

Since the anonymous class is non-static it cannot declare static non-constant members, despite that it is itself declared within a static context.


* Besides obscuring the matter a little, the fact that Operation is an enum is completely irrelevant (8.9.1):

The optional class body of an enum constant implicitly defines an anonymous class declaration that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes [...].

这篇关于枚举常量特定的类主体是静态的还是非静态的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆