【问题标题】:Can I extend Iterator to allow access to encapsulated inner class fields?我可以扩展 Iterator 以允许访问封装的内部类字段吗?
【发布时间】:2015-06-13 00:38:13
【问题描述】:

我很沮丧,试图向自定义迭代器添加方法。

对于我第二季度的 Java 课程中的一个作业,我们应该从头开始实现一个链表。没问题:我创建了一个外部类来实现链表和一个静态私有内部类来实现各个节点,封装它们,对任何客户端程序隐藏。

此链表中的节点将具有两个不同的下一个字段(一个用于名称,另一个用于位置)。跟随下一个字段之一将带我通过一条路径通过所有节点;跟随另一个下一个字段将带我另一条路线。 (考虑两个不同的字母顺序,取决于名称或位置。)没问题:为了遍历节点,遵循名称或位置,我创建了两个自定义迭代器。一个抽象类实现Iterator< Node > 和通用代码,两个内部类通过 nextName 字段或 nextPlace 字段为每个迭代器实现自定义代码。

next()hasNext() 方法运行良好,可以根据我是否实例化名称或地点迭代器来提供自定义结果。

这些节点还包含我想打印到控制台并保存在文件中的数据。这些节点被故意封装在列表类中,以保护它们免受客户端程序的恶意使用。我想通过添加访问器方法来扩展我的迭代器,例如getName()getPlace() 方法。这就是为什么我采取了额外的步骤来创建一个抽象类,而不是让我的自定义迭代器直接实现Iterator

但它不起作用。当我从客户端调用 itr.getName() 时,我得到“找不到符号”。我见过的最接近的答案是here,但我仍然得到“找不到符号”。

这是我的代码概要:

import java.util.Iterator;

public class MyList implements Iterable {

    // ...

    public Iterator nameIterator() {
        return new NameIterator( this );
    }

    public Iterator placeIterator() {
        return new placeIterator( this );
    }

    public abstract class NodeIterator implements Iterator< Node > {

        public NodeIterator( MyList list ) { ... }

        public boolean hasNext() { ... } // this appears to work fine

        public String getName() { ... } // this can't be seen by the client

        public String getPlace() { ... } // this can't be seen by the client

    }

    private class NameIterator extends NodeIterator {

        public NameIterator( MyList list ) {
            super( list );
            ...
        }

        public Node next() { ... }

    }

    private class PlaceIterator extends NodeIterator { ... } // same as NameIterator with custom code

    private static class AttractionNode {
        public String  name;
        public String  place;

        public Node  nextName;
        public Node  nextPlace;

        // ...
    }
}

我希望客户端代码能够运行:

    System.out.println( "\nBy names: " );
    Iterator itr = placesToGo.nameIterator();
    while( itr.hasNext() ) {
        itr.next();
        System.out.println( itr.getName() ); // gives me "cannot find symbol" error
        // System.out.println( itr.next() ); // works fine, alone
    }

抱歉,问题太长了。这是我第一次来这里,我仍在弄清楚我的问题到底是什么。

【问题讨论】:

  • 如果您想访问您的自定义方法,您需要在客户端代码中定义 NodeIterator 而不是 Iterator
  • iter.next()获取节点,并从节点读取属性。迭代器只是用于遍历项目,而不是表示项目。
  • 通过将itr 声明为Iterator,您只能访问Iterator 方法。它没有像您的自定义迭代器那样实现 getName() 之类的方法。 @RomanVottner 和 @bayou.io 都有出色的解决方案;我想我更喜欢bayou.io,因为这更像是标准模式。但是,根据您的代码,请坚持使用 RomanVottner 的
  • @bayou.io 我同意:通过迭代器从内部类返回值是非正统的。我在没有索引的情况下实现了它,所以我的 Node 类没有 get(index) 方法。由于 Node 是一个私有内部类,我无法看到 Node 从客户端读取其属性。
  • 我试图利用多态性,因为我不完全理解它,以尽可能高的类声明对象。我曾希望 Iterator itr = placesToGo.nameIterator();会成功的。可惜。谢谢你的想法。我会试试看。

标签: java iterator abstract-class inner-classes extends


【解决方案1】:

看了cmets中的讨论,建议你使用可以帮助你解决编译错误的IDE,比如Intellij IDEA

简要回顾您的问题:

如前所述,返回自定义迭代器的 List 方法必须具有具体的返回类型,例如 NameIteratorPlaceIterator

我应用了这两个修复 - 在客户端中将 itr 声明为 NameIterator 代码;调用 nameIterator() 时返回 NameIterator。叹。 现在“找不到符号”已移至 NameIterator itr 声明。

看来,编译器看不到您的内部 NameIterator 类。要从外部类外部使用内部类,您还应该指定外部类名称:

MyList.NameIterator itr = myList.nameIterator();

或者导入这个类:

import your.package.MyList.NameIterator;

【讨论】:

  • 我同意:外部类看不到内部类,这是应该的。我也尝试按照您的建议指定外部类 - 这很有效。它不优雅。我必须跟进教练为什么我的其他尝试失败了。我必须重新研究继承和多态性、接口和抽象类。但它有效。谢谢你。 (感谢您提供指向 Intellij IDEA 的指针。)
【解决方案2】:

nameIterator() 必须返回 NameIterator 而不是 Iterator&lt;Node&gt;

public NameIterator nameIterator() {
    return new NameIterator( this );
}

并且客户端代码必须使用NameIterator而不是Iterator&lt;Node&gt;

    System.out.println( "\nBy names: " );
    NameIterator itr = placesToGo.nameIterator();
    while( itr.hasNext() ) {
        itr.next();
        System.out.println( itr.getName() );
    } 

【讨论】:

    猜你喜欢
    • 2021-04-21
    • 1970-01-01
    • 2016-05-29
    • 1970-01-01
    • 2011-10-13
    • 2021-11-06
    • 2011-04-07
    • 2019-01-30
    相关资源
    最近更新 更多