Java预习任务完成与问题解析
预习任务完成报告
方法相关问题
1.1 changeStr与changeArr的功能各是什么?
changeStr方法接收一个 String 参数x,并尝试将x重新赋值为"xyz"。但由于 String 是不可变类,且 Java 采用值传递,该方法不会改变原始字符串变量的值。changeArr方法接收一个 String 数组参数strs,并遍历数组,将每个元素修改为原始值加上索引号(例如strs[i] + "" + i)。这会修改数组的内容,因为数组是引用类型,传递的是引用的副本,但通过引用可以修改原始数组的元素。
1.2 main方法的x有没有被改变?为什么?
- main 方法的
x没有被改变。因为changeStr方法中的参数x是局部变量,接收了 main 方法中x的值的副本(即引用的副本)。当在changeStr中重新赋值时,只是改变了局部变量x的引用,而不是原始变量。因此 main 中的x仍然指向"abc"。
1.3 main方法的args数组的内容有没有被改变?为什么?
- main 方法的
args数组的内容被改变了。因为changeArr方法接收的是数组的引用副本,但通过这个引用副本可以直接访问和修改原始数组的元素。因此,当changeArr修改数组元素时,原始args数组被修改。
1.4 args数组中的值是从哪里来的?要怎么才能给他赋值?
args数组中的值来自命令行参数。当运行 Java 程序时,可以通过命令行传递参数。例如,使用命令java Main arg1 arg2 arg3,那么args数组就会包含["arg1", "arg2", "arg3"]。在 IDE(如 IntelliJ IDEA 或 Eclipse)中,可以通过运行配置设置命令行参数。
数组相关问题
2.1 这段程序输出结果是什么?为什么?
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]
- 原因:
arrX被赋值为arr的引用,因此arrX和arr指向同一个数组对象。当修改arr[0]为 2 时,通过arrX访问同一个数组,所以arrX[0]也是 2。数组是引用类型,赋值操作共享引用。
2.2 字符串是不可变类,为什么可以对strArr[1]赋值"xx"?
String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));
- 字符串是不可变类,意味着 String 对象一旦创建就不能被修改。但
strArr是一个数组,数组的元素是 String 引用。当执行strArr[1] = "xx"时,并不是修改了原有的 String 对象"bb",而是将strArr[1]这个引用重新指向了一个新的 String 对象"xx"。因此,这是改变了数组元素存储的引用,而不是修改了 String 对象本身。
2.3 使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach或其他循环方法遍历这个二维数组?
- 使用
int[5][]定义一个二维数组时,第一维的长度是 5,但第二维的长度没有指定,因此每个第二维数组可以是不同的长度,或者为 null。需要单独初始化每个第二维数组。
补全代码示例:
import java.util.Arrays;
public class TwoDArrayExample {
public static void main(String[] args) {
int[][] twoDimArray = new int[5][]; // 第二维未初始化
// 初始化第二维数组,长度各不相同
twoDimArray[0] = new int[3];
twoDimArray[1] = new int[2];
twoDimArray[2] = new int[4];
twoDimArray[3] = new int[1];
twoDimArray[4] = new int[5];
// 使用foreach遍历
for (int i = 0; i < twoDimArray.length; i++) {
int[] innerArray = twoDimArray[i];
if (innerArray != null) {
for (int value : innerArray) {
System.out.print(value + " ");
}
System.out.println();
} else {
System.out.println("null");
}
}
}
}
类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?
-
类与对象的区别:
- 类是一个模板或蓝图,定义了对象的属性和行为。例如,String 类定义了字符串的属性和方法。
- 对象是类的实例,是具体的数据。例如,String 对象是具体的字符串值。
-
Math类有对象吗?
- Math 类没有对象。Math 类中的所有方法和属性都是 static 的,因此不需要创建对象就可以使用。Math 类设计为不可实例化,通常通过类名直接调用方法,如
Math.abs()。
- Math 类没有对象。Math 类中的所有方法和属性都是 static 的,因此不需要创建对象就可以使用。Math 类设计为不可实例化,通常通过类名直接调用方法,如
-
String类有什么属性是private的,有什么方法是public的,为什么这样设计?
- String 类内部使用 private 属性来存储字符数据,例如在 Java 8 中,String 类有
private final char value[]字段来存储字符数组。这些属性是 private 的,以防止外部直接修改,确保 String 的不可变性。 - String 类提供了许多 public 方法,如
length()、charAt()、substring()等,这些方法允许读取字符串的内容而不修改它(因为不可变),或者返回新的字符串。 - 为什么这样设计?为了封装和不可变性。封装保护了内部数据不被意外修改,不可变性使得字符串在多线程环境下安全,并且可以缓存哈希值等。例如:
private字段value被封装,外部不能直接访问,只能通过 public 方法操作。- public 方法如
toUpperCase()返回新字符串,而不是修改原字符串,确保了不可变性。
- String 类内部使用 private 属性来存储字符数据,例如在 Java 8 中,String 类有
将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?
- 使用 setter/getter 模式的主要原因是为了封装。封装是面向对象编程的基本原则之一,它隐藏了对象的内部状态,并通过方法来控制对状态的访问和修改。
- 好处:
- 控制访问:可以通过 getter 和 setter 添加验证逻辑。例如,在 setter 中检查输入值是否有效。
- 灵活性:可以在不改变类的外部接口的情况下修改内部实现。例如,如果将来需要计算某个值而不是直接存储,可以修改 getter 方法。
- 只读或只写属性:可以通过只提供 getter 或只提供 setter 来实现。
- 调试和维护:可以在 setter 或 getter 中添加日志或调试代码。
- 与封装性的关系:封装性要求对象的状态不被直接暴露,而是通过方法间接访问。setter/getter 模式正是实现这种间接访问的标准方式。
对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?
-
对象的属性可以在以下时机进行初始化:
- 声明时直接初始化:例如
private int age = 0; - 在构造器中初始化:通过构造函数赋值。
- 在初始化块中初始化:使用实例初始化块或静态初始化块(对于静态属性)。
- 通过 setter 方法初始化:在对象创建后,通过调用 setter 方法设置值。
- 懒初始化:在 getter 方法中检查属性是否已初始化,如果没有则初始化。
- 声明时直接初始化:例如
-
具体办法示例:
public class Example {
private int a = 10; // 直接初始化
private int b;
private int c;
{ // 实例初始化块
b = 20;
}
public Example() {
c = 30; // 构造器初始化
}
public void setC(int value) {
c = value; // 通过方法初始化
}
}

浙公网安备 33010602011771号