成员变量初始值
Java中所有的变量必须先声明,后赋值才能使用
Java中的成员变量,在创建对象的时候,都会执行一次初始化操作,都会给一个默认值
基本数据类型默认值都是0,包括boolean -> false
引用数据类型:null
null表示空,什么都没有,占位
object
所有的东西都是对象
在Java中所有的类都要继承object
object是一个类,是所有类的根
我们写的类即使不写继承关系,那么默认也会继承object
equals和==
==判断左右两端的数据是或否一致
equals:object类提供的一个方法,用来判断两个对象是否相等
equals可以自己重写
字符串的判断一定要用equals来判断
== :运算符,用于比较两个变量的值是否相等
对于基本数据类型(int, double, char, boolean 等):比较的是数值本身
对于引用数据类型(类、接口、数组等):比较的是内存地址(即是否指向同一个对象)
equals() :方法,属于 java.lang.Object 类,用于比较两个对象的内容是否相等 。默认实现(Object 类中的 equals)与 == 相同,也是比较地址。但许多类(如 String、Integer、Date 等)重写了 equals 方法,使其比较实际内容
一句话总结:== 比较"是不是同一个";equals 比较"内容是否相同"(在重写后)
java
int a = 10;
int b = 10;
System.out.println(a == b); // true
char c1 = 'A';
char c2 = 'A';
System.out.println(c1 == c2); // true
对于基本类型,== 直接比较数值
java
class Person {
String name;
Person(String name) { this.name = name; }
}
Person p1 = new Person("张三");
Person p2 = new Person("张三");
Person p3 = p1;
System.out.println(p1 == p2); // false(不同对象,地址不同)
System.out.println(p1.equals(p2)); // false(Object 默认比较地址)
System.out.println(p1 == p3); // true(同一个对象)
对于自定义类,如果没有重写 equals,则 == 和 equals 效果相同:都比较地址
java
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
// == 比较地址
System.out.println(s1 == s2); // true(字符串常量池,指向同一对象)
System.out.println(s1 == s3); // false(s3 在堆中新建对象)
System.out.println(s3 == s4); // false(两个不同对象)
// equals 比较内容
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // true
System.out.println(s3.equals(s4)); // true
String 类重写了 equals,比较字符序列内容。但需注意字符串常量池的影响
equals 与 == 的比较表格
| 类型 | == 比较什么 |
equals 比较什么(默认) |
equals 重写后比较什么 |
|---|---|---|---|
| 基本数据类型 | 数值 | 不可用 | - |
| 引用类型(未重写 equals) | 内存地址(是否同一对象) | 内存地址(同 ==) |
- |
String |
地址(注意常量池) | 字符串内容 | 内容 |
包装类(Integer 等) |
地址(但有缓存范围) | 数值 | 数值 |
| 数组 | 地址 | 地址(未重写) | 一般用 Arrays.equals() |
自定义类(重写 equals) |
地址 | 可自定义为逻辑相等 | 自定义内容 |
toString
默认的toString() -> 包+类@内存地址
toString() 对一个对象的字符串的表示形式
Java官方推荐你重写这个方法
instanceof
instanceof:判断xxx对象是否是xxx类型
参数传递问题
值传递:把变量的值作为参数进行传递
引用传递:直接把变量作为参数进行传递
Java使用的是值传递
一句话:参数传递的是"值",只不过这个值对于引用类型来说是对象的地址
java
public class Test {
public static void change(int x) {
x = 100; // 修改的是局部副本
System.out.println("方法内部: x = " + x);
}
public static void main(String[] args) {
int a = 10;
change(a);
System.out.println("方法外部: a = " + a);
}
}
// 输出:
// 方法内部: x = 100
// 方法外部: a = 10
当参数是基本类型时,方法接收的是原始值的拷贝。方法内部对参数的任何修改都不会影响外部变量
内存分析
java
栈内存:
main: a = 10
change: x = 10 (拷贝,修改 x 不影响 a)
当参数是引用类型时,传递的是引用的拷贝 (即对象地址的副本)。方法内部可以通过这个地址访问和修改对象的内容,但无法改变原始引用变量指向的对象
java
class Person {
String name;
Person(String name) { this.name = name; }
}
public class Test {
public static void changeName(Person p) {
p.name = "李四"; // 通过引用修改对象内容(有效)
}
public static void changeRef(Person p) {
p = new Person("王五"); // 修改的是引用的副本(无效)
System.out.println("方法内部: p.name = " + p.name);
}
public static void main(String[] args) {
Person person = new Person("张三");
changeName(person);
System.out.println(person.name); // 李四
changeRef(person);
System.out.println(person.name); // 李四(未被改变)
}
}
// 输出:
// 李四
// 方法内部: p.name = 王五
// 李四
内存分析
java
栈内存:
main: person -----> 堆内存对象 { name = "张三" }
changeName: p -----> 同一对象(地址拷贝)
p.name = "李四"; // 修改对象内容,原始 person 也看到变化
changeRef: p -----> 同一对象(地址拷贝)
p = new Person("王五"); // p 指向新对象,但原始 person 仍指向原对象
常见误区澄清
| 误区 | 正确理解 |
|---|---|
| "Java 对引用类型是引用传递" | 错误。Java 只有值传递,传递的是引用的值(地址)。 |
| "方法内修改参数会影响外部变量" | 对于基本类型,不会;对于引用类型,只能修改对象内容,不能改变引用本身。 |
| "交换两个对象参数可以影响外部" | 不能,因为交换的是引用的副本。 |
| "字符串传递时修改会生效" | 不会,因为字符串是不可变的,任何改变都会产生新对象。 |
| "数组参数传递的是数组本身" | 传递的是数组引用的副本,但可以通过索引修改元素。 |