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

时间:2013-12-16 12:29:34

标签: java polymorphism access-modifiers

为什么这有效?

Foo.java

public class Foo {

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

    private class Bar {}

}

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

8 个答案:

答案 0 :(得分:9)

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

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

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

如果传递的Object被用作传递但从未操作的“句柄”,则可能希望这样做。在这种情况下,虽然让课程public更有意义,但要在其中private制作所有方法,以防止它们在课堂外作用(或定义public返回的接口,让private类实现该。)。

所以答案似乎是:

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

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

Exporting non-public type through public API

答案 1 :(得分:3)

  

为什么这有效?

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

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

答案 2 :(得分:1)

public class Foo {

    private String myString;

    public String getMyString() {
        return myString;
    }

}

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

制作Bar private只会让外部世界看不到它,就像制作字段private一样。

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

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

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

答案 3 :(得分:1)

这是有效的,因为Bar类可以看到Foo。因此它编译。<​​/ p>

当然另一个班级看不到Bar,因此无法使用返回值。

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

public class FooBar {

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

内部课程

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

答案 6 :(得分:0)

它是嵌套类型的一种形式。这种类声明称为内部类。如果将内部类声明为static,那么它将被称为顶级嵌套类。 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类的上述示例所述。没有Transaction对象,Accounts不能存在。

答案 7 :(得分:0)

我有一个非常有效的用例,很高兴这被允许。

让我们留下一个创建UI片段的类。它接受某种域对象并创建一个UI:

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

BasePanelNode的子类,并且是与调用者无关的一些内部类,因为此类确定了外观。

现在,当我需要支持一个新对象PersonalProfile时,我需要重用该类的一部分,该对象不仅包含更多信息,而且还包含基本的Person数据:< / p>

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 {
}