Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 作为公共方法返回类型的私有类_Java_Polymorphism_Access Modifiers - Fatal编程技术网

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

Java 作为公共方法返回类型的私有类,java,polymorphism,access-modifiers,Java,Polymorphism,Access Modifiers,为什么这是有效的 Foo.java public class Foo { public Bar getBar() { return new Bar(); } private class Bar {} } 如果Bar是私有的,这个类的用户将如何使用这个方法?当然可以使用多态性,但这不应该是无效的,并且声明应该将其指示为返回一个对象吗 public class Foo { private String myString; publi

为什么这是有效的

Foo.java

public class Foo {

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

    private class Bar {}

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

public class Foo {

    private String myString;

    public String getMyString() {
        return myString;
    }

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

条设置为私有
只会使外部世界看不到它,就像将字段设置为私有
一样

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

所以最重要的是你可以这样做,但是你不应该这样做


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

它是有效的,因为
Bar
Foo
类可见。它就是这样编译的

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

public class FooBar {

   public void invokeBar() {
        Foo foo = new Foo();
        foo.getBar();
   }
}
但是另一个类仍然可以在不使用返回值的情况下调用该方法

public class FooBar {

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

内部类

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

为什么这是有效的

因为调用位置中的客户端代码可能需要一个
对象(或者根本不需要任何对象),所以从任何地方调用此方法都没有问题:

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

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

它是嵌套类型的一种形式。这种类声明称为内部类。如果您将内部类声明为静态类,那么它将被称为顶级嵌套类。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
类(它是内部类)之间的关系。一个
账户
类可以有多个
交易
对象,但是没有
账户
对象,交易对象就不能存在


尽管如此,返回私有内部类的对象是无用的,因为它在其类之外变得不可见。如上面的
账户
交易
类示例所述<代码>交易
如果没有
账户
对象就不可能存在。

我刚刚对此做了一些研究,还没有找到明确的答案。很可能这只是Java语言设计者的一个疏忽,因为它实际上并没有造成任何伤害,所以它被保留了下来。这与将
public
方法放入
private
类没有什么区别。没有任何东西可以阻止您这样做,即使无法实际访问该
public
方法

当然,当您尝试这样做时,NetBeans会向您发出警告“通过公共API导出非公共类型”。我希望大多数其他环境都会给出类似的警告

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

如果传递的
对象
被用作传递但从未操作的“句柄”,则可能需要执行此操作。在这种情况下,让类
public
更有意义,但是要让类中的所有方法
private
防止它们在类之外被操作(或者定义一个
public
接口返回并让
private
类实现它)

所以答案似乎是:

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

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


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

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

public Node createPersonUI(Person person) {
    BasePanel panel = new BasePanel();
    // ... setup panel with values ...
    return panel;
}
BasePanel
Node
的一个子类,是调用者与之无关的某个内部类,因为该类决定事情的外观

现在,当我需要支持时,我发现自己需要重新使用这个类的一部分
public Node createPersonalProfileUI(PersonalProfile profile) {
    BasePanel panel = (BasePanel)createPerson(profile.getPerson());
    // ... only setup missing values ...
    return panel;
}
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 {
}