
在Java编程中,尤其是在初学阶段,我们常常会将所有逻辑都写在一个main方法或一个类中。然而,为了代码的组织性、可读性和可维护性,将相关功能封装到独立的类中是良好的实践。当需要在一个类(例如Main类)中调用另一个类(例如ArrayOperations类)中定义的方法时,初学者可能会遇到困惑,尤其是在希望遵循面向对象(OOP)原则而非简单地使用静态导入(import static)时。
原始的ArrayOperations类(此处为便于理解和避免与java.util.Arrays混淆,我们将其命名为ArrayOperations)定义了一些静态方法和静态的Scanner对象:
import java.util.Scanner;
public class ArrayOperations { // 原始代码中的Arrays类
public static Scanner scan = new Scanner(System.in);
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;
}
}而Main类尝试直接调用这些方法:
public class Main {
public static void main (String[] args) {
// 以下代码在没有静态导入或限定符的情况下无法直接编译
int[] myIntegers = getIntegers(5);
int[] sorted = sortIntegers(myIntegers);
printArray(myIntegers);
printArray(sorted);
}
}由于ArrayOperations中的方法是static的,它们属于类本身而不是类的某个实例。在Main类中,如果没有import static ArrayOperations.*,或者不使用类名限定符,编译器将无法找到这些方法。直接使用类名限定符的调用方式是:
立即学习“Java免费学习笔记(深入)”;
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);
}
}这种方式是完全正确的,并且对于纯粹的工具类(utility class)来说很常见。import static只是为了简化书写,省略ArrayOperations.前缀。然而,如果目标是更深入地遵循OOP原则,避免大量静态方法,并考虑类的实例化和状态管理,那么我们需要探索其他设计模式。
Java提供了多种机制来实现类之间的协作和功能共享,每种机制都有其适用的场景。
继承是OOP三大特性之一,它表示“is-a”的关系。一个类可以extends(继承)另一个类,从而获得父类的非私有成员(方法和字段)。
示例:
// Main类继承ArrayOperations
public class Main extends ArrayOperations {
public static void main (String[] args) {
// 如果ArrayOperations中的方法是非静态的,Main可以直接调用
// 但由于原始方法是静态的,继承后仍然需要通过类名或静态导入调用
// 且main方法本身是静态的,不能直接调用非静态的继承方法
// 如果ArrayOperations的方法变为非静态,Main继承后需要创建Main的实例才能调用
// 或者将main方法中的逻辑放到非静态方法中
// 例如,如果ArrayOperations中的方法是非静态的,且Main也需要实例:
// Main mainInstance = new Main();
// int[] myIntegers = mainInstance.getIntegers(5); // 假设getIntegers是非静态的
}
}局限性:
接口定义了一组行为规范,表示“can-do”或“has-a-capability”的关系。一个类可以implements(实现)一个接口,从而承诺提供接口中定义的所有方法的具体实现。
示例:
// 定义一个接口
public interface ArrayProcessor {
int[] getIntegers(int number);
void printArray(int[] array);
int[] sortIntegers(int[] array);
}
// ArrayOperations实现接口
public class ArrayOperations implements ArrayProcessor {
private Scanner scanner; // 实例变量
public ArrayOperations(Scanner scanner) {
this.scanner = scanner;
}
@Override
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] = scanner.nextInt();
}
return entered;
}
@Override
public void printArray(int[] entered) {
for(int i = 0; i < entered.length; i++) {
System.out.println("Element " + i + ", typed value was " + entered[i]);
}
}
@Override
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) {
Scanner mainScanner = new Scanner(System.in);
ArrayProcessor processor = new ArrayOperations(mainScanner); // 使用接口类型引用实现类实例
int[] myIntegers = processor.getIntegers(5);
int[] sorted = processor.sortIntegers(myIntegers);
processor.printArray(myIntegers);
processor.printArray(sorted);
mainScanner.close(); // 关闭Scanner
}
}适用性: 接口非常适合定义不同类可以遵循的共同行为规范,实现多态性。例如,如果将来有多种排序算法(冒泡排序、快速排序),它们都可以实现ArrayProcessor接口。然而,对于本例中仅仅是想将一组具体实现方法从一个类移到另一个类并使用它,接口并不是最直接的解决方案,因为它引入了额外的抽象层。它通常与组合模式结合使用,如上述示例所示。
组合表示“has-a”的关系。一个类可以包含另一个类的实例作为其成员变量,并通过这个实例来调用其方法。这是最灵活、最常用的OOP设计模式之一,尤其适用于当一个类需要利用另一个类的功能,但两者之间没有强烈的“is-a”关系时。
为了更好地体现OOP原则,我们将ArrayOperations类中的静态方法和静态Scanner改为实例方法和实例变量。这样,每个ArrayOperations实例都可以有自己的状态(例如,如果它管理一个特定的数组或输入流),并且更好地进行资源管理。
步骤 1: 重构 ArrayOperations 类
将Scanner和方法改为非静态。Scanner作为资源,最好通过构造函数注入,由调用方管理其生命周期。
import java.util.Scanner;
public class ArrayOperations {
private Scanner scanner; // 改为实例变量
// 构造函数,接收一个Scanner实例
public ArrayOperations(Scanner scanner) {
this.scanner = scanner;
}
// 方法改为非静态
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] = scanner.nextInt(); // 使用实例的scanner
}
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) {
int[] sortedArray = new int[entered.length];
// 使用System.arraycopy进行数组复制,效率更高
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;
}
}步骤 2: Main 类使用组合模式
在Main类中,创建一个ArrayOperations的实例,并通过这个实例来调用其方法。
import java.util.Scanner; // Main类也需要Scanner
public class Main {
public static void main (String[] args) {
// 在Main类中创建并管理Scanner实例
Scanner mainScanner = new Scanner(System.in);
// 创建ArrayOperations的实例,并将Scanner注入
ArrayOperations ops = new ArrayOperations(mainScanner);
// 通过ops实例调用ArrayOperations中的方法
int[] myIntegers = ops.getIntegers(5);
int[] sorted = ops.sortIntegers(myIntegers);
ops.printArray(myIntegers);
ops.printArray(sorted);
// 使用完Scanner后,务必关闭它以释放系统资源
mainScanner.close();
}
}静态 vs. 实例方法:
Scanner资源管理:
以上就是Java跨类方法与数据共享:拥抱面向对象设计原则的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号