简体   繁体   English

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

[英]Private class as return type from public method

Why is this valid? 为什么这个有效?

Foo.java Foo.java

public class Foo {

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

    private class Bar {}

}

If Bar is private, how will users of this class use this method? 如果Bar是私有的,那么这个类的用户将如何使用此方法? Polymorphism can be used of course, but shouldn't this be invalid and the declaration should indicate this as returning an Object? 当然可以使用多态,但这不应该是无效的,并且声明应该指出这是返回一个对象吗?

I've just been doing a bit of research on this and have not been able to find a definitive answer. 我刚刚对此进行了一些研究,但未能找到明确的答案。 It seems most likely that it is just an oversight on the part of the Java language designers and since it doesn't actually do any harm it has been left. 它似乎很可能只是Java语言设计者的疏忽,因为它实际上并没有造成任何伤害。 It's no different really from putting a public method into a private class. public方法放入private类并没有什么不同。 Nothing stops you doing this, even though there is no way to actually access that public method. 即使没有办法实际访问该public方法,也没有什么能阻止你这样做。

Certainly NetBeans gives you the warning "Exporting non-public type through public API" when you try to do this. 当然,当您尝试执行此操作时,NetBeans会向您发出警告“通过公共API导出非公共类型”。 I expect most other environments will give a similar warning. 我希望大多数其他环境会发出类似的警告。

The returned object is entirely useless to anyone who tries to use it (unless they use reflection), pretty much all they can do is store it into an Object (or any other super class that they do have access to) and then pass that Object around. 返回的对象对尝试使用它的人来说完全没用(除非他们使用反射),他们几乎所能做的就是将它存储到一个Object (或者他们有权访问的任何其他超类)中,然后传递该Object周围。

You could potentially want to do this if the passed Object is being used as a "handle" that gets passed around but never operated on. 如果传递的Object被用作传递但从未操作过的“句柄”,您可能希望这样做。 In that case though it would still make much more sense to have the class public but make all the methods within it private to prevent them being acted on outside your class (or define a public interface to return and have the private class implement that). 在这种情况下,尽管将类public但将其中的所有方法设置为private以防止它们在类外部执行(或定义返回的public接口并使private类实现该方法)仍然更有意义。

So the answer seems to be: 所以答案似乎是:

It probably shouldn't be valid, but as it doesn't do any harm it has never been blocked. 它可能不应该有效,但因为它没有造成任何伤害,它从未被阻止过。

There is a good answer here on a similar subject: 对于类似的主题,这里有一个很好的答案:

Exporting non-public type through public API 通过公共API导出非公共类型

Why is this valid? 为什么这个有效?

Because client code in the call place might be expecting an Object (or not expecting anything at all), there is no problem with calling this method from anywhere: 因为调用位置中的客户端代码可能期望一个Object (或根本不期望任何东西),所以从任何地方调用此方法都没有问题:

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

    private String myString;

    public String getMyString() {
        return myString;
    }

}

This is valid as well. 这也是有效的。 Why should inner classes behave differently? 内部类为什么表现不同?

Making Bar private only makes it invisible to the outside world just as making fields private . 使Bar private只会让外部世界看不到,就像将字段设为private

One important caveat is that even if you are able to call getBar() on a Foo object you can't call methods of that reference (because of the visibility). 一个重要的警告是,即使您能够在Foo对象上调用getBar() ,也无法调用该引用的方法(因为可见性)。

So the main thing is that you can do that but you should not do so. 所以主要的是你可以这样做,但你不应该这样做。

The only situation I can imagine is when Foo is also an inner class and the outer class of Foo wants to use Bar . 我能想象的唯一情况是当Foo也是一个内部类而Foo的外部类想要使用Bar

It is valid because Bar is visible to the Foo class. 它是有效的,因为BarFoo类是可见的。 Thus it compiles. 因此它编译。

Of course another class can not see Bar and thus can not use the return value. 当然另一个类看不到Bar ,因此不能使用返回值。

But another class can still just invoke the method without using the return value. 但是另一个类仍然可以在不使用返回值的情况下调用该方法。

public class FooBar {

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

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

Inner class 内心阶级

Inner classes represent a special type of relationship that is it can access all the members (data members and methods) of outer class including private. 内部类表示一种特殊类型的关系,它可以访问外部类的所有成员(数据成员和方法),包括私有。 Nested classes can lead to more readable and maintainable code because it logically group classes in one place only. 嵌套类可以使代码更具可读性和可维护性,因为它仅在一个地方对逻辑上的类进行分组。

It is one of the form of nested types. 它是嵌套类型的一种形式。 This kind of class declaration is known as inner class. 这种类声明称为内部类。 If you declare the inner class as static, then it would be known as top-level nested class. 如果将内部类声明为static,那么它将被称为顶级嵌套类。 Other forms of nested types available in Java are local class; Java中可用的其他形式的嵌套类型是本地类; class declared and defined within a block,ie, a method or a constructor or an initializer block. 在块中声明和定义的类,即方法或构造函数或初始化块。 The fourth form of nested type is anonymous class; 嵌套类型的第四种形式是匿名类; a class without any name whose object is used where the class is defined. 没有任何名称的类,其对象用于定义类的位置。

As far as your case is considered, ie, inner class all the classes within a class can be declared with public, private and protected access specifiers. 就您的情况而言,即内部类,可以使用public,private和protected访问说明符声明类中的所有类。 All the classes with in the enclosing class as well as enclosing class itself share a trust relationship. 封闭类中的所有类以及封闭类本身都共享信任关系。 That means, all the private members of inner class as well as private members of enclosing class is shared among each other. 这意味着,内部类的所有私有成员以及封闭类的私有成员彼此共享。 However you cannot access the object of inner class without an object of enclosing class. 但是,如果没有封闭类的对象,则无法访问内部类的对象。

When you will try to create an object of inner class compiler would report a compile-time error. 当您尝试创建内部类编译器的对象时,将报告编译时错误。 However following example access the private members of each other class, ie, enclosing class access private members of inner class and inner class access private members of enclosing class : 但是下面的示例访问每个其他类的私有成员,即封闭类访问内部类的私有成员和内部类访问封闭类的私有成员:

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

Best example you could have for an inner class is the relationship of an Accounts class which is enclosing class and Transaction class which is inner class. 内部类的最佳示例是包含类的Accounts类与作为内部类的Transaction类的关系。 One Accounts class can have more than one Transaction objects but Transaction object cannot exist without Accounts object. 一个Accounts类可以有多个Transaction对象,但没有Accounts对象,Transaction对象不能存在。

Albeit, returning an object of private inner class is useless as it becomes invisible outside its class. 尽管如此,返回私有内部类的对象是无用的,因为它在类之外变得不可见。 As the above example of Accounts and Transaction class explains. 正如上面的AccountsTransaction类的例子所解释的那样。 Transaction cannot exists without Accounts object. 没有Accounts对象, Transaction不能存在。

I have a perfectly valid use case for this, and I'm glad this is allowed. 我有一个完全有效的用例,我很高兴这是允许的。

Let's stay you have a class that creates UI pieces. 让我们留下一个创建UI片段的课程。 It accepts somekind of domain object and creates a piece of UI: 它接受一些域对象并创建一个UI:

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

BasePanel is a subclass of Node and is some internal class that the caller has no business with, as this class determines how things will look. BasePanelNode的子类,是调用者没有业务的内部类,因为这个类决定了事物的外观。

Now, I found myself needing to re-use part of this class when I needed to support a new object, PersonalProfile that contains much more information, but also contains the basic Person data: 现在,当我需要支持一个包含更多信息的新对象PersonalProfile时,我发现自己需要重新使用这个类的一部分,但是还包含基本的Person数据:

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

However, that code was partially duplicated, so I did: 但是,该代码部分重复,所以我做了:

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

The cast however is a bit ridiculous -- changing it to return BasePanel not only works, but doesn't expose any functionality of my private class. 然而,演员BasePanel有点荒谬 - 将其更改为返回BasePanel不仅有效,而且不会暴露我的私人类的任何功能。 Instead it only exposes the methods from any public classes it inherits from... brilliant! 相反,它只从它继承的任何公共类中公开方法......非常棒!

Full code: 完整代码:

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