公共方法返回私有类实例怎么办?

3
我正在尝试测试以下情况:
  1. 有一个主类(city.Main)。
  2. 有一个包(package castle)。
  3. 在该包中,有一个公共类(castle.Guard)和一个包私有类(castle.Princess)。
  4. 如果公共类返回私有类的实例会怎样?
这是我的代码: Main.java
package city;

import castle.Guard;

public class Main {

    public static void main(String[] args) {
        Princess princess = Guard.getPrincessStatic();
        // Error: Princess cannot be resolved to a type
        
        Guard.getPrincessStatic().sayHi();
        // Error: The type Princess is not visible
        
        Guard guard = new Guard();
        guard.getPrincess().sayHi();
        // Error: The type Princess is not visible
        
        guard.getPrincessMember().sayHi();
        // Error: The type Princess is not visible
    }

}

Guard.java

package castle;

public class Guard {

    public Princess getPrincess() {
        return new Princess();
    }

    public static Princess getPrincessStatic() {
        return new Princess();
    }
    
    private Princess m_princess = new Princess();
    
    public Princess getPrincessMember() {
        return m_princess;
    }
}

Princess.java

package castle;

class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

请注意,main() 中的所有 4 条语句都有错误。

我也做了一些研究。实际上,我想模仿这个答案。但是我不知道为什么我的代码会抛出错误。

感谢任何解释!


编辑:

我打算将 castle-Princess 设为包私有。我知道,通过返回其包外的包私有类,我应该做好准备迎接错误。但为什么那个答案能够工作,而我的却不能呢?


错误基本上是在说“private意味着私有!”这些链接可能会有所帮助:Java语言规范:可见性,https://dev59.com/JFTTa4cB1Zd3GeqPw-2r,[可见性和耦合](http://www.leepoint.net/JavaBasics/oop/oop-70-visibility.html)。 - paulsm4
5个回答

5

Princess类是默认作用域为castle包的,因此在city包中不可见。为了规避这个问题:

(我们可以采取以下三种方法之一。)

1)将Princess类设置为public并使用它。

package castle;

// added public modifier
public class Princess {
     public void sayHi() { System.out.println("Hi world"); }
}

2) 或者,定义一个公共接口,并让Princess实现它并使用接口引用而不是类引用。我更喜欢这个方法。

castle \ IPrincess.java

// Interface definition
package castle;

public interface IPrincess {
    public void sayHi();
}

城堡/公主.java

// Implement the interface in Princess class
package castle;

class Princess implements IPrincess {
    public void sayHi() { System.out.println("Hi world"); }
}

castle \ Guard.java

// Modify the Guard class
package castle;

public class Guard {
    public IPrincess getPrincess() {
        return new Princess();
    }
    public static IPrincess getPrincessStatic() {
        return new Princess();
    }

    // for here i use Princess instead of IPrincess. (@midnite)
    private Princess m_princess = new Princess();
    public IPrincess getPrincessMember() {
        return m_princess;
    }
}

城市\ Main.java

// Modify the main class
  package city;

  import castle.Guard;
  import castle.IPrincess;

  public class Main {

  public static void main(String[] args) {

     IPrincess princess = Guard.getPrincessStatic();

     Guard.getPrincessStatic().sayHi();

     Guard guard = new Guard();
     guard.getPrincess().sayHi();

     guard.getPrincessMember().sayHi();
   }
}

3) 或者,将所有类放在同一个包中。


(注:此为技术相关内容,建议有基础的读者阅读。)

这真是一个不错的解决方案!请允许我稍微编辑一下你的答案,以便更易读 :-) - midnite

1
您试图模仿的答案之所以有效,是因为所有类都在同一个包中
如果您将UntrustworthyFriendFriend放在不同的包中(如您的情况),则会出现相同的问题。 Princess只有在public的情况下才能在其包外可见:

Princess.java

package castle;

public class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

此外,请确保在 Main 中导入它。

你是对的!如果我把 UntrustworthyFriend.javaFriend.java 放在不同的包中,那么 friendWithSecret.getMySecret().reveal() 这一行会报错:The type Secret is not visible。所以,在我看来,@Andy 想要说明的只是返回一个私有成员变量,而不是一个私有类,这并不是特别特殊(我们所有的 getter 方法都是这样做的)。 - midnite
@midnite: @Andy说:“然而,在UntrustworthyFriend内部仍然可以调用Secret的方法。”但是,这仅在SecretUntrustworthyFriend可见时才成立。只有当Secretpublic或与UntrustworthyFriend在同一包中时,它才会被看到。 - acdcjunior
@acdc junior:是啊,在 UntrustworthyFriend.main() 中,我甚至可以使用 System.out.println( (new Secret("blah")).reveal() );。我根本不需要一个“朋友”:-/ - midnite
确实。当你有stackoverflow时,谁还需要朋友呢? :) - acdcjunior

1
你无法返回一个在类内私有范围的类型。如果它在另一个类内部私有化,任何外部源如何知道它是什么类型?
这种设计甚至无法编译。
编辑:
简单的解决方案是将其公开,然后可以在包外部使用它。

0
问题出在您的 Princess 类的定义中一个非常小的错误:
package castle;

class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

一开始看起来都很好,但是你在类名前面缺少了一个 public 修饰符:
package castle;

//here!
public class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

如果没有public修饰符,那么公主类就无法在声明它的文件之外被访问。


0

你的例子不同,因为你的类在不同的包中,而且 Guard 和 Princess 从 Main 中不可见。

但是公共方法可以返回私有类的实例。JDK 中充满了这样的例子,这里是一个来自 java.util.Arrays 的例子。

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}
...
private static class ArrayList<E> extends AbstractList<E>  {
...

这就是你所要求的。诀窍在于该方法的返回类型是公共接口,而私有类实现了它。你可以做类似的事情。


谢谢@ED。这很有趣!我猜这应该是之前@noob实现的技巧? - midnite

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接