首页 / Java 入门教程 / 类与对象

Java 入门教程

类与对象

本教程共 100 篇 · 第 30 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

JavaJava 入门教程对象new引用

本节目标:搞懂”类是模板、对象是实例”的关系,学会定义类和用 new 创建对象,并说清对象在内存里长什么样、引用和对象的区别在哪。

类和对象是面向对象的地基。一句话区分:类是图纸,对象是按图纸盖出来的房子。图纸只有一份,房子能盖很多套。

图纸本身不能住人。你没法在图纸上放家具,也没法在图纸上做饭——得先盖出真房子。类和对象就是这个关系。

定义一个类

类用 class 关键字定义,花括号里写两样东西:成员变量(这类东西”有什么”)和方法(这类东西”能做什么”)。

public class Student {
    String name;             // 成员变量:姓名
    int age;                 // 成员变量:年龄

    void study() {           // 方法:行为
        System.out.println(name + " 在学习");
    }
}

这段代码执行时什么也不会发生。它只是告诉编译器:以后每个学生对象都长这样,带一个姓名、一个年龄,会学习。

类名用大驼峰,首字母大写,是 Java 的通行约定。看到 Student 就知道是类,看到 student 就知道是变量。

用 new 创建对象

想要真实数据,必须 new 出一个对象(也叫实例)。

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student();   // 造第一个学生
        s1.name = "小明";
        s1.age = 18;
        s1.study();                   // 输出:小明 在学习

        Student s2 = new Student();   // 再造一个,互不影响
        s2.name = "小红";
        s2.study();                   // 输出:小红 在学习
    }
}

第一行拆开看,它其实同时干了两件事:

  • 等号右边的 new Student()堆内存里造出一个真实对象。
  • 等号左边的 Student s1栈内存里开一个变量,用来记住那个对象在哪。

访问对象里的东西统一用点号:对象名.成员变量对象名.方法名()

new 到底做了什么

new Student() 这一下,JVM 依次做了三件事:

  1. 分配内存:在堆里划出一块空间,够放 Student 的所有成员变量。
  2. 赋默认值:所有成员变量先被写成该类型的零值,不会是随机垃圾数据。
  3. 返回地址:把这块内存的地址交出来,赋给等号左边的变量。

第 2 步的默认值规则要背下来:

成员变量类型默认值
byte / short / int / long0
float / double0.0
char\u0000(空字符,打印看不见)
booleanfalse
任何引用类型(String、数组、自定义类)null

所以刚 new 出来的学生,名字是 null,年龄是 0。不赋值直接打印不会报错,只是值没意义。

Note

只有成员变量享受这个待遇。方法里的局部变量没有默认值,不赋值就用会被编译器当场拦下。这条区别是下一章的重点。

栈里的引用,堆里的对象

很多初学者以为”s1 就是那个学生对象”。准确说法是:s1 是一根指向对象的绳子,对象在堆里。

        栈(stack)              堆(heap)
   ┌──────────────┐        ┌──────────────────┐
   │ s1  ● ───────┼───────▶│ name  = "小明"   │
   ├──────────────┤        │ age   = 18       │
   │ s2  ● ───────┼──┐     └──────────────────┘
   └──────────────┘  │     ┌──────────────────┐
                     └────▶│ name  = "小红"   │
                           │ age   = 0        │
                           └──────────────────┘

栈里的变量很小,只装一个地址;堆里才是真正的数据。方法执行完,栈上的变量就没了;堆里的对象只要还有人指着,就一直活着,没人指了才等垃圾回收。

多个对象各玩各的

s1 和 s2 是两块独立的堆内存,改一个不影响另一个:

s1.age = 20;
System.out.println(s2.age);   // 0,s2 还是默认值,纹丝不动

这正是面向对象”各自管好自己数据”的体现。造一百个学生对象,就有一百份互不干扰的姓名和年龄。

方法却不是这样。study 的代码只在方法区存一份,一百个对象共用同一段指令。区别在于每次调用时,方法内部看到的 name 是哪个对象的那一份。所以准确说法是:数据每个对象一份,代码全类共享一份

多个引用指向同一个对象

反过来,一个对象可以被好几根绳子拽着:

Student s3 = s1;              // 没有造新对象,只是复制了地址
s3.age = 21;
System.out.println(s1.age);   // 21,通过 s3 改的,s1 也看得见

赋值传的是地址,不是对象副本。s1 和 s3 是同一栋房子的两把钥匙,谁进去搬家具,另一个都看得到。

判断”是不是同一个对象”用 ==,它比的就是这两个地址:

System.out.println(s1 == s3);   // true,同一个对象
System.out.println(s1 == s2);   // false,两个不同对象

要比”内容是不是一样”得用 equals,第 54 章讲。参数传递里的坑在第 37 章深挖。

引用是 null 时会炸

如果一根绳子没系在任何对象上,它的值就是 null。这时候点它必炸:

public class Main {
    public static void main(String[] args) {
        Student s = null;
        System.out.println(s.name);   // 运行时抛异常
    }
}

运行输出:

Exception in thread "main" java.lang.NullPointerException: Cannot read field "name" because "<local1>" is null
	at Main.main(Main.java:4)

读这行报错的方法:冒号后面那句是 Java 14 起提供的”详细空指针信息”,它直接点名是谁为 null你想拿它干什么Cannot read field "name" 说明你在读字段,because ... is null 说明持有者是空的。

<local1> 是变量在字节码里的槽位编号。加上 -g 参数重新编译,就能看到真实变量名:

javac -g Main.java
java Main

这次报错会写成 because "s" is null,定位更快。

Warning

空指针是 Java 里最高频的运行时异常,没有之一。只要看到 NullPointerException,第一反应就是”哪个引用忘了 new”。声明了变量不等于创建了对象,这是两步。

一个文件里能放几个类

// 文件名必须叫 Main.java
public class Main {                 // public 类,名字必须和文件名一致
    public static void main(String[] args) {
        Student s = new Student();
        s.name = "小明";
        s.study();
    }
}

class Student {                     // 非 public 类,可以和上面同一个文件
    String name;
    void study() {
        System.out.println(name + " 在学习");
    }
}

规则是:一个 .java 文件里 public 类最多一个,且类名必须和文件名一模一样;非 public 的类想放几个放几个。练习阶段把它们塞进一个文件最省事,真实项目里通常一个类一个文件。

文件名写错的话,编译直接失败:

error: class Main is public, should be declared in a file named Main.java

常见疑问

Q:类名后面那对空括号 new Student() 是什么?能省吗?

A:不能省,它是在调用构造方法。你没写构造方法时,编译器会偷偷送你一个空的无参构造。第 33 章会把这套规则讲透。

Q:对象用完要手动销毁吗?

A:不用。Java 有垃圾回收器,当一个对象再也没有任何引用指向它,就会被自动回收。把引用置成 null 可以提前断开这根绳子,但绝大多数场景不需要你操心。

Q:Student s; 只声明不 new,能用吗?

A:局部变量这么写,不赋值就使用会编译报错;赋成 null 再点字段则是运行时空指针。想安全使用,必须先 new 出真实对象。

Q:直接打印对象为什么是一串乱码似的东西?

A:打印 s1 得到类似 Student@1b6d3586 的结果,这是类名加哈希码的默认格式,来自根类 Object 的 toString 方法。想让它打印得像人话,就在自己的类里重写 toString,第 54 章会演示。

Tip

把”类 = 图纸、对象 = 房子、引用 = 钥匙”这三个词的对应关系记牢,后面学继承、多态、参数传递都会轻松很多。下一章拆开对象内部,看看变量放在不同位置有什么不同。