私有类作为公共方法的返回类型

Posted

技术标签:

【中文标题】私有类作为公共方法的返回类型【英文标题】:Private class as return type from public method 【发布时间】:2014-01-03 20:21:53 【问题描述】:

为什么这是有效的?

Foo.java

public class Foo 

    public Bar getBar() 
        return new Bar();
    

    private class Bar 


如果 Bar 是私有的,这个类的用户将如何使用这个方法?多态当然可以使用,但是这不应该是无效的,并且声明应该表明这是返回一个Object吗?

【问题讨论】:

【参考方案1】:

我有一个完全有效的用例,我很高兴这是允许的。

让我们继续拥有一个创建 UI 片段的类。它接受某种领域对象并创建一个 UI:

public Node createPersonUI(Person person) 
    BasePanel panel = new BasePanel();
    // ... setup panel with values ...
    return panel;

BasePanelNode 的子类,并且是调用者没有业务的一些内部类,因为这个类决定了事情的外观。

现在,当我需要支持一个新对象 PersonalProfile 时,我发现自己需要重用这个类的一部分,它包含更多信息,但也包含基本的 Person 数据:

public Node createPersonalProfileUI(PersonalProfile profile) 
    BasePanel panel = new BasePanel();
    // ... setup panel with values ...
    return panel;

但是,该代码部分重复,所以我这样做了:

public Node createPersonalProfileUI(PersonalProfile profile) 
    BasePanel panel = (BasePanel)createPerson(profile.getPerson());
    // ... only setup missing values ...
    return panel;

然而,演员阵容有点荒谬——将其更改为返回 BasePanel 不仅有效,而且不会暴露我的私有类的任何功能。相反,它只公开它继承自的任何公共类的方法......太棒了!

完整代码:

public BasePanel createPersonUI(Person person) 
    BasePanel panel = new BasePanel();
    // ... setup panel with values ...
    return panel;


public BasePanel createPersonalProfileUI(PersonalProfile profile) 
    BasePanel panel = createPerson(profile.getPerson());
    // ... only setup missing values ...
    return panel;


private class BasePanel extends Node 

【讨论】:

我想在这种情况下,使用第三个私有方法来封装该功能会更正确。基本上 createPersonUI 已经在做,并且 createPersonUI 只需调用这个新的私有方法。我认为,例如,当为此类生成文档时,该方法的返回类型将是 BasePanel,并且文档的使用者可能无法知道 BasePanel 是什么,或者它甚至扩展了 Node,因为它是私人的。但是好吧,在所有这些场景中,如果工具意识到这一点并改为显示 Node,它就不会那么糟糕。【参考方案2】:

我刚刚对此进行了一些研究,但未能找到明确的答案。这似乎很可能只是 Java 语言设计者的疏忽,因为它实际上并没有造成任何伤害,所以它被留下了。这与将public 方法放入private 类没有什么不同。没有什么能阻止你这样做,即使没有办法实际访问 public 方法。

当您尝试执行此操作时,当然 NetBeans 会给您“通过公共 API 导出非公共类型”的警告。我希望大多数其他环境会给出类似的警告。

返回的对象对于任何尝试使用它的人来说完全没用(除非他们使用反射),他们所能做的几乎就是将其存储到Object(或他们有权访问的任何其他超类)中然后传递Object

如果传递的Object 被用作传递但从未操作过的“句柄”,您可能希望这样做。在这种情况下,尽管拥有 public 类仍然更有意义,但将其内的所有方法设为 private 以防止它们在您的类之外被执行(或定义一个 public 接口以返回并拥有private 类实现)。

所以答案似乎是:

它可能不应该是有效的,但由于它不会造成任何伤害,它从未被阻止。

在类似的主题上有一个很好的答案:

Exporting non-public type through public API

【讨论】:

关于在私有类中创建公共方法的说法。确实有所不同,如果您在父类中有该私有类的对象,则不能调用私有方法,对吗?因此,私有类中的私有/公共方法对于定义可访问该类的作用域中的用法很有用。 其实可以的。内部类算作父类的成员,用于访问私有方法和变量(从内部到外部以及从外部到内部)。 其实很重要。它允许您使用私有方法创建内部类并从外部类访问它们,而不必在该类之外公开它们。 实际上,只要类实现了某些接口,在适当设计的 Java 代码中返回私有类是非常常见和有用的。 Java 库一直都在这样做。尽管他们可能会返回接口类型而不是私有类类型。 没错。返回类型是接口而不是实现它的私有类。返回私人课程很有意义。没有私有类的返回类型。【参考方案3】:

为什么这是有效的?

因为调用处的客户端代码可能期待Object(或根本不期待任何东西),所以从任何地方调用此方法都没有问题:

Object o = new Foo().getBar();

【讨论】:

【参考方案4】:

它是嵌套类型的一种形式。这种类声明称为内部类。如果您将内部类声明为静态,那么它将被称为***嵌套类。 Java 中可用的其他形式的嵌套类型是本地类;在块中声明和定义的类,即方法或构造函数或初始化块。嵌套类型的第四种形式是匿名类;一个没有任何名称的类,其对象在定义该类的地方使用。

就您的情况而言,即内部类,一个类中的所有类都可以用公共、私有和受保护的访问说明符声明。包含在封闭类中的所有类以及封闭类本身共享信任关系。这意味着,内部类的所有私有成员以及封闭类的私有成员都是相互共享的。但是,如果没有封闭类的对象,您将无法访问内部类的对象。

当您尝试创建内部类的对象时,编译器会报告编译时错误。但是下面的示例访问每个其他类的私有成员,即封闭类访问内部类的私有成员和内部类访问封闭类的私有成员:

class Bar 
    private static int x;

    public void getFoo() 
        System.out.println(new Foo().y);
    

    private class Foo 
        private int y;
        public void getBar() 
            System.out.println(Bar.x);
        
    


public class Test
    public static void main(String[] a) 
        Bar b = new Bar();
        //Bar.Foo f = new Bar.Foo(); This is completely illegal syntax.     
    

内部类的最佳示例是作为封闭类的Accounts 类和作为内部类的Transaction 类之间的关系。一个Accounts 类可以有多个Transaction 对象,但没有Accounts 对象就不能存在Transaction 对象。

尽管返回私有内部类的对象是无用的,因为它在其类之外变得不可见。正如上面AccountsTransaction 类的示例所解释的。没有Accounts 对象,Transaction 就无法存在。

【讨论】:

【参考方案5】:
public class Foo 

    private String myString;

    public String getMyString() 
        return myString;
    


这也是有效的。为什么内部类的行为应该不同?

制作Barprivate只会使其对外界不可见,就像制作字段private一样。

一个重要的警告是,即使您能够在 Foo 对象上调用 getBar(),您也不能调用该引用的方法(因为可见性)。

所以主要的是你可以这样做,但你不应该这样做。

我能想象的唯一情况是Foo也是一个内部类,而Foo的外部类想使用Bar

【讨论】:

我投了反对票。我回答的时候你还没有回答。 我回答的时候你还没有回答。你是认真的吗? @Adam Aroid 很好的解释。我不知道为什么有人投了反对票???我投了赞成票,因为我喜欢你的回答。 也许我读得太快了,因为我不记得看到最后一行 - 这是唯一直接回答问题的部分。对此感到抱歉,我确实在重新阅读后立即删除了反对票:) 问题是关于嵌套类型的可见性。与变量无关。【参考方案6】:

返回私有类的公共方法可能很有用,因为您需要能够从任何范围调用该方法(例如,改变 Foo 的内部状态),如果您还需要任何类型的结果,则用于内部使用简单地调用方法。

【讨论】:

【参考方案7】:

这是有效的,因为 BarFoo 类可见。这样就可以编译了。

当然另一个类看不到Bar,因此不能使用返回值。

但是另一个类仍然可以直接调用方法而不使用返回值。

public class FooBar 

   public void invokeBar() 
        Foo foo = new Foo();
        foo.getBar();
   

【讨论】:

@JqueryLearner 好的,我更新了,以免混淆其他人。对于命名空间,我只是指名称中的空格是有效的。你怎么称呼它? 我也研究过 c#,所以知道命名空间在 c# 中的含义 @JqueryLearner 我相信你知道。我只是问你是否知道它在java中通常是如何调用的。我认为命名空间对 java 也有好处。【参考方案8】:

内部类

内部类代表一种特殊类型的关系,它可以访问外部类的所有成员(数据成员和方法),包括私有的。嵌套类可以导致代码更具可读性和可维护性,因为它在逻辑上仅将类分组到一个位置。

【讨论】:

以上是关于私有类作为公共方法的返回类型的主要内容,如果未能解决你的问题,请参考以下文章

不能使用公共嵌套类作为私有方法参数

私有方法作为公共方法出现

私有的嵌套类(内部或静态)是不是可能具有具有公共访问权限的方法?

Scala案例类私有构造函数但公共应用方法

Scala案例类私有构造函数但公共应用方法

打字稿:使父类中的公共方法成为派生类中的私有/受保护方法