当前位置: 首页 > news >正文

第02周Java:从方法传参到对象封装

在学习 Java 的过程中,我们经常会遇到一些“简单却易错”、“常见但难懂”的基础问题,比如:

为什么我方法里修改了 String,外面却没变化?

为什么我修改了数组的一个引用,原数组也变了?

二维数组的第二维长度到底怎么定?如何优雅遍历?

类和对象到底什么关系?Math 类有对象吗?String 类的设计有什么特别之处?

为什么大家都用 getter/setter,而不直接把属性设为 public?

对象的属性,到底应该在什么时候、以何种方式初始化?
接下来我们将通过一些例子解决这些问题。

一.方法相关问题
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的功能各是什么?
1.2 main方法的x有没有被改变?为什么?
1.3 main方法的args数组的内容有没有被改变?为什么?
1.4 args数组中的值是从哪里来的?要怎么才能给他赋值。
问题 1.1:changeStr和 changeArr的功能分别是什么?
changeStr(String x)​​
目标​​:试图将传入的字符串 x的值修改为 "xyz"。
实际行为​​:只是将方法内的局部变量 x指向了新的字符串对象 "xyz",​​对调用方传入的原始引用没有影响​​。
​​总结​​:这是一个“试图修改不可变对象并且误以为会影响外部”的典型案例。
changeArr(String[] strs)​​
目标​​:遍历字符串数组,将每个元素追加当前索引,例如 "a" → "a0","b" → "b1"。
​​实际行为​​:直接修改了传入数组的每个元素,因为数组是引用类型,方法内外操作的是同一个数组对象。
总结​​:操作的是数组内容(即引用指向的对象内容),因此会影响原始数组。
问题 1.2:main 方法中的 x有没有被改变?为什么?
答案:没有改变,输出的 x 仍然是 "abc"​​
核心原因:Java 是值传递(Pass By Value),不是引用传递!​
问题 1.3:main 方法中的 args数组内容有没有被改变?为什么?
答案:有改变!​​
​​原因:虽然 args 是传入的引用副本,但它和 changeArr方法中的 strs指向的是同一个数组对象。​​
你通过 strs[i] = strs[i] + "" + i;修改了数组中的每个元素,也就是修改了这个共享的数组对象的内容。
所以,main 中的 args数组打印出来时,内容已经改变了。
问题 1.4:args数组的值从哪里来?如何赋值?
来源:
args是 Java 应用程序的 ​​命令行参数​​,当你运行程序时从命令行传入,例如:
java Main hello world 123
那么 args就是:["hello", "world", "123"]
如何赋值?​
一般情况下,args由 JVM 在程序启动时初始化,开发者无法在代码中直接赋值。
如果你想在代码中模拟命令行参数,可以定义一个普通方法,自己传入一个数组:
public static void simulateArgs(String[] testArgs) {
testArgs[0] = "mockArg";
}

public static void main(String[] args) {
String[] myArgs = {"one", "two"};
simulateArgs(myArgs);
System.out.println(Arrays.toString(myArgs));
}
二.数组相关问题
对于如下程序

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));
这段程序输出结果是什么?为什么?
结果一样,因为你修改了 arr[0],其实就是修改了那个唯一数组的第 0 个元素,因此无论通过哪个引用访问,都是相同的数据
String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));
字符串是不可变类,为什么可以对strArr[1]赋值"xx"
String 是不可变的,但数组是可变的,strArr是一个 ​​String 类型的一维数组​​,它的每个元素是一个引用,指向一个 String 对象,当你执行 strArr[1] = "xx",你只是将数组的第 1 个位置,指向了另一个新的 String 对象 "xx",​​不是修改原来的 "bb" 对象本身
使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach或其他循环方法遍历这个二维数组?
int[][] arr = new int[5][];
arr[0] = new int[3];
arr[1] = new int[2];
第二维长度:不固定!可以是任意正整数,也可以为 null!​​
你​​必须为每一个一维数组单独分配空间​​,否则访问未初始化的元素会导致 NullPointerException。
使用 ​​增强 for 循环(foreach):
for (int[] row : arr) {
if (row != null) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
}
类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?
​​类(Class)​​ 是对象的模板,描述了对象有哪些状态(属性)和行为(方法)。
对象(Object)​​ 是类的实例,是具体存在的“个体”。
Math 类有对象吗?没有,Math是一个工具类​​,内部所有方法都是​​静态的。
​​String 的内部数据(如 char 数组)是 private 的​​,外部不能直接访问或修改。
但对外提供了大量 ​​public 方法​​,如:
length()
charAt(int)
substring(int, int)
toUpperCase()
为什么这么设计?​​
String 是不可变的​​,任何修改都返回新对象,保证线程安全。
将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?

直接 public 行不行?
技术上可行,比如:
public class User {
public String name;
}
但 ​​强烈不建议!​​
为什么不推荐?
​​破坏封装性!​外部可以随意修改属性,类无法控制、校验、记录或附加逻辑。比如,未来你可能希望对 name 做非空校验、去除空格、转换大小写等,如果属性是 public,你将不得不修改所有直接访问的代码
为什么要用 Getter / Setter?
控制读写逻辑(如校验、格式化、日志、懒加载等)
提高代码的可维护性、健壮性
符合面向对象设计原则:​​封装性​
对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?
何时初始化?
对象的属性可以在以下时机进行初始化:
声明时初始化
构造方法中初始化
初始化块(实例初始化块 / 静态初始化块)
Setter 方法中初始化
延迟初始化(使用时再初始化,比如懒加载)
public class Person {
// 1. 声明时初始化
private String name = "Unknown";

// 2. 构造方法中初始化
private int age;
public Person(int age) {this.age = age;
}// 3. 实例初始化块
{System.out.println("实例块执行,可用于公共初始化逻辑");
}// 4. 通过 Setter 方法初始化(更灵活)
public void setAge(int age) {if (age > 0) {this.age = age;}
}

}
以上就是这周课前问题的解答。

http://www.wxhsa.cn/company.asp?id=4948

相关文章:

  • 基于pandas自动化的csv信息提取保存的脚本
  • 9.15 hxh 讲题
  • qoj4239 MST
  • java相关问题解答
  • 牛客 周赛106 20250904
  • 第一篇博客
  • 如何让多个按钮绑定到同一个事件上
  • STM32 HAL学习笔记:GC1808(PCM1808)的使用以及使用I2S+DMA读取
  • 完整教程:【视频系统】技术汇编
  • MSTP 单域
  • 阿里云百炼平台使用避坑记录 - 详解
  • springboot的run
  • ubuntu服务器docker日期安装mysql
  • springboot的启动流程
  • 萤火虫旅行网和萤火虫文旅的关系是什么
  • 「微积分 A1」基础知识(连载中)
  • 第2周-预习作业
  • P12546 [UOI 2025] Convex Array
  • 一个新词:测试可靠性
  • CF827F Dirty Arkadys Kitchen
  • P2839 [国家集训队] middle
  • wuti
  • 友链
  • 向量化存储与知识图谱的比较
  • 力扣17题 电话号码的字母组合
  • 萤火虫文旅年票、为什么能做到低至4.2元一张景区门票、还能高达50%的毛利润?
  • ubuntu服务器docker容器安装nacos
  • PWN手的成长之路-02-r3m4ke
  • SAP 采购订单税率及含税金额取数
  • 深入解析:Linux x86 stability和coredump