
在java编程中,将应用程序逻辑拆分到不同的类中是实现模块化和良好设计的基石。对于初学者而言,如何在一个类(例如main类)中有效地调用另一个类(例如包含数组操作的arrayoperations类)的方法并处理其数据,是一个常见的挑战。本文将探讨几种实现这一目标的方法,并提供符合面向对象编程(oop)原则的实践建议。
理解Java中的方法类型:静态与实例
在深入探讨跨类调用之前,首先需要理解Java中方法的两种基本类型:静态方法和实例方法。
- 静态方法(Static Methods):使用static关键字修饰的方法。它们属于类本身,不依赖于任何特定的对象实例。你可以直接通过类名来调用静态方法,例如 ClassName.staticMethod()。静态方法不能直接访问类的非静态成员(实例变量或实例方法),因为它们没有关联的对象实例。
- 实例方法(Instance Methods):不使用static关键字修饰的方法。它们属于类的某个特定对象实例。要调用实例方法,必须首先创建该类的一个对象实例,然后通过该对象实例来调用,例如 objectName.instanceMethod()。实例方法可以访问类的所有成员(静态和非静态)。
用户最初提供的Arrays类中的所有方法(getIntegers、printArray、sortIntegers)以及Scanner对象都被声明为static。这意味着它们是类级别的成员,可以直接通过类名访问。
// 原始的 Arrays.java 类(为避免与java.util.Arrays冲突,建议重命名)
import java.util.Scanner;
public class Arrays { // 建议更名为 ArrayOperations 或 ArrayUtils
public static Scanner scan = new Scanner(System.in); // 静态Scanner
public static int[] getIntegers(int number) {
System.out.println("Please enter " + number + " numbers\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("Element " + i + ", typed value was " + entered[i]);
}
}
public static int[] sortIntegers(int[] entered) {
int[] sortedArray = new int[entered.length];
for(int i = 0; i < entered.length; i++) {
sortedArray[i] = entered[i];
}
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;
}
}方案一:直接通过类名调用静态方法
由于ArrayOperations(原Arrays)类中的所有方法都是静态的,最直接、最简单且符合其当前结构的方式,就是在Main类中直接通过类名来调用这些方法。
// Main.java
public class Main {
public static void main (String[] args) {
// 直接通过类名调用 ArrayOperations 类的静态方法
int[] myIntegers = ArrayOperations.getIntegers(5); // 假设 ArrayOperations 是重命名后的类名
int[] sorted = ArrayOperations.sortIntegers(myIntegers);
System.out.println("原始数组:");
ArrayOperations.printArray(myIntegers);
System.out.println("排序后数组:");
ArrayOperations.printArray(sorted);
// 注意:静态 Scanner 资源需要手动关闭,通常在程序结束前进行
ArrayOperations.scan.close();
}
}优点:
立即学习“Java免费学习笔记(深入)”;
- 简单直接,无需创建对象实例。
- 适用于工具类,其中方法不依赖于任何对象的状态,仅执行特定任务。
缺点:
- 如果方法需要维护状态,则不适用。
- 静态资源(如Scanner)的生命周期管理可能变得复杂,容易导致资源泄漏。
方案二:通过对象实例进行组合(更符合OOP的通用实践)
为了更好地遵循面向对象编程(OOP)的原则,通常推荐通过创建类的实例(对象)来进行方法调用。这种方式称为“组合”(Composition),即一个类“拥有”另一个类的对象。这要求被调用的方法是非静态的,以便它们可以操作该对象实例的特定状态。
为了实现这一点,我们需要对ArrayOperations类进行修改,使其方法成为实例方法,并将Scanner作为实例变量。
// ArrayOperations.java (修改后,更符合OOP设计)
import java.util.Scanner;
import java.util.Arrays; // 引入java.util.Arrays用于copyOf方法
public class ArrayOperations { // 建议的类名
private Scanner scan; // 非静态Scanner,属于每个 ArrayOperations 实例
public ArrayOperations() { // 构造函数,在创建对象时初始化Scanner
this.scan = new Scanner(System.in);
}
// 非静态方法,通过对象实例调用
public int[] getIntegers(int number) {
System.out.println("Please enter " + number + " numbers\r");
int[] entered = new int[number];
for(int i = 0; i < entered.length; i++) {
entered[i] = scan.nextInt();
}
return entered;
}
// 非静态方法
public void printArray(int[] entered) {
for(int i = 0; i < entered.length; i++) {
System.out.println("Element " + i + ", typed value was " + entered[i]);
}
}
// 非静态方法
public int[] sortIntegers(int[] entered) {
// 使用 java.util.Arrays.copyOf 避免直接修改原始数组
int[] sortedArray = Arrays.copyOf(entered, 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;
}
// 提供一个方法来关闭内部的Scanner资源
public void closeScanner() {
if (scan != null) {
scan.close();
}
}
}现在,Main类可以通过创建ArrayOperations的实例来调用这些方法:
// Main.java
public class Main {
public static void main (String[] args) {
ArrayOperations arrayOps = new ArrayOperations(); // 创建 ArrayOperations 类的实例
try {
int[] myIntegers = arrayOps.getIntegers(5); // 通过实例调用方法
int[] sorted = arrayOps.sortIntegers(myIntegers);
System.out.println("原始数组:");
arrayOps.printArray(myIntegers);
System.out.println("排序后数组:");
arrayOps.printArray(sorted);
} finally {
// 确保在程序结束或对象不再需要时关闭资源
arrayOps.closeScanner();
}
}
}优点:
立即学习“Java免费学习笔记(深入)”;
- 封装性更好: ArrayOperations对象管理自己的Scanner实例和其他状态,避免了全局静态资源的复杂性。
- 符合OOP原则: 将数据和操作数据的方法封装在一起,提高了代码的模块化和内聚性。
- 易于测试: 可以为ArrayOperations创建多个实例,每个实例有自己的状态,便于进行单元测试。
- 灵活性: 如果未来需要不同的数组操作策略,可以通过创建ArrayOperations的子类或实现不同接口来轻松扩展。
其他考虑:继承(extends)
在Java中,一个类可以通过extends关键字继承另一个类。继承表示一种“is-a”的关系(例如,Dog is-a Animal)。如果Main类继承ArrayOperations类,那么Main类将拥有ArrayOperations类的所有非私有成员。
// 示例:不推荐用于此场景
public class Main extends ArrayOperations { // 假设 ArrayOperations 的方法为非静态
public static void main(String[] args) {
// 如果 Main 继承了 ArrayOperations,可以直接调用其非静态方法
// 但 main 方法是静态的,所以直接调用非静态方法仍需要一个实例
// 或者将 main 方法中的逻辑放在一个非静态方法中,然后创建 Main 实例
// 例如:
// Main app = new Main();
// int[] myIntegers = app.getIntegers(5);
// ...
}
}为什么不推荐用于此场景:
- 逻辑关系不符: Main类“is-a”ArrayOperations类在语义上通常不成立。Main类是程序的入口,它通常“使用”其他类的功能,而不是“是”这些功能。
- 单继承限制: Java只支持单继承,这意味着一个类只能继承一个父类。如果Main类已经需要继承其他类,这种方式将不可行。
- 紧密耦合: 继承会创建紧密的耦合关系,父类的改变可能会影响到子类,降低了代码的灵活性。
在大多数情况下,当一个类需要利用另一个类的功能时,组合(通过创建对象实例)是比继承更优的选择,因为它提供了更高的灵活性和更低的耦合度。
注意事项与最佳实践
- 类命名规范: 避免将自定义类命名为Arrays,因为它与Java标准库中的java.util.Arrays类冲突,可能导致混淆。建议使用如ArrayOperations、ArrayUtils等描述性名称。
- 资源管理: 对于Scanner这类系统资源,务必在使用完毕后调用close()方法关闭,以防止资源泄漏。在使用组合模式时,可以在ArrayOperations类










