第02周 预习:Java基础语法2、面向对象入门
项目名称 | 内容 |
---|---|
课程名称 | java |
班级 | 网安2413 |
学生姓名 | 王璐 |
学号 | 202421336068 |
预习
1.1 学习目标
- 掌握引用类型及常见类:数组、数组列表(ArrayList)、方法及引用类型作为方法参数
- 掌握类、对象、方法、属性相关基本概念,对象的初始化。
- 能使用IDE快速创建对象。
1.2
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的功能各是什么?
1.2 main方法的x有没有被改变?为什么?
1.3 main方法的args数组的内容有没有被改变?为什么?
1.4 args数组中的值是从哪里来的?要怎么才能给他赋值。
1.1 changeStr功能:将传入的字符串参数修改为"xyz",但实际不会影响原变量
changeArr功能:遍历传入的字符串数组,将数组中每个元素修改为 "原始元素值+索引值"
1.2 main方法的x有没有被改变?为什么?
没有被改变,因为Java 中字符串是不可变对象,且方法参数传递的是 "值传递"。
1.3 main方法的args数组的内容有没有被改变?为什么?
被改变了,因为数组是引用类型,方法参数传递的是数组的引用(地址)的副本。
- main方法中的args和changeArr方法的参数strs指向同一个数组对象。
- 方法内部通过strs[i] = ...修改的是数组内部元素(操作的是同一个数组对象),因此main方法中的args数组内容会同步被改变。
1.4 args数组中的值是从哪里来的?要怎么才能给他赋值。
- args数组是main方法的参数,它的值来源于程序运行时传递的命令行参数。
- 1.给args数组赋值的方式就是在运行程序时通过命令行传递参数:
首先使用javac Main.java
编译Java文件生成 class 文件
然后使用java Main 参数1 参数2 参数3...
的形式运行程序,其中空格分隔的每个部分都会成为args数组的一个元素- 2.在IntelliJ IDEA中运行程序,可以通过配置运行参数的方式为args数组赋值
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]
- 因为数组属于引用类型。当执行int[] arrX = arr;时,并没有创建新的数组对象,而是让arrX和arr指向同一块内存地址(即引用同一个数组对象)。
- 因此,当通过arr[0] = 2修改数组元素时,arr和arrX引用的是同一个数组,所以两者的输出结果完全相同
- 数组初始化时未赋值的元素(如arr[2])会使用默认值,int类型的默认值为0。
String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));
2.2字符串是不可变类,为什么可以对strArr[1]赋值"xx"。
字符串的 "不可变" 是指
字符串对象本身的内容不可修改
(如"bb"这个字符串不能被改变)。
但在strArr[1] = "xx"中,我们并不是修改原有字符串"bb"的内容,而是:
- 创建了一个新的字符串对象"xx";
- 将数组strArr的第 1 个元素(原本指向"bb")重新指向了新的字符串对象"xx"。
3.使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach获其他循环方法遍历这个二维数组?
第二维的长度是不确定的
import java.util.Arrays;
public class Main { 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] = null;arr[0][0] = 1;arr[0][1] = 2; arr[1][0] = 3;arr[1][1] = 4;arr[1][2] = 5; arr[2][0] = 6; arr[3][0] = 7;arr[3][1] = 8;arr[3][2] = 9;arr[3][3] = 10; System.out.println("二维数组各行的长度与内容:"); for (int i = 0; i < arr.length; i++) { System.out.println("第" + i + "行(长度:" + (arr[i] == null ? "null" : arr[i].length) + "):" + Arrays.toString(arr[i])); } //使用foreach循环遍历 System.out.println("\n使用foreach遍历所有元素:"); for (int[] row : arr) { if (row != null) {for (int num : row) { System.out.print(num + " "); } } else { System.out.print("(null) "); } } // 使用for循环遍历 System.out.println("\n\n使用for循环遍历所有元素:"); for (int i = 0; i < arr.length; i++) { if (arr[i] != null) { for (int j = 0; j < arr[i].length; j++) { System.out.print(arr[i][j] + " "); } } else { System.out.print("(null) "); } } }
}
4.类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?
区别维度 类(Class) 对象(Object) 定义 是抽象的模板,描述一类事物的共同属性和行为 是具体的实例,是类的具象化产物 存在形式 逻辑概念,不占用内存 物理实体,占用内存空间 关系 类是对象的抽象,对象是类的实例化结果 一个类可以创建多个对象,对象依赖类存在
Math 类没有对象.
Math 类是 Java 中的工具类,其构造方法被声明为private
,且所有方法和属性都是static
(静态)的。所以无法通过new Math()
创建对象;只能通过Math.方法名()
直接调用其功能(如Math.random()
、Math.sqrt()
)。
String类
private public private final char value[]
,存储字符串的字符数组,final修饰表示一旦赋值不可修改(保证字符串不可变)。public int length()
,返回字符串长度(通过value.length实现)。private int hash
,缓存字符串的哈希值,避免每次调用hashCode()时重新计算,提高效率。public String substring(int beginIndex)
,截取子字符串(返回新的 String 对象,不修改原字符串)。
原因:
- 安全性:
私有属性value[]
防止外部直接修改字符数组。如果允许外部修改,可能导致字符串在多线程环境中出现不可预期的行为,或破坏依赖字符串内容的逻辑(如哈希表中的键)。- 封装性与可控性:
通过公共方法(如substring()
)提供修改逻辑,但返回新对象而非修改原对象,保证了字符串的不可变性。这种设计使 String 可以安全地作为 HashMap 的键,且多线程环境下无需额外同步。- 性能优化:
私有属性hash
缓存哈希值,使hashCode()
调用从 O (n) 优化为 O (1),提升哈希表等场景的效率。公共方法length()
直接返回value.length
,既便捷又不暴露内部存储细节。
5.将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?
- 控制访问权限,实现 "读写分离"
- 添加数据校验,保证属性合法性
封装性 : 通过 private 属性隐藏内部数据,仅通过公共方法暴露访问接口,实现 "隐藏细节、暴露必要接口"。
6.对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?
初始化时机:
- 静态属性:仅在类第一次被加载时,通过静态初始化块或声明时初始化,且只执行一次。
- 非静态属性:在对象创建时初始化,执行顺序为:声明时初始化 → 初始化块 → 构造方法。
- 声明时直接初始化
- 构造方法中初始化
- 初始化块(代码块)初始化
- 静态初始化块(针对静态属性)
7.进阶(可选):尝试使用作用域来说明封装性。
封装性的核心是通过控制作用域来隐藏类的内部实现细节,只暴露必要的接口供外部访问。Java 中的作用域修饰符(
private
、default
、protected
、public
)直接决定了类成员(属性和方法)的可访问范围,是实现封装的技术基础。
作用域修饰符从 "最严格" 到 "最宽松" 的顺序为:
private
→default
(默认,无修饰符) →protected
→public
它们的访问范围限制直接体现了封装的 "隐藏" 与 "暴露" 原则:
private
(私有):仅在当前类内部可访问
- 这是封装性最严格的体现,完全隐藏类的内部细节(如属性的存储、内部计算逻辑)。
- 例:
String
类的private char value[]
属性,外部无法直接修改字符数组,只能通过public
方法(如charAt()
)间接访问,保证了字符串的不可变性。
default
(默认):仅在同一包内可访问
- 适用于包内组件的协作,对外隐藏(不同包的类无法访问),实现包级别的封装。
- 例:工具类中辅助方法标记为默认,仅包内其他工具类可调用,避免外部误用。
protected
(受保护):同一包内或子类可访问
- 在隐藏的基础上,为继承关系保留必要的扩展接口,是封装与继承的平衡。
- 例:父类的
protected void init()
方法,允许子类重写初始化逻辑,但禁止无关类调用。
public
(公共):任何地方可访问
- 是类对外暴露的 "接口",仅开放必要的功能(如
getter
方法、业务方法),体现封装的 "最小权限原则"。- 例:
ArrayList
的public int size()
方法,外部只需知道集合大小,无需关心内部数组的存储细节。
总结
封装性通过作用域修饰符划定了类成员的访问边界:
- 用
private
隐藏核心实现(如属性、内部工具方法),确保类对自身状态的绝对控制;- 用
public
(或protected
)暴露必要接口,允许外部以可控方式使用类的功能。