Java:Subpackage可见性?

时间:2009-12-27 22:28:56

标签: java package visibility encapsulation

我的项目中有两个包:odp.projodp.proj.test。我希望某些方法只对这两个包中的类可见。我怎么能这样做?

编辑:如果Java中没有子包的概念,有什么方法可以解决这个问题吗?我有一些方法,我希望只有测试人员和该软件包的其他成员才能使用。我应该把所有东西扔进同一个包里吗?使用广泛的反思?

9 个答案:

答案 0 :(得分:150)

你做不到。在Java中没有子包的概念,所以odp.proj和odp.proj.test是完全独立的包。

答案 1 :(得分:55)

您的软件包名称暗示此处的应用程序用于单元测试。使用的典型模式是将您要测试的类和单元测试代码放在同一个包中(在您的情况下为odp.proj),但是在不同的源树中。因此,您可以将课程放在src/odp/proj中,将测试代码放在test/odp/proj

Java确实有“package”访问修饰符,当没有指定时,它是默认的访问修饰符(即,你没有指定public,private或protected)。使用“package”访问修饰符,只有odp.proj中的类才能访问这些方法。但请记住,在Java中,不能依赖访问修饰符来强制执行访问规则,因为通过反射,可以进行任何访问。访问修饰符仅仅是暗示性的(除非存在限制性安全管理器)。

答案 2 :(得分:11)

odp.projodp.proj.test之间没有特殊关系 - 它们恰好被命名为显然相关。

如果odp.proj.test包只是提供测试,那么您可以使用相同的包名称(odp.proj)。像Eclipse和Netbeans这样的IDE将创建具有相同包名但具有JUnit语义的单独文件夹(src/main/java/odp/projsrc/test/java/odp/proj)。

请注意,这些IDE将为odp.proj中的方法生成测试,并为不存在的测试方法创建相应的文件夹。

答案 3 :(得分:5)

当我在IntelliJ中执行此操作时,我的源代码树如下所示:

src         // source root
- odp
   - proj   // .java source here
- test      // test root
  - odp
     - proj // JUnit or TestNG source here

答案 4 :(得分:4)

  

编辑:如果没有概念   Java中的子包,有什么办法   在这附近?我有一些方法   我希望只有   测试人员和其他成员   封装

这可能取决于你不显示它们的动机,但如果唯一的原因是你不想用仅用于测试的东西(或其他一些内部物品)污染公共接口,我会把单独的公共接口中的方法,并让“隐藏”方法的使用者使用该接口。它不会阻止其他人使用界面,但我认为没有理由你应该这样做。

对于单元测试,如果可以不重写批次,请按照建议使用相同的包。

答案 5 :(得分:4)

这里的大多数答案都表明Java中没有子包之类的东西,但这并不是严格准确的。自第一个版本以来,该术语就出现在Java Language Specification(JLS)中。自初始版本以来,JLS中子软件包的描述没有太大变化。

Java 15 JLS

包的成员是其子包,并且在包的所有编译单元中声明了所有顶级类类型和顶级接口类型。

例如,在Java SE Platform API中:

  • java具有子包awtappletiolangnet和{{1} },但没有编译单元。
  • 软件包util有一个名为java.awt的子软件包,以及许多包含类和接口类型的声明的编译单元。

子包概念具有实际意义,因为它在包与类/接口之间强制实施命名约束:

一个程序包不能包含两个相同名称的成员,否则会导致编译时错误。

以下是一些示例:

  • 因为软件包image有一个子软件包java.awt,所以它不能(也没有)包含名为image的类或接口类型的声明。
  • 如果其中有一个名为image的程序包,并且该程序包中的成员类型为mouse(然后可能称为Button),则不能有任何程序包完全限定名称为mouse.Buttonmouse.Button
  • 如果mouse.Button.Click是类型的完全限定名称,则不能存在任何完全限定名称为com.nighthacks.java.jagcom.nighthacks.java.jag的程序包。 < / li>

但是,这种命名限制是语言给子包提供的 only 含义。

包的分层命名结构旨在方便以常规方式组织相关的包,但除禁止具有与声明的顶级类型具有相同简单名称的子包的包外,其本身没有其他意义。在那个包装中。

例如,在名为com.nighthacks.java.jag.scrabble的程序包和名为oliver的另一个程序包之间,或在名为oliver.twistevelyn.wood的程序包之间没有特殊的访问关系。也就是说,与其他任何软件包中的代码相比,名为evelyn.waugh的软件包中的代码无法更好地访问在软件包oliver.twist中声明的类型。


在这种情况下,我们可以回答问题本身。由于程序包及其子程序包之间或父程序包的两个不同子程序包之间没有特殊的访问关系,因此该语言中没有办法以所请求的方式使方法对两个不同的程序包可见,同时限制了对它的访问。其他包装。这是有据可查的故意设计决定。

或者可以将该方法设为公开,并且所有程序包(包括oliverodp.proj)都可以访问给定的方法,或者可以将该方法设为私有程序包(默认可见性),并且所有需要直接访问它的代码都必须与该方法放在同一(子)包中。

关于测试用例,Java中非常标准的做法是将类型的测试代码与其源代码放在同一包中,但放在文件系统上的不同位置。例如,在Maven构建工具中,约定是将源文件放入odp.proj.test,将测试文件放入 src/main/java/odp/proj。当使用构建工具进行编译时,两个目录中的项目最终都以src/test/java/odp/proj包结尾,但是生产工件中仅包含odp.proj文件。测试文件仅在构建时用于验证生产文件。通过此设置,测试代码可以自由访问正在测试的代码的任何程序包私有或受保护代码,因为它们将在同一程序包中。

在非测试/生产情况下要跨子包或同级包共享代码的情况下,我看到一些库使用的一种解决方案是将共享代码公开,但要记录它的意图仅供内部库使用。

答案 6 :(得分:2)

正如其他人所解释的那样,Java中没有“子包”这样的东西:所有包都是孤立的,并且不会从父母那里继承任何东西。

从另一个包访问受保护类成员的简单方法是扩展类并覆盖成员。

例如,要访问包ClassInA中的a.b

package a;

public class ClassInA{
    private final String data;

    public ClassInA(String data){ this.data = data; }

    public String getData(){ return data; }

    protected byte[] getDataAsBytes(){ return data.getBytes(); }

    protected char[] getDataAsChars(){ return data.toCharArray(); }
}

在该程序包中创建一个类,该类将覆盖ClassInA中所需的方法:

package a.b;

import a.ClassInA;

public class ClassInAInB extends ClassInA{
    ClassInAInB(String data){ super(data); }

    @Override
    protected byte[] getDataAsBytes(){ return super.getDataAsBytes(); }
}

这使您可以使用覆盖类代替其他包中的类:

package a.b;

import java.util.Arrays;

import a.ClassInA;

public class Driver{
    public static void main(String[] args){
        ClassInA classInA = new ClassInA("string");
        System.out.println(classInA.getData());
        // Will fail: getDataAsBytes() has protected access in a.ClassInA
        System.out.println(Arrays.toString(classInA.getDataAsBytes()));

        ClassInAInB classInAInB = new ClassInAInB("string");
        System.out.println(classInAInB.getData());
        // Works: getDataAsBytes() is now accessible
        System.out.println(Arrays.toString(classInAInB.getDataAsBytes()));
    }
}

请注意,这仅适用于对扩展类(继承)可见的受保护成员,而不适用于仅对同一包中的子/扩展类可见的包私有成员。希望这有助于某人!

答案 7 :(得分:0)

如果不将访问修饰符放在方法前面,则表示它是包私有的 请看下面的例子。

package odp.proj;
public class A
{
    void launchA() { }
}

package odp.proj.test;
public class B
{
    void launchB() { }
}

public class Test
{
    public void test()
    {
        A a = new A();
        a.launchA()    // cannot call launchA because it is not visible
    }
}

答案 8 :(得分:0)

使用PackageVisibleHelper类,并在PackageVisibleHelperFactory冻结之前将其保密,我们可以在任何地方调用launchA(通过PackageVisibleHelper)方法:)

RestartService
相关问题