导读:本期聚焦于大象创作的《如何在 Java 中跨包访问并打印另一个包中方法返回的数组?》,敬请观看详情。在 Java 项目里,不同包之间的类要互相调用并不复杂,但容易卡在权限修饰符和数组打印这两个细节上。假设 com.util 包下的 ArrayProvider 类有一个 public 方法返回 int[],业务代码位于 com.app 包,希望拿到数组并输出元素,就需要同时满足几个条件:目标类必须是 public,目标方法也必须是 public,调用方要通过 import 或全限定名正确引用该类。调用成功后得到的数组是一个引用,直接传入 System.out.println 只会看到类似 [I@15db9742 的对象标识,而不是元素内容。正确做法是使用 java.util.Arrays.toString 处理一维数组,或者用循环逐个输出。若返回的是二维数组,则要改用 Arrays.deepToString。本文结合完整代码示例说明跨包调用前的准备工作、返回数组的接收方式,以及多种打印数组内容的方法和常见误区。还会讨论方法返回数组时的封装建议,避免调用方意外修改内部状态。

在 Java 工程中,包的作用除了组织类文件,还承担访问控制边界。跨包访问一个返回数组的方法,看起来只是调用一个方法再打印结果,实际涉及类可见性、方法签名、数组引用传递以及输出格式四个方面。许多人在同一个包里写得顺畅,一旦把工具类拆到其他包就出现无法从外部访问或打印出一串十六进制地址的情况,原因通常不是逻辑错误,而是忽略了 Java 的包隔离规则和数组的 toString 行为。

如何在 Java 中跨包访问并打印另一个包中方法返回的数组?

下文拆成四个环节来梳理:先确认包结构和 public 修饰符,再完成跨包调用,然后解决数组内容打印,最后讨论返回数组时的封装注意事项。

跨包访问的前提:包结构与 public 权限

Java 的包使用 package 关键字声明,源文件第一行没有 package 语句时属于默认包。默认包中的类不能被显式 import,因此真实项目中应避免使用默认包。跨包访问的首个条件是目标类必须声明为 public。一个类的声明如果写成 class ArrayProvider,它的可见性就仅限于当前包,其他包即使 import 了包名也无法访问。同理,目标方法也必须使用 public 修饰符,否则外部包无法调用。

下面先给出一个位于 com.util 包的数组提供类。该类只有一个 public 方法 getNumbers,返回一个 int 数组。注意类和方法都是 public,这是跨包调用的最低要求。

package com.util;

public class ArrayProvider {
    private int[] numbers = {12, 7, 35, 18, 29};

    public int[] getNumbers() {
        return numbers;
    }
}

如果把 public class 改成 class,或者把 public int[] getNumbers 改成 int[] getNumbers,那么另一个包中的类在编译阶段就会报错。常见报错信息包括 ArrayProvider is not public in com.util 和 getNumbers() is not public in com.util; cannot be accessed from outside package。理解这些提示可以快速定位权限问题。

在另一个包中导入并接收返回的数组

调用方放在 com.app 包中,需要先 import com.util.ArrayProvider,也可以不 import 而使用全限定名 com.util.ArrayProvider。导入后创建对象并接收方法返回值。因为数组在 Java 中属于引用类型,所以 int[] result 拿到的是 ArrayProvider 内部 numbers 数组的引用,而不是数组副本。

下面是一个完整的调用示例,包名与上一个示例不同,类名为 Main。代码中先实例化 ArrayProvider,再通过 getNumbers 获取数组,然后打印数组的长度和元素内容。

package com.app;

import com.util.ArrayProvider;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        ArrayProvider provider = new ArrayProvider();
        int[] result = provider.getNumbers();

        System.out.println("数组长度:" + result.length);
        System.out.println("数组内容:" + Arrays.toString(result));
    }
}

这里有一个很容易误解的地方:方法返回的是数组引用,而不是重新创建的新数组。调用方如果执行 result[0] = 100,ArrayProvider 内部保存的 numbers 数组也会改变。如果希望跨包调用时不暴露内部数组,可以在 getter 中返回数组的克隆,比如 return numbers.clone(),这样外部修改不会影响原对象。

另外,跨包调用时还需要注意 classpath 或模块路径是否正确。在命令行编译时,应该先编译 com/util 下的类,再编译 com/app 下的类,运行时要保证根目录在 classpath 中。比如在 src 目录下执行 javac com/util/ArrayProvider.java com/app/Main.java,然后 java com.app.Main。

打印数组的几种方式与常见误区

直接执行 System.out.println(result) 会输出类似 [I@15db9742 的内容。这是因为数组的 toString 方法继承自 Object,默认实现返回类名加哈希码,并不展示数组元素。要输出元素,最快捷的方式是使用 java.util.Arrays.toString。它会把一维数组格式化为类似 [12, 7, 35, 18, 29] 的字符串。

如果数组是二维或更高维度,Arrays.toString 只能打印外层数组的引用地址,还是会出现 [I@... 这样的内容。此时必须使用 Arrays.deepToString。例如一个 int[][] 二维数组,用 deepToString 可以得到 [[1, 2], [3, 4]] 的效果。下面代码对比了一维和二维数组的不同打印方式。

import java.util.Arrays;

public class PrintArrayDemo {
    public static void main(String[] args) {
        int[] oneDim = {10, 20, 30};
        int[][] twoDim = {{1, 2}, {3, 4}};

        System.out.println("错误打印一维:" + oneDim);
        System.out.println("正确打印一维:" + Arrays.toString(oneDim));
        System.out.println("错误打印二维:" + twoDim);
        System.out.println("正确打印二维:" + Arrays.deepToString(twoDim));
    }
}

除了 Arrays 工具类,传统 for 循环和增强 for 循环也常用于打印数组。对数组元素逐个输出可以方便地控制格式,但也需要手动处理分隔符。Arrays.toString 已经足够满足绝大多数日志和调试需求。如果数组可能为 null,直接调用 Arrays.toString 会抛出 NullPointerException,因此打印前应判断 result != null。

跨包返回数组的封装建议

从包设计角度看,直接返回内部数组会让外部代码获得修改内部状态的能力,破坏封装性。即便是同一个团队内部的工具类,也建议区分只读访问和可修改访问。对于只读场景,可以返回数组的副本,或返回 List 的不可变视图。对于性能敏感的场景,如果数据量很大,可以返回数组引用但通过文档约定不得修改,不过这种约定不如代码约束可靠。

另一种做法是不直接暴露数组,而是提供打印方法或遍历方法。例如 ArrayProvider 增加一个 printNumbers 方法,内部使用 Arrays.toString 输出。这样调用方只需要调用 provider.printNumbers(),无需关心数组如何跨包传递。但有时调用方需要拿到数组做进一步计算,这时返回副本更安全。

跨包访问数组并不复杂,复杂的是把可见性、引用语义和输出格式三者同时处理正确。只要类和方法都是 public,调用方正确 import,再使用 Arrays.toString 或 deepToString 打印,就能避免大部分开发中的小坑。若还需要保护数据完整性,返回副本或不可变视图是更稳妥的选择。

Java跨包访问数组打印访问修饰符修改时间:2026-10-05 04:49:23

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1005/65850.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。