私有类作为公共方法的返回类型
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;
BasePanel
是Node
的子类,并且是调用者没有业务的一些内部类,因为这个类决定了事情的外观。
现在,当我需要支持一个新对象 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 对象。
尽管返回私有内部类的对象是无用的,因为它在其类之外变得不可见。正如上面Accounts
和Transaction
类的示例所解释的。没有Accounts
对象,Transaction
就无法存在。
【讨论】:
【参考方案5】:public class Foo
private String myString;
public String getMyString()
return myString;
这也是有效的。为什么内部类的行为应该不同?
制作Bar
private
只会使其对外界不可见,就像制作字段private
一样。
一个重要的警告是,即使您能够在 Foo
对象上调用 getBar()
,您也不能调用该引用的方法(因为可见性)。
所以主要的是你可以这样做,但你不应该这样做。
我能想象的唯一情况是Foo
也是一个内部类,而Foo
的外部类想使用Bar
。
【讨论】:
我投了反对票。我回答的时候你还没有回答。 我回答的时候你还没有回答。你是认真的吗? @Adam Aroid 很好的解释。我不知道为什么有人投了反对票???我投了赞成票,因为我喜欢你的回答。 也许我读得太快了,因为我不记得看到最后一行 - 这是唯一直接回答问题的部分。对此感到抱歉,我确实在重新阅读后立即删除了反对票:) 问题是关于嵌套类型的可见性。与变量无关。【参考方案6】:返回私有类的公共方法可能很有用,因为您需要能够从任何范围调用该方法(例如,改变 Foo 的内部状态),如果您还需要任何类型的结果,则用于内部使用简单地调用方法。
【讨论】:
【参考方案7】:这是有效的,因为 Bar
对 Foo
类可见。这样就可以编译了。
当然另一个类看不到Bar
,因此不能使用返回值。
但是另一个类仍然可以直接调用方法而不使用返回值。
public class FooBar
public void invokeBar()
Foo foo = new Foo();
foo.getBar();
【讨论】:
@JqueryLearner 好的,我更新了,以免混淆其他人。对于命名空间,我只是指名称中的空格是有效的。你怎么称呼它? 我也研究过 c#,所以知道命名空间在 c# 中的含义 @JqueryLearner 我相信你知道。我只是问你是否知道它在java中通常是如何调用的。我认为命名空间对 java 也有好处。【参考方案8】:内部类
内部类代表一种特殊类型的关系,它可以访问外部类的所有成员(数据成员和方法),包括私有的。嵌套类可以导致代码更具可读性和可维护性,因为它在逻辑上仅将类分组到一个位置。
【讨论】:
以上是关于私有类作为公共方法的返回类型的主要内容,如果未能解决你的问题,请参考以下文章