第二周-预习作业

预习问题:
一、
1.1 changeStr与changeArr的功能各是什么?
changeStr方法:接收一个String类型的参数x,尝试将其赋值为"xyz",但该操作仅在方法内部有效。
changeArr方法:接收一个String数组参数strs,遍历数组并修改每个元素的值(在原字符串后拼接其索引)。
1.2 main方法的x有没有被改变?为什么?
没有被改变。

原因是Java中方法参数传递采用值传递:当调用changeStr(x)时,传递的是x指向的字符串"abc"的地址副本。在changeStr方法内部,x被重新赋值为"xyz",但这只是修改了方法内部的局部变量(副本),并不会影响main方法中原始的x变量指向。因此,main方法中的x仍然指向"abc"。

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

数组是引用类型,当调用changeArr(args)时,传递的是数组对象的引用地址(同样是值传递,但这个"值"是引用)。changeArr方法内部通过该引用找到了原数组对象,并直接修改了数组中的元素值。由于方法内外的变量指向同一个数组对象,因此main方法中args数组的内容会被改变。

1.4 args数组中的值是从哪里来的?要怎么才能给它赋值?
来源:args数组的值来自程序运行时的命令行参数。它是main方法的默认参数,用于接收外部传入的参数。
赋值方式:运行Java程序时,在类名后跟随参数即可。例如:
java Main hello world 123
此时args数组的值为["hello", "world", "123"]。
二、数组相关问题解析
2.1 数组引用传递的输出结果及原因
看这段程序:

import java.util.Arrays;

public class ArrayTest {
public static void main(String[] args) {
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, 0]
[2, 1, 0]

原因:数组是引用类型,int[] arrX = arr表示arrX和arr指向同一个数组对象(内存中同一块地址)。当修改arr[0] = 2时,本质是修改了这个共享对象的值,因此arr和arrX输出的结果完全一致。未赋值的arr[2]默认值为0(int类型的默认值)。

2.2 字符串不可变,为何能修改数组元素的值?
看这段代码:

import java.util.Arrays;

public class StringArrayTest {
public static void main(String[] args) {
String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr)); // 输出 [aa, xx, cc]
}
}
原因:
"字符串不可变"指的是String对象本身的内容不能被修改(例如"bb"这个对象的字符序列无法改变)。但strArr[1] = "xx"操作并非修改"bb"对象,而是将数组的第1个元素(原本指向"bb")重新指向了新的String对象"xx"。数组存储的是对象的引用,修改数组元素只是改变引用的指向,与字符串本身是否可变无关。

2.3 二维数组int[5][]的第二维长度及遍历
int[5][]定义了一个包含5个元素的二维数组,但第二维的长度不确定(每个元素可以是不同长度的int数组,称为"不规则数组")。

补全代码并遍历:

import java.util.Arrays;

public class TwoDArrayTest {
public static void main(String[] args) {
// 定义二维数组,第一维长度为5,第二维长度不确定
int[][] arr = new int[5][];
// 初始化第二维数组(长度可不同)
arr[0] = new int[2]; // 长度2
arr[1] = new int[3]; // 长度3
arr[2] = new int[1]; // 长度1
arr[3] = new int[4]; // 长度4
arr[4] = new int[0]; // 长度0(空数组)

    // 给数组赋值
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr[i].length; j++) {
            arr[i][j] = i + j;
        }
    }

    // 使用foreach遍历
    System.out.println("二维数组内容:");
    for (int[] subArr : arr) {
        System.out.println(Arrays.toString(subArr));
    }
}

}
输出结果:

二维数组内容:
[0, 1]
[1, 2, 3]
[2]
[3, 4, 5, 6]
[]
三、类与对象相关问题解析
3.1 类与对象的区别?Math类有对象吗?
区别:
类是抽象的模板,定义了对象的属性和行为(例如"汽车类"定义了汽车有颜色、能行驶等);
对象是类的具体实例,是根据类创建的具体个体(例如"我的黑色轿车"是"汽车类"的一个对象)。

Math类是否有对象:
没有。Math类的构造方法被声明为private,禁止外部创建实例,其所有方法都是静态方法(如Math.random()),直接通过类名调用。

3.2 String类的private属性与public方法及设计原因
private属性:例如private final char value[](存储字符串的字符数组)。
设计原因:通过私有属性隐藏字符串的内部存储细节,防止外部直接修改字符数组,保证字符串的不可变性。

public方法:例如public int length()(返回字符串长度)、public char charAt(int index)(返回指定位置的字符)。
设计原因:提供安全的访问接口,允许外部获取字符串信息但不破坏其内部结构,同时在方法中可以添加边界检查等逻辑(如charAt会验证index是否越界)。

3.3 为什么Java普遍使用setter/getter模式?与封装性的关系?
原因:
若将属性设为public,外部可直接修改属性值,可能导致数据不合法(例如年龄设置为负数)。而setter/getter模式允许在方法中添加逻辑控制:

setter方法:修改属性时验证数据合法性(如if(age > 0) this.age = age);
getter方法:控制属性的访问权限(如只允许读取不允许修改)。
与封装性的关系:
封装性要求"隐藏对象内部细节,仅通过公开接口交互"。setter/getter模式正是封装性的体现:将属性私有化(隐藏细节),通过公共方法(接口)控制访问,既保证了数据安全性,又保留了灵活性。

3.4 对象属性的初始化时机与方法
对象属性的初始化可在以下时机进行:

声明时初始化:
public class Person { private String name = "默认姓名"; }

实例初始化块:

public class Person {
private int age;
// 实例初始化块,创建对象时执行
{ age = 18; }
}
构造方法中初始化:

public class Person {
private String name;
public Person(String name) { this.name = name; } // 构造方法赋值
}
使用对象时动态赋值:
person.setName("张三");(通过setter方法)

进阶:用作用域说明封装性
作用域修饰符(private、default、protected、public)是实现封装的核心工具:

private:仅类内部可访问,完全隐藏内部细节(如String的value数组);
default(默认):同包内可访问,限制跨包的直接访问;
protected:同包或子类可访问,允许子类扩展但限制外部访问;
public:全局可访问,通常用于暴露安全的接口(如setter/getter方法)。
封装性通过作用域控制,将"不应该被外部访问的细节"(private)隐藏,只暴露"必须被外部使用的功能"(public),从而降低代码耦合度,提高安全性和可维护性。

总结
本文主要探讨Java编程语言中的若干基础性核心主题,包括方法参数的传递机制、数组的数据结构特性,以及类与对象所体现的封装设计原则。通过对这些关键概念的深入剖析,旨在为构建符合工程规范的高质量代码奠定坚实的理论基础。

posted @ 2025-09-15 17:49  零零12  阅读(15)  评论(0)    收藏  举报