垃圾收集器和匿名类

时间:2017-06-17 16:09:12

标签: java collections garbage-collection

我们有代码:

Iterator<Object> it = new Collection<Object>(){/*...implementation...*/}.iterator();

问:垃圾收集器会删除我创建的对象以表示集合吗?在形式上,我们没有引用此对象,但it (Iterator <Object>)仍然与匿名类对象的内部相关联。

换句话说,请考虑代码:

Iterator<Object> it = new Collection<Object>(){             // String (1)

    private Object[] array;

    public Iterator<Object> iterator(){
        /*Here, an iterator that references this.array is returned
        + Performing its tasks*/
    } 

    /* + other implementation...*/ 

}.iterator();

然后GC会删除第一行中创建的对象,我们客观地没有链接到? //String (1)

对于那些特别喜欢编写伪答案的人来说,这里是我的迭代器看起来像的代码:

Iterator<Object> it = new Collection<Object>() { // String (1)

        private Object[] array2;

        @Override
        public Iterator<Object> iterator() {
            return new Iterator<Object>() {
                Object[] array;
                {
                    array = array2;
                }
                @Override
                public boolean hasNext() {
                    // We do what is necessary
                    return false;
                }
                @Override
                public Object next() {
                    // We do what is necessary
                    return null;
                }
            };
        }

        /* + other implementation... */
}.iterator();

小额外问:

我可以将“array2”(在Collection的实现中)重命名为“array”吗?那么如何在Iterator的实现中使用它?

return new Iterator<Object>() {
    Object[] array;
    {
        array = array2;   // array = array ? It doesn't work. How refer to array above
    }
    // and so on...

关于重复......不是this question。也许它看起来像,但我希望得到关于DELETING的问题的答案。这会发生或不发生,为什么? +接收其他问题的答案很重要。 That question可以帮助某人了解我的问题的答案,但不是我。

1 个答案:

答案 0 :(得分:0)

如果赋予外部类相同的名称array,则无法访问外部类'字段,只要外部类是匿名内部类。但是,第二个array字段的整个维护已经过时,因为它不会阻止内部(大多数)类维护对其外部实例的引用,如Do anonymous classes always maintain a reference to their enclosing instance?中所述。

这两个问题的解决方案是相同的,不要使用匿名内部类,而是使用命名的嵌套类,或者将其移动到不具有范围外部实例的工厂方法中:

    Iterator<Object> it = new AbstractCollection<Object>() {
        private Object[] array;
        @Override
        public Iterator<Object> iterator() {
            return getIterator(array);
        }
        @Override
        public int size() {
            throw new AssertionError("no-one's gonna call this here");
        }
    }.iterator();
…

static Iterator<Object> getIterator(final Object[] array) {
    return new Iterator<Object>() {
        @Override
        public boolean hasNext() {
            // We do what is necessary
            return false;
        }
        @Override
        public Object next() {
            // We do what is necessary
            return null;
        }
    };
}

当然,这还有两个问题

  1. 当我们已经知道我们要做的就是调用Collection方法时,iterator()实现的重点是什么?为什么不首先调用getIterator方法?

  2. 如果我们在这一点上,为什么不调用Arrays.asList(array).iterator()(请记住,复制数组)?

  3. 也就是说,拥有引用并不一定能防止垃圾回收。考虑The Java® Language Specification, §12.6.1

      

    可达对象是任何可以从任何活动线程继续计算中访问的对象。

         

    ...

         

    可以设计优化程序的转换,以减少可达到的对象数量,使其少于可以被认为可达的对象数量。例如,Java编译器或代码生成器可以选择将不再用于null的变量或参数设置为使得此类对象的存储可能更快地回收。

    请注意,这甚至适用于Iterator实例,在将其代码内联到调用者(即循环)后可以回收其存储,以便它只在数组上工作。但是你不会注意到这一点,因为当然,优化器会确保程序的行为不会改变。