跳到主要内容
Java 类的实例化与封装详解 | 极客日志
Java java
Java 类的实例化与封装详解 综述由AI生成 Java 中对象的构造与初始化机制,包括构造方法的概念、特性、重载规则以及默认初始化和就地初始化的区别。同时阐述了面向对象编程中的封装概念,讲解了访问限定符(public、protected、default、private)的作用及使用规范。此外,还涵盖了包的管理、导入方式(import、全类名、静态导入)以及 IDE 中的包结构实践。通过示例代码演示了如何在实际开发中合理设计类结构,保护数据安全,并避免命名冲突。最后总结了构造器链、成员变量初始化顺序及包权限控制的关键点,为后续学习静态成员、代码块及内部类打下基础。
颠三倒四 发布于 2026/3/27 更新于 2026/6/2 24 浏览类和对象(中)
五、对象的构造及初始化
5.1 如何初始化对象
通过前面知识点的学习我们知道,在 Java 方法内部定义一个局部变量时,必须要初始化,否则会编译失败。
public static void main (String[] args) {
int a;
System.out.println(a);
}
要让上述代码通过编译,非常简单,只需在正式使用变量之前给它设置初始值即可。
public static void main (String[] args) {
Date d = new Date ();
d.printDate();
d.setDate(2021 , 6 , 9 );
d.printDate();
}
如果是对象,就需要调用之前写的 setDate 方法将具体的日期设置到对象中。
通过上述例子我们发现两个问题:
问题 1 :每次对象创建好后调用 setDate 方法设置具体日期显得比较麻烦,那么对象该如何初始化?
问题 2 :局部变量必须初始化才能使用,而字段声明之后没有给值依然可以使用,这是因为字段具有默认初始值。
为了解决问题 1,Java 引入了 构造方法 ,使得对象在创建时就能完成初始化操作。
5.2 构造方法
构造方法(也称为构造器)是一种特殊的成员方法,其主要作用是初始化对象。
5.2.1 构造方法的概念
public class Date {
public int year;
public int month;
public int day;
public {
.year = year;
.month = month;
.day = day;
System.out.println( );
}
{
System.out.println(year + + month + + day);
}
{
( , , );
d.printDate();
}
}
Date
(int year, int month, int day)
this
this
this
"Date(int,int,int) 方法被调用了"
public
void
printDate
()
"-"
"-"
public
static
void
main
(String[] args)
Date
d
=
new
Date
2021
6
9
名字必须与类名相同 ,且没有返回值类型(连 void 都不行)。
在创建对象时由编译器自动调用 ,并且在对象的生命周期内只调用一次。注意:构造方法的作用是对对象中的成员进行初始化,并不负责给对象开辟内存空间。
5.2.2 构造方法的特性
名字必须与类名完全相同
没有返回值类型 ,即使设置为 void 也不行
创建对象时由编译器自动调用 ,且在对象生命周期内只调用一次(就像人的出生,每个人只能出生一次)
支持重载 :同一个类中可以定义多个构造方法,只要参数列表不同即可
public class Date {
public int year;
public int month;
public int day;
public Date (int year, int month, int day) {
this .year = year;
this .month = month;
this .day = day;
System.out.println("Date(int, int, int) 方法被调用了" );
}
public void printDate () {
System.out.println(year + "-" + month + "-" + day);
}
public static void main (String[] args) {
Date d = new Date (2021 , 6 , 9 );
System.out.println("Date(int, int, int) 方法被调用了" );
d.printDate();
System.out.println("2021-6-9" );
}
}
public class Date {
public int year;
public int month;
public int day;
public Date () {
this .year = 1900 ;
this .month = 1 ;
this .day = 1 ;
}
}
上述两个构造方法名字相同但参数列表不同,构成了方法的重载。
如果用户没有显式定义构造方法,编译器会生成一个默认的无参构造方法。
注意:一旦用户显式定义了构造方法,编译器就不会再生成默认构造方法了。
示例代码 3:仅定义带参构造方法时默认构造方法不会生成
public Date (int year, int month, int day) {
this .year = year;
this .month = month;
this .day = day;
}
public void printDate () {
System.out.println(year + "-" + month + "-" + day);
}
public static void main (String[] args) {
Date d = new Date ();
d.printDate();
}
public class Date {
public int year;
public int month;
public int day;
public void printDate () {
System.out.println(year + "-" + month + "-" + day);
}
public static void main (String[] args) {
Date d = new Date ();
d.printDate();
}
}
public class Date {
public int year;
public int month;
public int day;
public Date (int year, int month, int day) {
this .year = year;
this .month = month;
this .day = day;
}
}
构造方法中可以通过 this(...) 调用其他构造方法来简化代码。
注意:this(...) 必须是构造方法中的第一条语句,否则编译器会报错。
示例代码 6:正确使用 this(...) 实现构造器链
public class Date {
public int year;
public int month;
public int day;
public Date () {
this (1900 , 1 , 1 );
}
public Date (int year, int month, int day) {
this .year = year;
this .month = month;
this .day = day;
}
}
注意:构造方法中的 this(...) 调用不能形成循环,否则会导致编译错误。
public Date () {
this (1900 , 1 , 1 );
}
public Date (int year, int month, int day) {
this ();
}
在大多数情况下,我们使用 public 来修饰构造方法,但在特殊场景下(如实现单例模式)可能会使用 private 修饰构造方法。
5.3 默认初始化 在上文中提到的第二个问题:为什么局部变量在使用前必须初始化,而成员变量可以不初始化?
要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:
Date d = new Date (2021 , 6 , 9 );
在程序员看来只是一句简单的语句,但 JVM 层面需要做好多事情。下面简单介绍下:
检测对象对应的类是否被加载,如果没有则加载
为对象分配内存空间并先默认初始化
处理并执行类中的 init 方法
初始化分配好的空间 (说明:多个线程同时申请资源,JVM 要保证分配给对象的空间内干净)
即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:Java 中的 成员变量 会由 JVM 自动赋予默认值(如 int 类型为 0,boolean 类型为 false 等),而局部变量则需要显式初始化才能使用。
Java 为不同的数据类型提供了默认值,具体如下所示:
数据类型 默认值 byte 0 char '\u0000' short 0 int 0 long 0L boolean false float 0.0f double 0.0d reference null
这些默认值确保了即使对象的成员变量没有显式初始化,也不会发生错误,成员变量会有一个初始的稳定状态。
设置对象头信息 (关于对象内存模型后面会介绍)
调用构造方法,给对象中各个成员赋值
5.4 就地初始化 就地初始化是指在成员变量声明时直接为它们赋初值。这种方法在代码的简洁性上具有优势,可以避免每次创建对象时重复设置成员变量的值。
public class Date {
public int year = 1900 ;
public int month = 1 ;
public int day = 1 ;
public Date () {
}
public void printDate () {
System.out.println(year + "-" + month + "-" + day);
}
public static void main (String[] args) {
Date d = new Date ();
d.printDate();
}
}
在这个例子中,year、month 和 day 的值在声明时就被初始化为 1900、1 和 1,确保了每次创建对象时这些值已经存在。
六、封装
6.1 封装的概念 封装是面向对象编程的三大特性之一,其核心思想是将数据和操作数据的方法结合在一起,并对外隐藏实现细节。
例如,电脑作为一个复杂的设备,用户只需通过开关、键盘和鼠标等接口进行交互,而不必关心内部 CPU、显卡等工作原理。
6.2 访问限定符
public :可以理解为一个人的外部接口,能被外部访问。
protected :主要是给继承使用,子类继承后就能访问到。
default (不写修饰符时即为默认访问修饰符):对于同一包内的类可见,不同包则不可见。
private :只能在当前类中访问。
【说明】protected 主要是给继承使用;default 只能给同一个包内使用;按照自己的理解去记忆。
public class Computer {
private String cpu;
private String brand;
private String memory;
private String screen;
public Computer (String brand, String cpu, String memory, String screen) {
this .brand = brand;
this .cpu = cpu;
this .memory = memory;
this .screen = screen;
}
public void boot () {
System.out.println("开机" );
}
public void shutDown () {
System.out.println("关机" );
}
}
public class TestComputer {
public static void main (String[] args) {
Computer c = new Computer ("华为" , "i9" , "16G" , "4K" );
c.boot();
c.shutDown();
}
}
注意 :一般情况下,成员变量通常设置为 private,成员方法设置为 public。
6.3 封装扩展之包
6.3.1 包的概念 包(Package)用于对类进行分组管理,有助于解决类名冲突并提高代码的组织性。例如,将相似功能的类归为同一包。
为了更好的管理类,把多个类收集在一起成为一组,称为软件包。
6.3.3 导入包 在 Java 中,如果我们需要使用不在默认 java.lang 包中的类或接口,就需要使用 import 关键字来导入。
例如,我们想使用 java.util.Date 这个类,就可以这样做:
import java.util.Date;
public class TestImport {
public static void main (String[] args) {
Date d = new Date ();
System.out.println(d);
}
}
6.3.3 全类名 当不同包中存在同名的类时(如 java.util.Date 与 java.sql.Date 都叫 Date),可能会引发冲突。
这时,可以使用 全类名 (Fully Qualified Name)来指定使用哪个类:
public class TestFullName {
public static void main (String[] args) {
java.util.Date d1 = new java .util.Date();
java.sql.Date d2 = new java .sql.Date(System.currentTimeMillis());
System.out.println(d1);
System.out.println(d2);
}
}
通过在创建对象时加上包名,就可以区分来自 java.util 和 java.sql 的 Date 类。
6.3.4 静态导入 从 Java 5 开始,支持使用 静态导入 (import static)的方式将某个类中的 静态成员(常量或方法) 导入到当前类中,从而在调用时可以省略类名。
import static java.lang.Math.PI;
import static java.lang.Math.random;
public class TestStaticImport {
public static void main (String[] args) {
System.out.println(PI);
System.out.println(random());
}
}
System.out.println(Math.PI);
System.out.println(Math.random());
6.3.5 IDE 工具中的包结构 当我们使用 IntelliJ IDEA 或 Eclipse 等 IDE 工具时,会在项目结构中直观地看到包名与文件夹一一对应。
包名一般使用 小写 的域名反写形式(如 com.example.project),在 IDE 中会对应层级文件夹结构。
在同一个包下,可以放置多个类文件,便于组织与管理。
在实际开发中,合理划分包结构能让项目更易于维护和理解。
6.3.6 包的访问权限控制举例 Computer 类位于 com.bit.demo1 包中,TestComputer 位于 com.bit.demo2 包中:
package com.bit.demo1;
public class Computer {
private String cpu;
private String memory;
public String screen;
String brand;
public Computer (String brand, String cpu, String memory, String screen) {
this .brand = brand;
this .cpu = cpu;
this .memory = memory;
this .screen = screen;
}
public void PowerOff () {
System.out.println("关机~~~" );
}
public void SurfInternet () {
System.out.println("上网~~~" );
}
}
package com.bit.demo2;
import com.bit.demo1.Computer;
public class TestComputer {
public static void main (String[] args) {
Computer p = new Computer ("HW" , "i7" , "8G" , "13*14" );
System.out.println(p.screen);
}
}
注意:
如果去掉前面的 Computer 类中的 public 修饰符,代码也会编译失败。
6.3.7 常见的包
java.lang :系统常用基础类(String,Object),此包从 JDK1.1 后自动导入。
java.lang.reflect :Java 反射机制包;
java.net :进行网络编程开发包;
java.sql :进行数据库开发的包;
javax.util :Java 提供的工具程序包(集合类等)非常重要;
javalio.io :编程程序包。
注意事项:import 和 C++ 的 #include 差别很大。C++ 必须 #include 来引入其他文件内容,但是 Java 不需要。import 只是为了写代码的时候更方便。
Java 的 import: 仅在编译时为你提供类或接口的简写路径,使你可以直接使用类名而不用写出完整的包名。实际上,编译器会在编译过程中通过类路径(classpath)去查找相应的类文件,而不会把代码插入到当前文件中。
C/C++ 的 #include: 预处理器会在编译之前将头文件的内容直接拷贝进源代码文件中,这种方式实际上是将文件的内容'粘贴'到包含它的文件里。
因此,Java 的 import 只是一种简化引用的机制,并不涉及代码的复制。
七、总结与展望 在本篇文章中,我们围绕对象的构造与初始化、封装、包的管理以及访问权限等内容展开了详细讲解,帮助大家深入理解 Java 面向对象编程的核心概念。
7.1 总结
对象的构造与初始化
构造方法 :通过构造方法,我们可以在创建对象时立即为其成员赋值,保证对象在使用前处于有效状态。
构造器重载与 this 调用 :支持多个构造方法以及构造器链,让对象初始化更加灵活和简洁。
默认初始化与就地初始化 :成员变量会自动获得默认值,同时也可以在声明时直接赋值,避免重复代码。
封装
核心思想 :将数据与操作数据的方法绑定在一起,通过访问限定符(public、private、protected、default)隐藏内部实现细节。
访问控制 :合理使用访问修饰符保护数据安全,提供公开接口供外部使用,增强了程序的健壮性和安全性。
包的管理与导入
包的概念 :通过将相关类归为一组,实现代码的模块化管理和命名空间隔离,避免类名冲突。
import 语句 :在编译时提供类名简写路径,与 C/C++ 的#include 机制不同,import 不进行代码复制,仅起到标识和简化引用的作用。
7.2 展望
深入 static 成员 :在后续的内容中,我们将更详细地探讨 static 关键字的使用,包括静态变量、静态方法及其在类中的意义,帮助大家更好地理解类级别的共享特性。
代码块与初始化块 :将介绍类中的初始化块和静态代码块,讨论它们在对象创建过程中的执行顺序和作用,为进一步掌握对象生命周期奠定基础。
内部类与匿名类 :内部类是一种特殊的类定义方式,它能够更紧密地绑定外部类的成员,将在未来篇章中深入剖析其用法和设计思想。
面向对象的设计原则 :随着对类和对象理解的深入,我们也将探讨更多面向对象设计的原则和模式,帮助大家构建更健壮、可维护的 Java 应用程序。
本文为大家构建了坚实的面向对象编程基础,希望通过系统的总结和展望,能够激发你对 Java 编程更深层次的兴趣。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online