成员变量初始值

Java中所有的变量必须先声明,后赋值才能使用

Java中的成员变量,在创建对象的时候,都会执行一次初始化操作,都会给一个默认值

基本数据类型默认值都是0,包括boolean -> false

引用数据类型:null

null表示空,什么都没有,占位

object

所有的东西都是对象

在Java中所有的类都要继承object

object是一个类,是所有类的根

我们写的类即使不写继承关系,那么默认也会继承object

equals和==

==判断左右两端的数据是或否一致

equals:object类提供的一个方法,用来判断两个对象是否相等

equals可以自己重写

字符串的判断一定要用equals来判断

==:运算符,用于比较两个变量的值是否相等

对于基本数据类型(intdoublecharboolean 等):比较的是数值本身

对于引用数据类型(类、接口、数组等):比较的是内存地址(即是否指向同一个对象)

equals():方法,属于 java.lang.Object 类,用于比较两个对象的内容是否相等。默认实现(Object 类中的 equals)与 == 相同,也是比较地址。但许多类(如 StringIntegerDate 等)重写了 equals 方法,使其比较实际内容

一句话总结:== 比较“是不是同一个”;equals 比较“内容是否相同”(在重写后)

int a = 10;
int b = 10;
System.out.println(a == b);   // true

char c1 = 'A';
char c2 = 'A';
System.out.println(c1 == c2); // true

对于基本类型,== 直接比较数值

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 效果相同:都比较地址

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使用的是值传递

一句话:参数传递的是“值”,只不过这个值对于引用类型来说是对象的地址

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

当参数是基本类型时,方法接收的是原始值的拷贝。方法内部对参数的任何修改都不会影响外部变量

内存分析

栈内存:
main: a = 10
change: x = 10 (拷贝,修改 x 不影响 a)

当参数是引用类型时,传递的是引用的拷贝(即对象地址的副本)。方法内部可以通过这个地址访问和修改对象的内容,但无法改变原始引用变量指向的对象

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 = 王五
// 李四

内存分析

栈内存:
main: person -----> 堆内存对象 { name = "张三" }
changeName: p -----> 同一对象(地址拷贝)
    p.name = "李四";   // 修改对象内容,原始 person 也看到变化

changeRef: p -----> 同一对象(地址拷贝)
    p = new Person("王五");   // p 指向新对象,但原始 person 仍指向原对象
常见误区澄清
误区正确理解
“Java 对引用类型是引用传递”错误。Java 只有值传递,传递的是引用的值(地址)。
“方法内修改参数会影响外部变量”对于基本类型,不会;对于引用类型,只能修改对象内容,不能改变引用本身。
“交换两个对象参数可以影响外部”不能,因为交换的是引用的副本。
“字符串传递时修改会生效”不会,因为字符串是不可变的,任何改变都会产生新对象。
“数组参数传递的是数组本身”传递的是数组引用的副本,但可以通过索引修改元素。

更多推荐