0

0

Java中跨类访问数组与方法:面向对象实践指南

DDD

DDD

发布时间:2025-09-24 12:54:21

|

608人浏览过

|

来源于php中文网

原创

Java中跨类访问数组与方法:面向对象实践指南

本文旨在指导Java初学者如何在不同类之间高效且符合面向对象原则地访问和操作数组与方法,避免对static import的依赖。我们将探讨通过对象实例化(组合)、静态方法调用等多种方式实现跨类协作,并分析其适用场景与最佳实践,以构建结构清晰、可维护的Java应用程序。

理解跨类访问的需求

java编程中,为了保持代码的模块化和可维护性,我们通常会将相关的功能封装在不同的类中。例如,一个类可能专门负责数组的操作(如输入、打印、排序),而另一个主类则负责协调这些操作的执行。当主类需要调用其他类中定义的方法或访问其数据时,就需要掌握正确的跨类访问机制。

原始代码示例展示了一个名为Arrays(为避免与java.util.Arrays混淆,通常建议重命名为ArrayOperations或ArrayUtils)的类,其中包含获取整数数组、打印数组和排序数组的静态方法。主类Main试图直接调用这些方法。虽然static import可以简化静态方法的调用,但有时我们希望遵循更严格的面向对象原则,通过对象实例来交互。

原始 ArrayOperations 类(为清晰起见,已重命名):

import java.util.Scanner;

public class ArrayOperations {

    // 静态Scanner,所有静态方法共享
    public static Scanner scan = new Scanner(System.in);

    // 静态方法:获取用户输入的整数数组
    public static int[] getIntegers(int number) {
        System.out.println("请输入 " + number + " 个整数\r");
        int[] entered = new int[number];
        for(int i = 0; i < entered.length; i++) {
            entered[i] = scan.nextInt();
        }
        return entered;
    }

    // 静态方法:打印数组内容
    public static void printArray(int[] entered) {
        for(int i = 0; i < entered.length; i++) {
            System.out.println("元素 " + i + ", 输入的值为 " + entered[i]);
        }
    }

    // 静态方法:对数组进行降序排序
    public static int[] sortIntegers(int[] entered) {
        // 创建一个副本进行排序,不修改原数组
        int[] sortedArray = new int[entered.length];
        System.arraycopy(entered, 0, sortedArray, 0, entered.length); // 更高效的数组复制

        boolean flag = true;
        int temp;
        while(flag) {
            flag = false;
            for(int i = 0; i < sortedArray.length - 1; i++) {
                if(sortedArray[i] < sortedArray[i + 1]) { // 降序排列
                    temp = sortedArray[i];
                    sortedArray[i] = sortedArray[i + 1];
                    sortedArray[i + 1] = temp;
                    flag = true; // 发生了交换,可能还需要下一轮
                }
            }
        }
        return sortedArray;
    }
}

原始 Main 类:

public class Main {
    public static void main (String[] args) {
        // 直接调用 ArrayOperations 类中的静态方法
        int[] myIntegers = ArrayOperations.getIntegers(5); // 注意:这里需要通过类名调用
        int[] sorted = ArrayOperations.sortIntegers(myIntegers);
        ArrayOperations.printArray(myIntegers);
        ArrayOperations.printArray(sorted);
    }
}

请注意,即使没有static import,只要ArrayOperations类在同一个包中或被正确导入,Main类也可以通过ArrayOperations.methodName()的形式直接调用其public static方法。用户提出的问题是想了解在不使用static import的情况下,如何以“OOP标准”来访问这些功能。

立即学习Java免费学习笔记(深入)”;

Java中跨类成员访问的几种主要方式

在Java中,实现跨类访问有多种策略,每种策略都有其特定的适用场景和优缺点。

1. 通过对象实例化(组合):推荐的面向对象方法

这是最符合面向对象封装原则的方法。当一个类(如Main)需要使用另一个类(如ArrayOperations)的功能时,它应该创建该类的一个实例(对象),然后通过这个实例来调用其非静态方法。这种关系被称为“组合”或“has-a”关系。

优点:

Designs.ai
Designs.ai

AI设计工具

下载
  • 封装性好: 不同的对象可以拥有自己的状态。
  • 灵活性高: 可以轻松地替换实现(多态)。
  • 符合OOP原则: 鼓励通过对象而不是类本身进行交互。
  • 易于测试: 方便进行单元测试和模拟。

实现步骤:

  1. 将目标类中的方法改为非静态(如果它们依赖于对象状态或你希望每个对象有独立的行为)。
  2. 在需要调用这些方法的类中,创建目标类的一个实例。
  3. 通过该实例调用其方法。

重构 ArrayOperations 类(方法改为非静态):

import java.util.Scanner;

public class ArrayOperations {

    // Scanner现在是实例字段,每个ArrayOperations对象都有自己的Scanner
    private Scanner scan;

    // 构造器:初始化Scanner
    public ArrayOperations() {
        this.scan = new Scanner(System.in);
    }

    // 非静态方法:获取用户输入的整数数组
    public int[] getIntegers(int number) {
        System.out.println("请输入 " + number + " 个整数\r");
        int[] entered = new int[number];
        for(int i = 0; i < entered.length; i++) {
            entered[i] = scan.nextInt();
        }
        // 注意:通常不建议关闭System.in,除非程序即将退出
        // scan.close(); // 如果Scanner是本地创建的,则可以关闭
        return entered;
    }

    // 非静态方法:打印数组内容
    public void printArray(int[] entered) {
        for(int i = 0; i < entered.length; i++) {
            System.out.println("元素 " + i + ", 输入的值为 " + entered[i]);
        }
    }

    // 非静态方法:对数组进行降序排序
    public int[] sortIntegers(int[] entered) {
        int[] sortedArray = new int[entered.length];
        System.arraycopy(entered, 0, sortedArray, 0, entered.length);

        boolean flag = true;
        int temp;
        while(flag) {
            flag = false;
            for(int i = 0; i < sortedArray.length - 1; i++) {
                if(sortedArray[i] < sortedArray[i + 1]) {
                    temp = sortedArray[i];
                    sortedArray[i] = sortedArray[i + 1];
                    sortedArray[i + 1] = temp;
                    flag = true;
                }
            }
        }
        return sortedArray;
    }
}

重构 Main 类(通过实例化调用):

public class Main {
    public static void main (String[] args) {
        // 创建 ArrayOperations 类的实例
        ArrayOperations operations = new ArrayOperations();

        // 通过实例调用其非静态方法
        int[] myIntegers = operations.getIntegers(5);
        int[] sorted = operations.sortIntegers(myIntegers);
        operations.printArray(myIntegers);
        operations.printArray(sorted);
    }
}

注意事项: 当Scanner作为实例变量时,它的生命周期与ArrayOperations对象绑定。如果ArrayOperations对象在main方法中创建并使用完毕后,Scanner也应该被关闭以释放资源。然而,关闭System.in通常会导致整个应用程序无法再次从标准输入读取,因此在实际应用中需要谨慎处理。对于本教程的简单示例,我们暂时忽略scan.close(),但请在生产代码中注意资源管理。

2. 使用静态成员(工具类方法)

如果一个方法不依赖于任何对象的状态(即它不需要访问类的实例变量),并且它执行的是通用工具性质的操作,那么将其声明为static是合理的。例如,数学函数Math.sqrt()就是静态方法。

优点:

  • 无需实例化: 可以直接通过类名调用,无需创建对象。
  • 内存效率: 没有实例字段,不会占用额外的对象内存。
  • 适用于工具类: 非常适合提供通用实用功能的类。

缺点:

  • 面向对象特性弱化: 静态方法不能访问非静态成员,限制了其与对象状态的交互。
  • 难以测试: 静态方法难以被模拟或替换,增加了单元测试的难度。
  • 过度使用可能导致设计问题: 如果所有方法都是静态的,那么这个类可能更像一个模块而不是一个真正的面向对象类。

实现方式(如原始代码所示): 将方法声明为public static。在调用时,通过ClassName.methodName()的方式访问。

// ArrayOperations 类保持原始的静态方法声明不变
// ...

public class Main {
    public static void main (String[] args) {
        // 直接通过类名调用静态方法
        int[] myIntegers = ArrayOperations.getIntegers(5);
        int[] sorted = ArrayOperations.sortIntegers(myIntegers);
        ArrayOperations.printArray(myIntegers);
        ArrayOperations.printArray(sorted);
    }
}

这种方式是原始代码实际采用的,也是非常常见的工具类设计模式。用户提到的import static className.*只是为了在调用时省略ClassName.前缀,本质上仍是调用静态方法。

3. 继承(extends):不适用于此场景

继承(public class Child extends Parent)用于建立“is-a”关系。如果Main类是ArrayOperations类的一种特殊类型,那么使用继承是合适的。例如,Car extends Vehicle。

为什么不适用于此场景:

  • Main类和ArrayOperations类之间没有“is-a”的逻辑关系。Main不是一个ArrayOperations,它只是使用ArrayOperations的功能。
  • Java只支持单继承,如果Main类继承了ArrayOperations,它就不能再继承其他类了,这会限制其未来的扩展性。
  • 继承会暴露父类的所有protected和public成员给子类,这可能违反封装原则。

因此,对于这种仅仅是使用另一个类功能的场景,继承通常不是一个好的选择。

4. 接口(interface):通常过于复杂

接口(interface)定义了一组行为规范。一个类可以实现(implements)一个或多个接口,从而承诺提供这些行为的实现。

为什么不适用于此场景:

  • 对于仅仅是调用一些工具方法的需求,引入接口会增加不必要的复杂性。
  • 接口主要用于定义契约、实现多态或解耦,而不是直接提供功能实现。
  • 虽然可以定义一个包含数组操作方法的接口,然后让ArrayOperations实现它,再让Main通过接口引用ArrayOperations对象,但这对于简单的工具方法调用来说是过度设计。

重构与最佳实践

根据上述讨论,对于你的需求,最符合“OOP标准”且灵活的方式是通过对象实例化(组合)。如果你确定这些方法确实不依赖于任何对象状态,并且仅仅是提供通用工具功能,那么保持它们为静态方法也是一种合理且常见的做法。

推荐的重构思路:

  1. 类名优化: 将Arrays类重命名为更具描述性的ArrayOperations或ArrayUtils,以避免与java.util.Arrays混淆,并清晰表达其职责。
  2. 方法性质判断:
    • 如果方法需要维护状态(例如,如果Scanner是每次操作独立的,或者类中还有其他需要被不同方法共享和修改的实例变量),则使用非静态方法并通过对象实例化来调用。这是更典型的面向对象设计。
    • 如果方法是纯粹的函数式,不依赖于任何实例状态,并且可以被广泛重用,那么将其设计为public static方法,并封装在一个工具类中(如ArrayUtils),是完全合理的。
  3. 资源管理: 如果类中创建了Scanner或其他需要关闭的资源,确保在对象不再需要时关闭它们。对于System.in,通常不建议在应用程序中关闭,因为它会影响整个应用程序的标准输入。

总结

在Java中,从另一个类中获取(或更准确地说,是使用)数组和方法,主要有两种符合不同“OOP标准”的实践:

  1. 面向对象实例化(组合):将方法设计为非静态,并在需要使用的类中创建目标类的一个实例。通过这个实例调用方法。这强调了对象间的协作,提供了更高的灵活性和更好的封装性。
  2. 静态方法调用:将方法设计为public static。在需要使用的类中,直接通过类名调用这些静态方法。这适用于提供通用工具功能或不依赖任何对象状态的方法。

继承和接口在更复杂的场景中发挥作用,但对于仅仅是调用其他类提供的数组操作功能而言,它们通常不是最直接或最合适的解决方案。理解这两种主要方式的优缺点和适用场景,将有助于你编写出结构清晰、高效且符合Java编程范式的代码。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

56

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

52

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1106

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

192

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1595

2025.12.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.8万人学习

Java 教程
Java 教程

共578课时 | 52.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号