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

1.3 课前问题列表

1.方法相关问题

public class Main {
    static void changeStr(String x) {
        x = "xyz";
    }
    static void changeArr(String[] strs) {
        for (int i = 0; i < strs.length; i++) {
            strs[i] = strs[i]+""+i;
        }
    }

    public static void main(String[] args) {    
        String x = "abc";
        changeStr(x);
        System.out.println(x);
        changeArr(args);
        System.out.println(Arrays.toString(args));
    }
}

对于如上代码:

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

changeStr 方法:尝试将传入的 String 类型参数 x 的值修改为 "xyz",但由于 String 是不可变类型,该修改只是在方法内部对参数的引用进行了改变,不影响外部实参。
changeArr 方法:遍历传入的 String 数组 strs,将数组中的每个元素与该元素的索引值拼接(通过 strs[i] + "" + i 实现),从而修改数组元素的值。

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

main 方法中的 x 没有被改变。因为 String 是不可变对象,在 changeStr 方法中,只是将方法内部的参数 x 重新指向了 "xyz" 这个新的 String 对象,而 main 方法中的 x 仍然指向原来的 "abc" 对象,所以外部的 x 值不会改变。

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

main 方法中的 args 数组的内容被改变了。因为数组是引用类型,changeArr 方法接收到的是 args 数组的引用,在方法内部对数组元素的修改,会直接影响到原数组(main 方法中的 args 数组)。

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

args 数组中的值是从程序运行时的命令行参数传递而来。要给 args 数组赋值,可以在运行 Java 程序时,在命令行中输入参数,例如:java Main 参数1 参数2 参数3,这样 args 数组就会依次存储 "参数1"、"参数2"、"参数3" 这些值。

2.数组相关问题

对于如下程序

int[] arr = new int[3];
arr[0] = 1; arr[1] = 1;
int[] arrX = arr;
arr[0] = 2;
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(arrX));

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

第一行输出:[2, 1, 0]
第二行输出:[2, 1, 0]
因为数组是引用类型,arrX = arr 表示 arrX 和 arr 指向同一个数组对象。当修改 arr[0] 的值为 2 时,这个数组对象的内容被改变,所以通过 arr 和 arrX 访问该数组,得到的结果是一样的。

String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));

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

字符串是不可变的,指的是字符串对象本身的内容不可变。但 strArr 是字符串数组,strArr[1] 存储的是字符串对象的引用。给 strArr[1] 赋值 "xx",是让 strArr[1] 这个引用指向了新的字符串对象 "xx",而不是修改原来字符串对象的内容,所以可以这样操作。

3.使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach获其他循环方法遍历这个二维数组?

第二维长度:int[5][] 定义的二维数组,第二维长度没有指定,所以每一行(第一维的每个元素)可以是不同长度的一维数组,需要在后续代码中分别初始化

public class ArrayDemo {
    public static void main(String[] args) {
        int[][] arr = new int[5][];
        // 为每一行的一维数组初始化不同长度
        arr[0] = new int[2];
        arr[1] = new int[3];
        arr[2] = new int[1];
        arr[3] = new int[4];
        arr[4] = new int[5];

        // 使用 foreach 遍历
        for (int[] row : arr) {
            for (int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
}

4.类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?

类与对象的区别:类是对具有相同属性和行为的事物的抽象描述,是一种模板;对象是类的实例,是根据类创建出来的具体存在的个体。
Math 类对象:Math 类的方法都是静态方法,不需要创建对象,通过类名直接调用,所以 Math 类没有对象(不需要创建对象来使用它的功能)。

String 类的 private 属性和 public 方法:

private 属性:例如 value 数组(用于存储字符串的字符),将其设为 private,是为了封装字符串的内部存储细节,防止外部直接修改,保证字符串的不可变性。
public 方法:例如 length()(获取字符串长度)、charAt(int index)(获取指定索引的字符),这些方法对外提供了操作字符串的接口,方便外部使用字符串的功能,同时内部实现细节被隐藏。

5.将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?

使用 setter/getter 的原因:如果将属性设为 public,外部类可以随意修改属性值,可能会导致对象状态不符合预期。而使用 setter 方法可以在设置属性值时进行校验等逻辑,getter 方法可以控制属性的读取方式,保证对象的封装性和安全性。
与封装性的关系:封装性要求隐藏对象的内部实现细节,只对外提供有限的接口。setter/getter 模式就是封装性的体现,它隐藏了属性的直接访问,通过方法来控制属性的访问和修改。

6.对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?

初始化时间:对象的属性可以在声明时初始化、在构造方法中初始化、在实例初始化块中初始化。
初始化办法:
声明时初始化:例如 private int age = 18;
构造方法中初始化:在类的构造方法里为属性赋值。
实例初始化块中初始化:用 {} 包裹的代码块,在创建对象时会执行,可用于初始化属性。

7.进阶(可选):尝试使用作用域来说明封装性。

作用域(如 private、public、protected 等访问修饰符)是实现封装性的重要手段。private 修饰的成员(属性或方法)只能在当前类内部访问,隐藏了类的内部细节;public 修饰的成员可以被任何类访问,提供了对外的接口。通过不同的作用域修饰符,控制了类的成员对外部的可见性,从而实现了封装,将类的内部实现与外部使用隔离开。

posted @ 2025-09-15 19:51  我今天真的要早睡了  阅读(10)  评论(0)    收藏  举报