Java:在静态上下文中访问匿名类中的非静态字段

Java: accessing a non-static field in an anonymous class in a static context

提问人:YoavKlein 提问时间:7/7/2023 更新时间:7/7/2023 访问量:85

问:

请考虑以下类:

public class DataStructure {
    
    // Create an array
    private final static int SIZE = 15;
    private int[] arrayOfInts = new int[SIZE];

    public DataStructure() {
        // fill the array with ascending integer values
        for (int i = 0; i < SIZE; i++) {
            arrayOfInts[i] = i;
        }
    }

    public void print(DataStructureIterator iter) {
        while(iter.hasNext()) {
            System.out.print(iter.next() + " ");
        }
        System.out.println();
    }
    
    interface DataStructureIterator extends java.util.Iterator<Integer> { } 

    // Inner class implements the DataStructureIterator interface,
    // which extends the Iterator<Integer> interface
    
    private class EvenIterator implements DataStructureIterator {
        
        // Start stepping through the array from the beginning
        private int nextIndex = 0;
        
        public boolean hasNext() {
            
            // Check if the current element is the last in the array
            return (nextIndex <= SIZE - 1);
        }        
        
        public Integer next() {
            
            // Record a value of an even index of the array
            Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]);
            
            // Get the next even element
            nextIndex += 2;
            return retValue;
        }

    }
    
    public static void main(String s[]) {
        
        // Fill the array with integer values and print out only
        // values of even indices
        DataStructure ds = new DataStructure();
    
        ds.print(
            new DataStructure.DataStructureIterator() {
                private int nextIndex = 1;
                public boolean hasNext() { 
                    return (nextIndex <= ds.size() - 1);
                }
                public Integer next() {
                    //int retValue = arrayOfInts[nextIndex]; // this won't work:
                    // non-static variable arrayOfInts cannot be referenced from a static context
                    int retValue = ds.get(nextIndex);
                    nextIndex += 2;
                    return retValue;
                }
            }
        );        
    }
}

编译这个,我得到:

error: non-static variable arrayOfInts cannot be referenced from a static context

编译器抱怨从 main 方法中的匿名类访问变量。arrayOfInts

我的问题是:好的,我知道我无法从静态上下文访问非静态变量 - 这完全有意义。 但在本例中,我实际上并没有从静态上下文访问变量。相反,我正在将一段代码(一个匿名类)传递给一个非静态方法。非静态方法肯定可以访问非静态变量,那么为什么不可能呢?

Java 内部 匿名类

评论

0赞 user207421 7/7/2023
new DataStructure.DataStructureIterator()应该肯定吗?ds.new DataStructure.DataStructureIterator()
0赞 Sweeper 7/7/2023
@user207421 为什么会有帮助?在静态上下文中创建的匿名类不是内部类,不能有封闭实例。
0赞 user207421 7/7/2023
好的,那么下一个问题是,他为什么要在 main 方法中定义迭代器?如果有必要,为什么不延长呢?这将*需要*上下文,并提供他需要的非静态上下文。目前,他正在访问超出(非静态)范围的东西。EvenIteratords.
0赞 Sweeper 7/7/2023
@user207421是的,我同意代码的设计很奇怪。我认为这只是展示 OP 混乱的人为场景之一。

答:

0赞 Maksym Kosenko 7/7/2023 #1

您正在从静态方法中创建一个匿名类,并尝试将非静态字段传递给实现,这就是您收到编译错误的原因。而 EvenIterator 类相对于 DataStructure 是内部的,因此它意味着绑定到 DataStructure 类的实例并可以访问其非静态变量。

内部类和嵌套类的规范

与实例方法和变量一样,内部类与其封闭类的实例相关联,并可以直接访问该对象的方法和字段。

0赞 Sweeper 7/7/2023 #2

相反,我正在将一段代码(一个匿名类)传递给一个非静态方法

Java 不会考虑您对正在创建的实例执行的操作,以确定您是否可以访问非静态字段。

据 Java 所知,您可以将匿名类的实例分配给局部变量:

public static void main(String[] args) {
    var foo = new DataStructure.DataStructureIterator() {
        public boolean hasNext() { 
            ...
        }
        public Integer next() {
            int retValue = arrayOfInts[nextIndex]; // this won't work:
            ...
        }
    };
    foo.next();
}

在这种情况下会怎么做?任何地方都没有实例!foo.next()DataStructure

也就是说,在您的代码中有一个实例 - 。在这种情况下,您可能打算访问,因此请改为访问。DataStructuredsarrayOfIntsds.arrayofInts

请注意,inside 的使用是有效的,因为 是 的内部类。请注意,,它也嵌套在 中,它不是“内部接口”。没有“内部接口”这样的东西。 只是另一种常规类型。arrayOfIntsEvenIteratorEvenIteratorDataStructureDataStructureIteratorDataStructureDataStructure.DataStructureIterator

要创建 的实例,您需要一个 的实例。此实例称为 的封闭实例EvenIteratorDataStructureDataStructureEvenIterator

因为正在访问其封闭实例,而不是您正在调用的任何实例,这可能会导致一些意外结果:EvenIteratorarrayOfIntsprint

DataStructure ds1 = new DataStructure();
DataStructure ds2 = new DataStructure();
EvenIterator iter = ds1.new EvenIterator(); // enclosing instance is ds1
ds2.print(iter); // prints the elements of ds1, not ds2!

评论

0赞 Maksym Kosenko 7/7/2023
嗯,这就是我讨厌的功能,得分高的游戏玩家围绕原作者做一些化妆,并窃取接受和投票。查看答案的编辑历史记录
0赞 Maksym Kosenko 7/7/2023
从另一方面来看,@YoavKlein为什么你接受了这个答案,而不是我的答案?你们是朋友吗?@Sweeper的虚假账户?或者也许我的答案不是那么好,除了至少接受之外,甚至不值得投赞成票?