java复习 13
1 两个char字符型的数据相加会得到什么?
char
类型的数据本质上是整数,代表着 ASCII 码或者 Unicode 码点。
当对两个char
类型的数据进行相加操作时,实际上执行的是整数加法运算,最终得到的结果是一个int
类型的整数。
下面为你举个例子来详细说明:
java
public class CharAddition {public static void main(String[] args) {char a = 'A'; // ASCII码值为65char b = 'B'; // ASCII码值为66int sum = a + b;System.out.println(sum); // 这里会输出131(也就是65 + 66的结果)}
}
深入分析
- 数据类型转换规则:在 Java 中,当
char
类型参与算术运算时,会自动将其转换为int
类型,这是由 Java 的类型提升规则所决定的。 - 运算本质:从本质上来说,字符相加就是对它们对应的数值进行加法运算。
- 结果类型:不管是哪种情况,相加后的结果必然是
int
类型,而非char
类型。
要是你希望得到一个字符结果,那就需要进行强制类型转换,示例如下:
java
char result = (char) (a + b); // 把整数结果转换为char类型
System.out.println(result); // 输出字符 '�'(该字符对应的码点是131)
总结
- 两个
char
类型的数据相加,得到的是一个int
类型的数值,这个数值是这两个字符对应 ASCII 码值的和。 - 若想得到字符结果,就需要手动进行强制类型转换,不过要留意转换后可能会出现字符无法正常显示的情况。
2 类和对象的关系
在面向对象编程中,类和对象的关系是:类是对象的抽象描述,而对象是类的具体实例。这是面向对象编程的核心概念之一。
详细解释
-
类(Class)
- 定义:类是一种抽象的模板或蓝图,它定义了对象的属性(数据)和方法(行为)。
- 特点:类本身不占用内存空间,它只是描述了对象的共性。
- 示例:
java
// 类:汽车的抽象描述 public class Car {private String color; // 属性:颜色private int speed; // 属性:速度public void accelerate() { // 方法:加速speed += 10;} }
-
对象(Object)
- 定义:对象是类的具体实例,是根据类的模板创建出来的实体。
- 特点:每个对象都有自己独立的属性值,且占用内存空间。
- 示例:
java
// 创建两个Car类的对象(实例) Car car1 = new Car(); // car1是Car类的一个对象 Car car2 = new Car(); // car2是另一个对象car1.color = "红色"; // car1的颜色是红色 car2.color = "蓝色"; // car2的颜色是蓝色
关键区别
类 | 对象 |
---|---|
抽象的模板 | 具体的实例 |
定义属性和方法的结构 | 拥有具体的属性值和行为 |
不占用内存 | 占用内存空间 |
例如:汽车设计图 | 例如:实际的一辆汽车 |
总结
- 类是对象的抽象:类定义了对象 “是什么” 和 “能做什么”。
- 对象是类的实例化:通过类创建对象的过程称为 “实例化”,对象是类的具体表现。
因此,对象是类的实例化具体化。
3 再明确一下方法重载和重写的规则
方法重载返回值类型可以相同也可以不同!
方法重载的规则是:
参数列表必须不同(参数类型、数量或顺序不同),而返回值类型可以相同也可以不同,但不能作为重载的唯一依据。
方法重写的关键规则(Override)的核心规则是:
方法签名(方法名 + 参数列表)必须与父类完全相同,仅允许修改方法的实现逻辑(方法体)。以下是详细说明:
-
方法签名必须相同
- 方法名、参数类型、数量和顺序必须与父类方法一致。
- 若参数列表不同,则成为方法重载(Overload),而非重写。
-
返回值类型必须兼容
- 要么与父类方法完全相同,要么是父类返回值类型的子类(协变返回)。
-
访问修饰符不能更严格
- 例如父类方法是
protected
,子类重写时不能是private
。
- 例如父类方法是
-
异常声明范围更小
- 子类方法不能抛出比父类更宽泛的异常。
总结
- 方法重写:签名不变,逻辑变(保持方法名、参数、返回值类型不变,修改方法体)。
- 方法重载:签名可变,逻辑相关(方法名相同,但参数列表不同)。
4 用 equals 比较
同一个类的两个对象可以相互赋值,赋值后两个对象具有相同的存储空间,用 equals 比较的时候是比较存储地址,应该会返回 true
-
“同一个类的两个对象可以相互赋值”
- 正确:Java 中对象赋值是引用传递,例如
Object obj2 = obj1
,此时obj2
指向obj1
的内存地址,二者引用同一对象。
- 正确:Java 中对象赋值是引用传递,例如
-
“赋值后两个对象具有相同的存储空间”
- 正确:这里的 “存储空间” 指对象在堆内存中的地址,赋值后两个引用指向同一地址,因此存储空间相同。
-
“用 equals 比较的时候是比较存储地址,应该会返回 true”
- 部分正确:
- 若未重写
equals()
方法,equals()
默认比较引用地址,此时因两个引用指向同一对象,equals()
返回true
。 - 若重写了
equals()
方法(如比较对象内容),则结果取决于重写逻辑,可能返回false
(即使引用相同,但若重写逻辑有异常)。
- 若未重写
- 部分正确:
在没有重写equals()
方法的情况下,Java 中对象的equals()
行为完全等同于==
,即比较两个对象的引用地址。
5 值传递(方法参数是独立的局部变量,与类成员变量无关)
执行下面的程序,输出结果是(10)。public class Test { int x= 12; public void method(int x) { x+=x; System.out.println(x); } public static void main(String[] args){ Test t = new Test(); t.method(5); }}
Q:
int x作为参数,创了一个新的x参数副本,但是原来test类里面的x并不会被改变,此x非彼x,这么理解值传递对不对?
A:
你的理解完全正确!在 Java 中,方法参数传递是值传递(Pass by Value),具体表现为:
-
基本类型参数(如
int
):- 传递的是值的副本,方法内对参数的修改不会影响原始变量。
- 示例中,
method(int x)
的参数x
是局部变量,与类成员变量x
无关。
-
引用类型参数(如
Object
):- 传递的是引用的副本(即对象地址的拷贝),而非对象本身。
- 若方法内修改引用指向的对象(如调用对象的 setter),会影响原始对象;但重赋值引用(如
obj = new Object()
)不会影响外部引用。
关键验证示例
以下代码演示了值传递的两种场景:
java
public class ParameterPassing {public static void main(String[] args) {// 场景1:基本类型参数int num = 10;modifyPrimitive(num);System.out.println("基本类型:" + num); // 输出:10(未改变)// 场景2:引用类型参数StringBuilder sb = new StringBuilder("Hello");modifyReference(sb);System.out.println("引用类型:" + sb); // 输出:Hello World(对象被修改)// 场景3:重赋值引用参数StringBuilder another = new StringBuilder("Java");resetReference(another);System.out.println("重赋值引用:" + another); // 输出:Java(未改变)}// 修改基本类型参数static void modifyPrimitive(int x) {x += 10; // 修改的是副本,不影响原始值}// 修改引用指向的对象static void modifyReference(StringBuilder sb) {sb.append(" World"); // 修改原对象内容}// 重赋值引用参数static void resetReference(StringBuilder sb) {sb = new StringBuilder("New"); // 仅修改副本的指向,不影响原始引用}
}
输出结果解释
plaintext
基本类型:10 // modifyPrimitive未改变原始值
引用类型:Hello World // modifyReference修改了原对象
重赋值引用:Java // resetReference未影响外部引用
核心区别总结
参数类型 | 传递内容 | 方法内修改的影响 |
---|---|---|
基本类型 | 值的副本 | 不影响原始变量 |
引用类型 | 引用的副本(地址) | 修改对象内容会影响原始对象 重赋值引用不会影响外部引用 |
你的理解 “此 x 非彼 x” 非常准确,即方法参数是独立的局部变量,与类成员变量无关。这种机制保证了方法调用的安全性和可维护性。
6 同名变量在子类中会隐藏父类的变量
以下程序运行结果是 fatherpublic class Test extends Father{ private String name="test"; public static void main(String[] args){ Test test = new Test(); System.out.println(test.getName()); }}class Father{ private String name="father"; public String getName() { return name; }}
关键步骤解析
-
继承与成员变量隐藏:
Test
类继承自Father
,但Test
类中定义了同名的私有变量private String name="test"
。- 由于
name
在Father
中是 private,Test
类无法直接访问或覆盖它,而是隐藏了父类的name
变量。
-
方法重写规则:
Test
类没有重写getName()
方法,因此test.getName()
实际调用的是 父类Father
的getName()
方法。
-
父类方法的作用域:
Father
类的getName()
方法只能访问其自身的name
变量(值为"father"
),无法访问子类的同名变量。
验证代码
java
public class Test extends Father {private String name = "test"; // 隐藏父类的name变量public static void main(String[] args) {Test test = new Test();System.out.println(test.getName()); // 调用父类的getName()}
}class Father {private String name = "father"; // 父类的私有变量public String getName() { // 未被子类重写return name; // 返回父类的name}
}
输出结果
plaintext
father
常见误区!!!!
- 成员变量不能被重写:只有方法可以被重写,成员变量只能被隐藏(同名变量在子类中会隐藏父类的变量)。
- 方法调用绑定:
test.getName()
的调用在编译时已确定为父类的方法,即使子类有同名变量,也不会影响父类方法的逻辑。
若要访问子类的 name
需在 Test
类中重写 getName()
方法:
java
public class Test extends Father {private String name = "test";@Overridepublic String getName() { // 重写父类方法return this.name; // 返回子类的name}public static void main(String[] args) {Test test = new Test();System.out.println(test.getName()); // 输出 "test"}
}
7 实例变量和静态变量会有默认初始值,而局部变量若未显式赋值则会报错
一、变量分类与初始化规则
变量类型 | 定义位置 | 默认值情况 | 未初始化的结果 |
---|---|---|---|
实例变量 | 类中(方法外) | 有默认值(如int=0 ,boolean=false ) | 直接使用默认值,不会报错 |
静态变量 | 类中(方法外)且用static 修饰 | 有默认值,规则同实例变量 | 直接使用默认值,不会报错 |
局部变量 | 方法内或代码块中 | 没有默认值 | 未赋值就使用会编译报错 |
二、“值不确定” 的情况:局部变量
1. 局部变量未初始化的报错示例
java
public class VariableDemo {public void method() {int num; // 局部变量,未初始化System.out.println(num); // 编译错误:变量可能尚未初始化}
}
- 原因:局部变量的作用域仅限方法或代码块,Java 不会为其赋予默认值,必须显式赋值后才能使用。
2. 为什么实例变量和静态变量有默认值?
- 设计目的:实例变量和静态变量属于类的成员,其生命周期与对象或类相关。
- 为避免 null 或 0 等默认值导致逻辑问题,Java 强制赋予默认值(例如:
- 数值类型:
0
(int
)、0.0
(double
) - 布尔类型:
false
- 引用类型:
null
)。
- 数值类型:
三、特殊场景:数组元素的初始化
- 数组本质是对象,其元素作为 “实例变量” 存在,因此有默认值:
java
int[] arr = new int[5]; // 每个元素默认0 String[] strArr = new String[3]; // 每个元素默认null
四、总结:“值不确定” 的唯一情况
仅当局部变量未显式赋值时,使用该变量会报错(而非 “值不确定”)。Java 中不存在 “值不确定” 的合法变量 —— 实例 / 静态变量有默认值,局部变量必须初始化,否则编译不通过。
示例对比
java
public class VariableTest {int instanceVar; // 实例变量,默认0static int staticVar; // 静态变量,默认0public void test() {int localVar; // 局部变量,未初始化// System.out.println(localVar); // 报错!必须先赋值localVar = 10; // 显式赋值后才能使用System.out.println(localVar); // 输出10}public static void main(String[] args) {VariableTest test = new VariableTest();System.out.println(test.instanceVar); // 输出0(实例变量默认值)System.out.println(VariableTest.staticVar); // 输出0(静态变量默认值)}
}