Java 类与对象
面向对象基础
类与对象
- 类:一组具有相同属性和行为的对象的抽象描述。它是创建对象的模板。
- 对象:类的具体实例,代表现实世界中某个具体的事物。
- 成员变量:对象的属性(状态)。
- 成员方法:对象的行为(操作)。
关系:类是对象的抽象,对象是类的实例。类不占用内存,而对象存储在堆内存中。
示例:学生类
class Student {
// 成员变量
String name; // 姓名
char sex; // 性别
int age; // 年龄
// 成员方法
public void learn() {
System.out.println(this.name + "正在学习");
}
public void dine() {
System.out.println(this.name + "正在吃饭");
}
}
成员变量与局部变量
| 比较项 | 成员变量 | 局部变量 |
|---|---|---|
| 定义位置 | 类中,方法外 | 方法定义中、方法参数、代码块内 |
| 生命周期 | 随对象的创建而存在,随对象被回收而消失 | 随方法的调用而存在,方法结束即消失 |
| 初始化值 | 有默认值(如 null, 0, false) | 无默认值,必须显式赋值后才能使用 |
| 内存位置 | 堆内存(对象本身存储在堆中) | 栈内存(方法调用时压入栈帧) |
| 作用域 | 在整个类中有效 | 仅在定义它的方法或代码块内有效 |
补充说明:
- 引用类型的局部变量本身存储在栈中,但指向的对象仍在堆中。
- 类变量(static 修饰)存储在方法区。
访问权限修饰符
Java 提供了四种访问权限控制级别,用于控制类、成员变量、方法的可见性。
| 修饰符 | 本类 | 同包 | 子类(不同包) | 其他包 |
|---|---|---|---|---|
public |
√ | √ | √ | √ |
protected |
√ | √ | √ | |
default(无修饰符) |
√ | √ | ||
private |
√ |
- public:所有类都可访问。
- protected:同包类、不同包子类可访问。
- default:仅同包类可访问。
- private:仅本类内部可访问。
构造方法
构造方法是一种特殊的方法,用于初始化新创建的对象。
特点
- 方法名必须与类名完全相同。
- 没有返回值类型(连
void也不能写)。 - 可以重载(多个参数列表不同的构造方法)。
- 在创建对象时通过
new关键字自动调用。
示例
class Apple {
int sum;
String color;
// 无参构造
public Apple() {}
// 有参构造
public Apple(int sum) {
this.sum = sum;
}
public Apple(String color) {
this.color = color;
}
public Apple(int sum, String color) {
this.sum = sum;
this.color = color;
}
}
// 使用
Apple a1 = new Apple(); // 调用无参构造
Apple a2 = new Apple(10); // 调用 int 参数构造
Apple a3 = new Apple("red"); // 调用 String 参数构造
Apple a4 = new Apple(5, "green");
注意事项
- 如果类中没有显式定义任何构造方法,编译器会自动生成一个无参构造方法。
- 一旦定义了任何构造方法,编译器就不再提供默认无参构造,若仍需无参构造则必须手动编写。
上图错误原因是:必须提供Apple带有int参数的构造方法,而默认的无参构造方法没有被允许使用。
深入理解:类的生命周期(JVM层面)
Java 类从被加载到虚拟机内存中,到卸载出内存,完整生命周期包括以下阶段:
加载(Loading)
作用:通过类的全限定名获取二进制字节流,并将其转化为方法区的运行时数据结构,同时在堆中生成一个 java.lang.Class 对象作为访问入口。
类加载器分类:

- 启动类加载器(Bootstrap ClassLoader):加载
JAVA_HOME/lib目录下的核心类(如rt.jar)。 - 扩展类加载器(Extension ClassLoader):加载
JAVA_HOME/lib/ext目录下的类。 - 应用程序类加载器(Application ClassLoader):加载用户类路径(
classpath)上的类。
双亲委派模型:
当一个类加载器收到加载请求时,首先将任务委派给父类加载器,最终由启动类加载器尝试加载。只有当父类加载器无法完成时,子加载器才会自己加载。这保证了核心类库(如 java.lang.Object)在任何环境下都是同一份。
链接(Linking)
- 验证(Verify):确保字节码符合规范,不会危害 JVM 安全。
- 准备(Prepare):为静态变量分配内存,并设置默认初始值(如 0, null, false)。注意:
final static变量在准备阶段直接赋值为编译时常量。 - 解析(Resolve):将常量池中的符号引用替换为直接引用(如内存地址或偏移量)。
初始化(Initialization)
核心操作:执行类构造器 <clinit>() 方法,该方法由编译器收集静态变量赋值动作和静态代码块合并而成。
<clinit>() 方法特点:
- 由 JVM 保证线程安全(多线程环境下只会有一个线程执行)。
- 父类的
<clinit>()优先于子类执行。 - 接口的
<clinit>()不要求父接口先执行,仅当使用父接口变量时才触发。
触发类初始化的场景(主动引用)
- 使用
new关键字实例化对象、读取或设置静态变量(被 final 修饰且已放入常量池的除外)、调用静态方法。 - 对类进行反射调用。
- 初始化子类时,如果父类尚未初始化,则先触发父类初始化。
- 虚拟机启动时,包含
main()方法的主类会先被初始化。 - 使用
java.lang.invoke.MethodHandle时,对应的方法句柄指向的类如果未初始化则触发。
不会触发类初始化的场景(被动引用)
- 通过子类引用父类的静态字段,只会触发父类初始化,不会触发子类。
- 定义对象数组(如
Apple[] arr = new Apple[10])不会触发Apple类初始化。 - 引用编译时常量(如
static final int MAX = 100)不会触发定义常量的类初始化。 - 通过
Class.forName()加载类时指定initialize=false。 - 通过
ClassLoader.loadClass()加载类不会触发初始化。
总结
- 类与对象是面向对象编程的核心,理解它们的区别与联系是基础。
- 成员变量和局部变量在生命周期、存储位置、默认值等方面有明显差异。
- 访问权限修饰符用于封装和控制可见性。
- 构造方法负责对象初始化,注意默认构造方法的生成规则。
- 深入 JVM 层面的类加载机制有助于理解 Java 程序的执行过程,是进阶必备知识。
掌握这些内容,你将对 Java 的类与对象有一个全面且深刻的认识。

浙公网安备 33010602011771号