有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java当一个类包含packagelevel方法时,如何将该类隐藏在接口后面?

如何将以下类隐藏在接口后面(并使用工厂对其进行实例化)?:

public class TreeNode {
    private List<TreeNode> children;
    private TreeNode parent;

    public void addChild(TreeNode newChild) {
        children.add(newChild);
        newChild.setParent(this);
    }

    public TreeNode getParent() {
        return parent;
    }

    public void removeChild(TreeNode child) {
        children.remove(child);
        child.setParent(null);
    }

    void setParent(TreeNode newParent) {
        if(parent != null) {
            parent.removeChild(this);
        }
        parent = newParent;
    }
}

假设您将该类重命名为TreeNodeObj,并让它实现TreeNode接口:

class TreeNodeObj implements TreeNode {
    private List<TreeNode> children;
    private TreeNode parent;

    public void addChild(TreeNode newChild) {
        children.add(newChild);
        newChild.setParent(this);
    }
    ... etc. ...
}

public interface TreeNode {
    public void addChild(TreeNode newChild);
    public void removeChild(TreeNode child);
    public TreeNode getParent();
}

public class NodeFactory {
    public static TreeNode createTreeNode() {
        return new TreeNodeObj();
    }
}

这段代码不会编译,因为setParent()没有在TreeNode接口中定义(因为不应该直接调用它,也不应该在包外部公开)

我能想到的唯一解决办法是进行以下修改:

public interface TreeNode extends TreeNodePackageAccess {
    public void addChild(TreeNode newChild);
    public void removeChild(TreeNode child);
    public TreeNode getParent();
}

interface TreeNodePackageAccess {
    void setParent(TreeNode newParent);
}

class TreeNodeObj implements TreeNode {
    …[previous code]…

    public void setParent(TreeNode newParent) { 
        // this method is made public in order to implement TreeNodePackageAccess
        …[previous code]…
    }
}

有没有比使用上述策略更好的方法来实现这一点?(此外,使用上述策略,setParent()仍然可以通过反射从包外部访问,因此从技术上讲,您甚至无法使用它实现包级封装。)

如果接口需要一个不应该公开的包级方法,那么如何将原始类隐藏在接口后面


共 (2) 个答案

  1. # 1 楼答案

    只要在需要的地方将其转换为实现类。如果TreeNode的任何实现不是TreeNodeObj,则抛出一个异常,表明它来自无效的提供程序

    JavaSE已经做到了这一点。从the documentation of the java.nio.file package

    Unless otherwise noted, invoking a method of any class or interface in this package created by one provider with a parameter that is an object created by another provider, will throw ProviderMismatchException.

    因此,该包中的其他类可以执行以下操作:

    @Override
    public void add(TreeNode node) {
        if (!(node instanceof TreeNodeObj)) {
            throw new WrongProviderException(
                "Argument was created by a different provider: " + node);
        }
    
        TreeNodeObj obj = (TreeNodeObj) node;
        obj.setParent(parent);
    }
    
  2. # 2 楼答案

    How do you hide a class behind an interface when that class contains a package-level method?

    如前所述,这里没有什么特别的要求。可以使用接口抽象类的public方法的任意数量,包括零。在任何一般意义上,类的所有方法都不必镜像为接口的抽象方法

    但您的意思似乎是希望在接口中表示一个或多个包访问方法,这是不可能的。接口方法只能是publicprivate,并且private方法不是抽象的。抽象方法的实现不能缩小其访问范围,因此抽象接口方法的实现必须是public

    您将接口拆分为包访问超级接口和公共子接口的想法毫无帮助,即使您最终愿意将实现方法公开。superinterface声明的任何方法都会被子接口继承,并可以通过它进行访问