Java:Subpackage可见性?

Nic*_*ner 138 java encapsulation visibility package

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

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

sta*_*lue 155

你不能.在Java中没有子包的概念,因此odp.proj和odp.proj.test是完全独立的包.

  • 虽然我喜欢这种方式,但令人困惑的是,大多数IDE都将具有相同名称的包放在一起.谢谢你的澄清. (7认同)

Asa*_*aph 57

包的名称暗示这里的应用程序是用于单元测试.使用的典型模式是将您要测试的类和单元测试代码放在同一个包中(在您的情况下odp.proj),但是在不同的源树中.所以你会把你的课程src/odp/proj和你的测试代码放进去test/odp/proj.

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


M. *_*tin 14

这里的大多数答案都说明Java中没有子包这样的东西,但这并不准确。该术语在Java 语言规范(JLS) 中定义,并且自该规范的初始版本以来一直存在。

Java 15 JLS

包的成员是它的子包以及包的所有编译单元中声明的所有顶级类类型和顶级接口类型。

例如,在 Java SE Platform API 中:

  • 封装java有子包awtappletiolangnet,和util,但没有编译单元。
  • 该包java.awt有一个名为 的子包image,以及许多包含类和接口类型声明的编译单元。

子包概念具有实际意义,因为它强制执行包和类/接口之间的命名约束:

一个包可能不包含两个同名成员,否则会导致编译时错误。

这里有些例子:

  • 因为包java.awt有一个子包image,它不能(也不)包含名为 的类或接口类型的声明image
  • 如果有一个名为的包mouse和该包中的成员类型Button(然后可能称为mouse.Button),则不能有任何具有完全限定名称mouse.Button或 的包mouse.Button.Click
  • 如果com.nighthacks.java.jag是类型的完全限定名称,则不能有任何完全限定名称为com.nighthacks.java.jag或 的包com.nighthacks.java.jag.scrabble

但是,这种命名限制是语言赋予子包的唯一意义:

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

例如,named 包oliver和另一个包namedoliver.twist之间,或者包namedevelyn.wood和包之间没有特殊的访问关系evelyn.waugh。也就是说,与任何其他包中的代码相比,命名包中的代码oliver.twist无法更好地访问包中声明的类型oliver


有了这个背景,我们就可以回答这个问题了。由于包与其子包之间或父包的两个不同子包之间没有特殊的访问关系,因此语言中无法以请求的方式使方法对两个不同的包可见,同时限制其访问其他包。这是一个记录在案的、有意的设计决策。

方法可以公开并且所有包(包括odp.projodp.proj.test)都可以访问给定的方法,或者可以将方法设为包私有(默认可见性),并且所有需要直接访问它的代码都必须放入与方法相同的(子)包。

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

如果您希望跨子包或非测试/生产案例的同级包共享代码,我见过一些库使用的一种解决方案是将该共享代码设为公开,但记录它是用于内部库仅使用。


pet*_*ust 11

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

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

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


duf*_*ymo 5

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

src         // source root
- odp
   - proj   // .java source here
- test      // test root
  - odp
     - proj // JUnit or TestNG source here
Run Code Online (Sandbox Code Playgroud)


ndm*_*m13 5

正如其他人所解释的那样,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(); }
}
Run Code Online (Sandbox Code Playgroud)

在该包中创建一个类来覆盖您需要的方法ClassInA

package a.b;

import a.ClassInA;

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

    @Override
    protected byte[] getDataAsBytes(){ return super.getDataAsBytes(); }
}
Run Code Online (Sandbox Code Playgroud)

这使您可以使用覆盖类代替另一个包中的类:

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()));
    }
}
Run Code Online (Sandbox Code Playgroud)

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