Java TreeSet 中的私有整数

Java Private Integer in a TreeSet

我当前的任务是创建一个整数树集。 我应该以某种方式创建它,以便内部结构对用户隐藏,所以我应该尽可能多地声明为私有。 在之前的练习中,我们应该自己构建树,在这种情况下,您可以将节点元素设置为私有,现在我可以使用 Java 实用程序,这不再需要了。

目前看起来是这样的:

import java.util.Iterator;
import java.util.TreeSet;

public class Tree28 {

    public static void main(String[] args) {

        TreeSet<Integer> Tree28 = new TreeSet();
        for (int i = 0; i <= 10; i++) {
            Tree28.add(new Integer(i));
        }

        //Testing duplicates (shouldn't add object as int=4 is already part of the collection)
        Integer i11 = 4;
        Tree28.add(i11);

        System.out.println();
        System.out.println("Printing TreeSet using For-Loop");
        for (Integer i : Tree28) System.out.print(i + "\t");

        System.out.println();
        Iterator<Integer> it = Tree28.iterator();
        System.out.println("Printing TreeSet using Iterator with While");
        while (it.hasNext()) {
            System.out.print(it.next() + "\t");
        }

所以基本结构有效,我理解它,但是无法将整数包装器 class 设置为私有,我无法使用搜索功能找到任何解决方案。 如果你们中的一些人能向我解释我应该如何进行,我将不胜感激。

您可以在 class 中将任何内容设为私有,但不能在方法中设为私有。所以你的 TreeSet 需要是一个实例字段,而不是在 main 中声明。这也意味着您不能像 main 一样从静态上下文访问它,但可以从实例方法访问它。但是要让 class 的用户访问它,您需要提供一种受控的访问方式。因此,要检索特定值或打印 TreeSet,您需要创建一个方法来执行此操作,如下所示。

public Integer getValue() {
    <return some value here>
}

public void printTreeSet() {
   Iterator<Integer> it = Tree28.iterator();
   System.out.println("Printing TreeSet using Iterator with While");
   while (it.hasNext()) {
        System.out.print(it.next() + "\t");
   }
}

听起来你的作业的重点是演示封装。至于为什么要封装,我们来说说吧。

public class MySet {
    final Set<Integer> mySet = new TreeSet<>(); //final, can't be reassigned
}

我们现在可以创建一个 MySet 对象,其中包含我们的 java 集合:

MySet object = new MySet();
//assuming class is in the same package...
object.mySet.add(/* ... */);
object.mySet.remove(/* ... */);
//can't be done, it's final so it can't change! right?
object.mySet = null;

当然,您甚至可以使用方法围绕您的集合添加功能。为了演示为什么封装,我还添加了方法#wasAddedPreviously和字段previous

public class MySet {
    //...
    final Set<Integer> previous = new TreeSet<>(); //for #wasAddedPreviously

    public void add(int num) {
        this.mySet.add(num);
        this.previous.add(num);
    }

    public void printAll(PrintStream output) {
        this.mySet.forEach(output::println);
    }

    public boolean wasAddedPreviously(int num) {
        return this.previous.contains(num);
    }
}

显然您可以像这样公开成员,但您也可以看到当您引入复杂状态时 public 字段的问题如何变得不自然。现在,如果您直接修改 mySet,您会注意到 #wasAddedPreviously 中断!

MySet object = new MySet();
object.mySet.add(42);
object.add(43);
object.printAll(System.out); //42, 43
object.mySet.remove(42);
object.mySet.remove(43);
object.wasAddedPreviously(42); //false
object.wasAddedPreviously(43); //true

为了解决这个问题,您尝试让您的对象只公开并执行您想要定义的内容。您不想要一个包含集合的所有属性的对象,您想要一个可以添加、删除或打印所有内容的对象,因此我们涵盖了它并确保我们的字段不暴露(通过使用 private):

public class MySet {
    private final Set<Integer> mySet = new TreeSet<>();
    private final Set<Integer> previous = new TreeSet<>(); 

    //added to allow removing from the set
    public boolean add(int num) {
        this.mySet.remove(num);
    }
}

从这里开始,您将无法再访问 object.mySet,但您需要的所有功能都在那里,不会破坏您的其他方法:

MySet object = new MySet();
object.add(42);
object.add(43);
object.printAll(System.out); //42, 43
object.remove(42);
object.remove(43);
object.wasAddedPreviously(42); //true
object.wasAddedPreviously(43); //true
object.mySet./* ... */; // compile error

额外的好处是,当您设计一个更大的系统时,您无需跟踪大量内部状态(针对特定问题使用抽象的二元组系统?),您只需使用方法#add 、#remove、#wasAddedPrev 和#print 来处理。这极大地简化了您自己的编码。