【问题标题】:What about public method returns private class instance?公共方法返回私有类实例呢?
【发布时间】:2013-04-05 18:16:47
【问题描述】:

我正在尝试测试以下情况:

  1. 有一个主要的。 (city.Main)
  2. 有一个包。 (package castle)
  3. 在包中,有一个公共类 (castle.Guard) 和一个 package-private 类 (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 条语句都有错误。

我也做过一些研究。事实上我想模仿this answer。但我不明白为什么我的代码会抛出错误。

感谢您的任何解释!


编辑:

我打算将castle-Princess 包私有。我知道,通过从包中返回一个 package-private 类,我应该为错误做好准备。但是为什么that answer 有效,而我的无效?

【问题讨论】:

标签: java class package private public


【解决方案1】:

Princess 类默认范围为 castle 包,因此它在 city 包中不可见。为了避免这种情况:

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

1) 制作Princesspublic 并使用它。

package castle;

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

2) 或者,定义一个 public interface 并让 Princess 实现它并使用 interface reference 而不是 class reference 。我更喜欢这个。

城堡\IPrincess.java

// Interface definition
package castle;

public interface IPrincess {
    public void sayHi();
}

城堡\Princess.java

// Implement the interface in Princess class
package castle;

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

城堡\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) 或者,将所有类放在同一个包中。

【讨论】:

  • 这真是一个不错的解决方案!!请允许我编辑您的答案以提高可读性:-)
【解决方案2】:

您将无法返回在类中私有作用域的类型。如果它是另一个类的私有范围,任何外部来源怎么能知道该类型是什么?

这个设计甚至无法编译。

编辑:

简单的解决方案是将其公开,然后您可以在包外部使用它。

【讨论】:

    【解决方案3】:

    您试图模仿的答案是有效的,因为所有类都在同一个包中

    如果您将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 想要说明的只是返回一个私有成员变量,而不是一个私有类,这并不是真正特殊的 IMO(我们所有的 getter 方法都这样做)。
    • @midnite: @Andy 说 “但是,仍然可以从 UntrustworthyFriend 内部调用 Secret 上的方法。” 不过,这仅适用于 SecretUntrustworthyFriend 可见。只有当Secretpublic 或与UntrustworthyFriend 在同一个包中时才会如此。
    • @acdc 初级:是的。在UntrustworthyFriend.main(),我什至可以做System.out.println( (new Secret("blah")).reveal() );。我根本不需要Friend:-/
    • 确实如此。有了 stackoverflow,谁还需要朋友? :)
    【解决方案4】:

    问题在于您的 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 修饰符,公主类不能在声明它的文件之外被访问。

    【讨论】:

      【解决方案5】:

      您的示例不同,因为您的类位于不同的包中,而 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 之前实现的技巧吧?
      猜你喜欢
      • 2011-07-21
      • 2014-11-20
      • 2014-01-03
      • 1970-01-01
      • 1970-01-01
      • 2011-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多