繁体   English   中英

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

[英]Private class as return type from public method

为什么这个有效?

Foo.java

public class Foo {

    public Bar getBar() {
        return new Bar();
    }

    private class Bar {}

}

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

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

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

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

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

所以答案似乎是:

它可能不应该有效,但因为它没有造成任何伤害,它从未被阻止过。

对于类似的主题,这里有一个很好的答案:

通过公共API导出非公共类型

为什么这个有效?

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

Object o = new Foo().getBar();
public class Foo {

    private String myString;

    public String getMyString() {
        return myString;
    }

}

这也是有效的。 内部类为什么表现不同?

使Bar private只会让外部世界看不到,就像将字段设为private

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

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

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

它是有效的,因为BarFoo类是可见的。 因此它编译。

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

但是另一个类仍然可以在不使用返回值的情况下调用该方法。

public class FooBar {

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

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

内心阶级

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

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

就您的情况而言,即内部类,可以使用public,private和protected访问说明符声明类中的所有类。 封闭类中的所有类以及封闭类本身都共享信任关系。 这意味着,内部类的所有私有成员以及封闭类的私有成员彼此共享。 但是,如果没有封闭类的对象,则无法访问内部类的对象。

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

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不能存在。

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

让我们留下一个创建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有点荒谬 - 将其更改为返回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 {
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM