Java - 使静态嵌套类对所有人可见,但仅由父类和父类构成

时间:2018-05-21 08:29:44

标签: java inner-classes access-modifiers

我有一个包含类似结构的静态嵌套类的父类。嵌套类必须是公共的,因为它应该返回到其内容被执行的其他类。但是,只有父类及其子类应该能够实例化嵌套类,因为它们知道如何定义其内容。下面显示的所有类都在不同的包中。

public abstract class Parent
{
    public static class Data
    {
        public final String data1
        ...

        public Data(String d1, ...)
        {
            data1 = d1;
            ...
        }
    }

    public abstract Data getData();
}
public final class Subclass extends Parent
{
    @Override
    public Data getData()
    {
        return new Data(.....);
    }
}
public class SomeOtherClass
{
    public void someMethod()
    {
        final Data d = new Subclass().getData();
        System.out.println(d.data1);
    }
}

声明Dataprotected会阻止getData()正常工作。减少Data构造函数上的访问修饰符会阻止Parent的子类正常工作。我想要的是像protected-by-parent这样的东西,我猜它在Java中不存在。

是否有合适的解决方法?我可以看到的一种可能性是在protected中创建Parent方法,该方法可以有效地镜像,调用和返回Data的构造函数(将生成private)。然而这似乎有点凌乱;有人知道更好的方式/设计吗?

2 个答案:

答案 0 :(得分:2)

更好的解决方案是创建嵌套类protected,并使其实现public接口。只有接口才会暴露给外部类,嵌套类本身仍将是一个实现细节。

public abstract class Parent
{

    public interface Data {
        public String getData1();
    }

    protected static class DataImpl implements Data
    {
        private final String data1;
        ...

        protected DataImpl(String d1, ...)
        {
            data1 = d1;
            ...
        }
        public String getData1(){
            return data1;
        }
    }

    public abstract Data getData();
}

public final class Subclass extends Parent
{
    @Override
    public Data getData()
    {
        return new DataImpl(.....);
    }
}

public class SomeOtherClass
{
    public void someMethod()
    {
        final Data d = new Subclass().getData();
        System.out.println(d.getData1());
    }
}

答案 1 :(得分:1)

您不能为外部类的子类创建静态成员类import java.awt.*; import java.awt.datatransfer.*; import java.awt.event.ActionEvent; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.tree.*; public class JTreeTransferHandler2 extends JFrame { public JTreeTransferHandler2() { initiate(); } private void initiate() { setTitle("Copy from JTree"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400,400); setLocation(200,200); setVisible(true); DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root"); DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables"); vegetableNode.add(new DefaultMutableTreeNode("Capsicum")); vegetableNode.add(new DefaultMutableTreeNode("Carrot")); DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits"); fruitNode.add(new DefaultMutableTreeNode("Mango")); fruitNode.add(new DefaultMutableTreeNode("Apple")); root.add(vegetableNode); root.add(fruitNode); JTree tree = new JTree(root); TreeTransferHandler treeTransferHandler = new TreeTransferHandler(); tree.setTransferHandler(treeTransferHandler); Clipboard clipboard = this.getToolkit().getSystemClipboard(); JButton copy = new JButton("Copy"); copy.addActionListener((ActionEvent e) -> { TransferHandler handler = tree.getTransferHandler(); handler.exportToClipboard(tree, clipboard, TransferHandler.COPY); }); JButton paste = new JButton("Paste"); paste.addActionListener((ActionEvent e) -> { Transferable clipData = clipboard.getContents(null); if (clipData != null) { if (clipData.isDataFlavorSupported(treeTransferHandler.nodesFlavor)) { TransferHandler handler = tree.getTransferHandler(); handler.importData(tree, clipData); } } }); JPanel buttonsPanel = new JPanel(); buttonsPanel.add(copy); buttonsPanel.add(paste); add(new JScrollPane(tree), BorderLayout.CENTER); add(buttonsPanel, BorderLayout.SOUTH); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JTreeTransferHandler2 jTreeTransferHandler = new JTreeTransferHandler2(); }); } } class TreeTransferHandler extends TransferHandler { DataFlavor nodesFlavor; DataFlavor[] flavors = new DataFlavor[1]; DefaultMutableTreeNode[] nodesToRemove; public TreeTransferHandler() { try { String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" + DefaultMutableTreeNode[].class.getName() + "\""; nodesFlavor = new DataFlavor(mimeType); flavors[0] = nodesFlavor; } catch(ClassNotFoundException e) { System.out.println("ClassNotFound: " + e.getMessage()); } } //TransferHandler @Override public int getSourceActions(JComponent c) { return TransferHandler.COPY; } //TransferHandler @Override public boolean canImport(JComponent comp, DataFlavor flavor[]) { for (int i = 0, n = flavor.length; i < n; i++) { for (int j = 0, m = flavors.length; j < m; j++) { if (flavor[i].equals(flavors[j])) { return true; } } } return false; } //TransferHandler @Override protected Transferable createTransferable(JComponent c) { JTree tree = (JTree) c; TreePath[] paths = tree.getSelectionPaths(); if (paths != null) { List<DefaultMutableTreeNode> copies = new ArrayList<>(); List<DefaultMutableTreeNode> toRemove = new ArrayList<>(); DefaultMutableTreeNode node = (DefaultMutableTreeNode) paths[0].getLastPathComponent(); DefaultMutableTreeNode copy = copy(node); copies.add(copy); toRemove.add(node); for (int i = 1; i < paths.length; i++) { DefaultMutableTreeNode next = (DefaultMutableTreeNode) paths[i].getLastPathComponent(); // Do not allow higher level nodes to be added to list. if (next.getLevel() < node.getLevel()) { break; } else if (next.getLevel() > node.getLevel()) { // child node copy.add(copy(next)); // node already contains child } else { // sibling copies.add(copy(next)); toRemove.add(next); } } DefaultMutableTreeNode[] nodes = copies.toArray(new DefaultMutableTreeNode[copies.size()]); nodesToRemove = toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]); return new NodesTransferable(nodes); } return null; } /** Defensive copy used in createTransferable. */ private DefaultMutableTreeNode copy(TreeNode node) { return new DefaultMutableTreeNode(node); } //TransferHandler @Override public boolean importData(TransferHandler.TransferSupport support) { if (!canImport(support)) { return false; } // Extract transfer data. DefaultMutableTreeNode[] nodes = null; try { Transferable t = support.getTransferable(); nodes = (DefaultMutableTreeNode[]) t.getTransferData(nodesFlavor); } catch (UnsupportedFlavorException ufe) { System.out.println("UnsupportedFlavor: " + ufe.getMessage()); } catch (java.io.IOException ioe) { System.out.println("I/O error: " + ioe.getMessage()); } // Get drop location info. int childIndex; TreePath dest; if (support.isDrop()) { JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation(); childIndex = dl.getChildIndex(); dest = dl.getPath(); } else { childIndex = -1; JTree tree = (JTree) support.getComponent(); dest = tree.getSelectionPath(); } DefaultMutableTreeNode parent = (DefaultMutableTreeNode) dest.getLastPathComponent(); JTree tree = (JTree) support.getComponent(); DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); // Configure for drop mode. int index = childIndex; // DropMode.INSERT if (childIndex == -1) { // DropMode.ON index = parent.getChildCount(); } // Add data to model. for (int i = 0; i < nodes.length; i++) { // ArrayIndexOutOfBoundsException model.insertNodeInto(nodes[i], parent, index++); } return true; } //TransferHandler @Override public boolean importData(JComponent comp, Transferable t) { return importData(new TransferHandler.TransferSupport(comp, t)); } public class NodesTransferable implements Transferable { DefaultMutableTreeNode[] nodes; public NodesTransferable(DefaultMutableTreeNode[] nodes) { this.nodes = nodes; } //Transferable @Override public Object getTransferData(DataFlavor flavor) { if(!isDataFlavorSupported(flavor)) { return false; } return nodes; } //Transferable @Override public DataFlavor[] getTransferDataFlavors() { return flavors; } //Transferable @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.equals(nodesFlavor); } } } 的构造函数。表达性并不直接存在于Java语言中。

但是,您可以创建静态成员类protected Data的构造函数 - 在这种情况下,外部类仍然可以访问它。外部类可以定义一个受保护的工厂方法来调用private构造函数 - 通过使它成为Data,它只能被父本身,子类和同一个包中的所有类访问(总是如此) protected修饰符的情况)

protected