第02周 预习、实验与作业:Java基础语法2、面向对象入门

方法相关问题

1.1 changeStr与changeArr的功能各是什么?

  • changeStr(String x): 尝试将传入的字符串引用指向新的字符串"xyz"
  • changeArr(String[] strs): 遍历数组并将每个元素修改为原值加上索引号

1.2 main方法的x有没有被改变?为什么?

没有改变。因为:

  • Java中参数传递是值传递(传递的是引用的副本)
  • x = "xyz" 只是改变了方法内部参数x的指向,不影响外部的x变量
  • 字符串是不可变对象,无法在原地修改

1.3 main方法的args数组的内容有没有被改变?为什么?

有改变。因为:

  • 数组是引用类型,传递的是数组引用的副本
  • 两个引用(main中的args和changeArr中的strs)指向同一个数组对象
  • 通过strs[i]修改的是共享的数组元素

1.4 args数组中的值是从哪里来的?要怎么才能给他赋值。

  • args数组的值来自命令行参数
  • 赋值方式:
    • 命令行:java Main arg1 arg2 arg3
    • IDE中:在运行配置中设置程序参数
    • 其他方式:可以通过其他数组赋值 args = new String[]{"a", "b"}

2.1 这段程序输出结果是什么?为什么?

int[] arr = new int[3];
arr[0] = 1; arr[1] = 1;
int[] arrX = arr;  // arrX和arr指向同一个数组
arr[0] = 2;        // 修改的是共享的数组
System.out.println(Arrays.toString(arr));   
System.out.println(Arrays.toString(arrX)); 

2,1,0,因为arrX和arr引用同一个数组对象。

2.2 字符串是不可变类,为什么可以对strArr[1]赋值"xx"。

  • 字符串不可变指的是String对象内容不可变
  • strArr[1] = "xx" 是修改数组元素(引用)的指向,不是修改字符串内容
  • 原来的"bb"字符串对象没有被修改,只是数组第二个元素现在指向了新的"xx"字符串

3. 二维数组遍历

int[][] arr2D = new int[5][]; // 第二维长度不确定

// 初始化第二维
for (int i = 0; i < arr2D.length; i++) {
    arr2D[i] = new int[i + 1]; // 每行长度不同
}

// 嵌套for循环
for (int i = 0; i < arr2D.length; i++) {
    for (int j = 0; j < arr2D[i].length; j++) {
        System.out.print(arr2D[i][j] + " ");
    }
    System.out.println();
}

// foreach
for (int[] row : arr2D) {
    for (int num : row) {
        System.out.print(num + " ");
    }
    System.out.println();
}

4.类与对象的区别

  • :模板/蓝图,定义对象的属性和行为(如:String类)
  • 对象:类的实例,具体存在的数据(如:"hello"字符串对象)
  • 关系:类是抽象概念,对象是具体实现

Math类有对象吗?

没有。Math类是工具类:

  • 所有方法和属性都是static的
  • 构造函数是private的,无法实例化
  • 设计为静态工具类,提供数学运算功能

String类的封装设计

private属性举例

  • private final char value[]:存储字符数据,防止外部直接修改
  • private int hash:缓存哈希值,避免重复计算

public方法举例

  • public int length():提供安全的长度访问
  • public char charAt(int index):提供安全的字符访问

为什么这样设计

  1. 安全性:防止外部直接修改内部数据
  2. 不可变性:保证字符串内容不会被意外改变
  3. 封装实现细节:可以优化内部实现而不影响使用者

5.

为什么使用setter/getter

  1. 控制访问:可以在setter中添加验证逻辑
  2. 保持兼容性:可以修改内部实现而不改变接口
  3. 延迟初始化:可以在getter中实现懒加载
  4. 添加副作用:可以在值改变时触发其他操作

与封装性的关系

  • 封装的核心是"隐藏实现细节,暴露必要接口"
  • setter/getter提供了受控的访问方式,实现了信息隐藏

6. 对象的属性可在什么时候进行初始化?

  1. 声明时直接初始化
  2. 构造方法中初始化
  3. 初始化块中初始化
  4. 使用时延迟初始化

初始化方法

public class Example {
    // 1. 声明时初始化
    private String name = "default";
    
    // 2. 初始化块
    {
        count = 0;
    }
    
    // 3. 构造方法
    public Example() {
        this.name = "unknown";
    }
    
    // 4. 延迟初始化
    private String lazyValue;
    public String getLazyValue() {
        if (lazyValue == null) {
            lazyValue = "initialized";
        }
        return lazyValue;
    }
}

进阶:作用域与封装性

从作用域角度理解封装性:

  1. 类内部作用域:private属性和方法只在类内部可见
  2. 包作用域:default访问级别在包内可见
  3. 全局作用域:public对所有类可见

封装性通过限制作用域来实现:

  • 将实现细节限制在最小作用域(private)
  • 只暴露必要的接口到更大作用域(public)
  • 这样减少了代码的耦合度,提高了可维护性

例如String类的value数组是private的,外部代码无法直接访问,只能通过public方法间接操作,这样就保证了字符串的不可变性和安全性。

posted @ 2025-09-15 20:29  糯米鸡加鸡蛋  阅读(4)  评论(0)    收藏  举报