有没有办法将嵌套类放在单独的文件中?

问题描述 投票:0回答:4

我有一个大约 4,000 行长的 Java 类(有很多方法)。然后这个类使用了大约 200 个它需要的小类,所以又需要 4,000 行代码。

如果这是 C#,我会将其他内容放入部分类文件(不同的文件)中,但它们将保留私有嵌套类,仅对父类可见。

有没有办法在Java中做到这一点?我并不是要求某些方法位于不同的文件中,而是要求私有嵌套类位于不同的文件中。

java unit-testing junit junit5 partial-classes
4个回答
3
投票

您不能将一个类仅对另一个类私有,同时将其放入不同的文件中。

不使用类访问修饰符

您可以做的是将这些类放在没有访问修饰符的单独文件中(省略“public”),这将使它们成为包私有的,即仅在其自己的包中可见。另请参阅官方访问控制教程

UtilClasses.java:

package OurPackage;

class UtilClass1
{
}
class UtilClass2
{
}

MainClass.java:

package OurPackage;

public class MainClass
{
   UtilClass1 iAmAUtilClass;
}

使用接口或继承

您还可以通过省略嵌套类中的访问修饰符,使用接口或继承来实现类似的效果。这也将是包私有的,但在某些情况下这可能比上面的更好,因为它避免了所有嵌套类都位于顶层。

BaseInterface.java:

package OurPackage;

interface BaseInterface
{
   class UtilClass1
   {
   }
}

MainClass.java:

package OurPackage;

public class MainClass implements BaseInterface
{
   UtilClass1 iAmAUtilClass;
}

您还可以使用基类代替接口并扩展它,效果大致相同。

您不需要实现

BaseInterface
即可访问其嵌套类,但是,如果您不这样做,则需要使用
BaseClass.UtilClass1
而不仅仅是
UtilClass1


1
投票

内部私有类无法“提取”,并且仍然仅对一个特定类可见。评论中已经提到了一种解决方案:创建一个包含“主”类和所有先前内部类的包,并使内部类包可见。这还允许您创建单元测试来测试内部类的正确功能,这目前很可能不会发生,因为单元测试目前无法“到达”内部类。

Java 中不存在像 C++ 中那样在类之间声明“友谊”的概念。


0
投票

您可以用顶级内部类替换内部类,但是您必须手动重写编译器自动为您连接内部类关系的许多内容。对于虚拟机来说,内部类没有什么特别的,它只是与外部类位于同一包中的另一个类,具有一个奇特的名称。但是编译器在底层创建了很多帮助器构造,您必须手动重建它们(或者使用一些重构工具为您做这件事):

  • 内部类可以通过在外部类名称前面加上前缀来引用外部
    this
    实例。您需要将外部
    this
    传递到内部构造函数中,并将其存储在像
    outerThis
    这样的字段中才能访问。
  • 在源码中,可以直接调用外部类的方法。你需要像
    outerThis.method()
    一样重写它。这同样适用于字段。
  • 为了使私有外部方法和字段变得可访问,编译器会为您创建桥接结构。您必须更改访问修饰符或自己创建包私有桥接方法。

最终,您将拥有以前的内部类,至少是包可见的,并且比原始内部类更详细,但另一方面,您将获得更好的隔离性和可测试性。


0
投票

这里有一种使用 JUnit 5 来实现这一点的方法(在 Kotlin 中,但稍作修改也应该适用于 Java)。

MyContainerTest.kt(或.java)文件:

class MyContainerTest {
    @Nested inner class MyNestedTestsOne : MyNestedTest1()

    @Nested inner class MyNestedTestsTwo : MyNestedTest2()

    // Can also have regular unit tests
    @Test
    fun myUnitTestInContainer() { /* ... */ }

    @Test
    fun myOtherUnitTestInContainer() { /* ... */ }
}

MyNestedTest1.kt(或.java)文件:

abstract class MyNestedTest1 {
    @Test
    fun myUnitTestInNestedClass1() { /* ... */ }
}

MyNestedTest2.kt(或.java)文件:

abstract class MyNestedTest2 {
    @Test
    fun myUnitTestInNestedClass2() { /* ... */ }
}

嵌套测试类已被提取到单独的文件中,然后在所需的容器类中,已创建从这些类继承的占位符嵌套类。这样,它们在测试视图和报告中显示为容器测试类的子层次结构。

注意:使这些嵌套类抽象以避免运行它们两次。

参见https://github.com/junit-team/junit5/issues/1750

© www.soinside.com 2019 - 2024. All rights reserved.