当前位置: 首页 > news >正文

12 封装与构造方法

目录

  • 🔐 12 封装与构造方法
    • 12.1 为什么要封装
    • 12.2 private关键字
      • 访问修饰符对比
      • 使用private修饰成员变量
    • 12.3 getter与setter方法
      • 12.3.1 基本写法
      • 12.3.2 使用getter/setter
      • 12.3.3 只读属性与只写属性
    • 12.4 this关键字
      • 12.4.1 问题引出
      • 12.4.2 this的含义
      • 12.4.3 this的常见用法
      • 12.4.4 完整示例
    • 12.5 构造方法
      • 12.5.1 什么是构造方法
      • 12.5.2 构造方法的特点
      • 12.5.3 定义构造方法
      • 12.5.4 带参构造方法
    • 12.6 构造方法重载
      • this()调用其他构造方法
    • 12.7 JavaBean规范
      • JavaBean规范
      • 标准JavaBean示例
    • 12.8 综合案例:学生管理系统
      • 需求
      • 代码实现
    • 12.9 本章总结
      • 知识回顾
      • 练习题
    • 💬 互动时间
    • 📚 参考资料

🔐 12 封装与构造方法

更新日期:2026年5月
版权声明:本文为原创内容,转载请注明出处。
系列:Java入门到精通系列 · 第二阶段 · 面向对象



12.1 为什么要封装

上一章中,我们可以直接访问和修改对象的属性:

Studentstu=newStudent();stu.age=-100;// 合法但不合理!

问题:外部代码可以随意修改数据,没有安全保障。

封装的核心思想:隐藏内部实现细节,只暴露必要的接口给外部使用。

问题封装前封装后
数据安全外部可直接修改通过方法控制访问
数据校验无法校验在setter中校验
代码耦合外部依赖内部实现外部只依赖接口
可维护性修改内部影响外部修改内部不影响外部

12.2 private关键字

private是一个访问修饰符,用于修饰成员变量和成员方法,使其只能在本类内部被访问。

访问修饰符对比

修饰符同类同包子类不同包
public
protected
默认(不写)
private

使用private修饰成员变量

publicclassStudent{privateStringname;// 私有化privateintage;// 私有化privatedoublescore;// 私有化}

此时在外部直接访问会编译报错:

Studentstu=newStudent();stu.name="张三";// ❌ 编译错误!name是private的

12.3 getter与setter方法

为了在保护数据的同时允许外部访问,我们提供公开的getter/setter方法

12.3.1 基本写法

publicclassStudent{privateStringname;privateintage;privatedoublescore;// ---- getter方法 ----publicStringgetName(){returnname;}publicintgetAge(){returnage;}publicdoublegetScore(){returnscore;}// ---- setter方法(带数据校验)----publicvoidsetName(Stringname){this.name=name;}publicvoidsetAge(intage){if(age<0||age>150){System.out.println("年龄不合法!");return;}this.age=age;}publicvoidsetScore(doublescore){if(score<0||score>100){System.out.println("成绩必须在0-100之间!");return;}this.score=score;}}

12.3.2 使用getter/setter

publicclassStudentTest{publicstaticvoidmain(String[]args){Studentstu=newStudent();stu.setName("张三");stu.setAge(20);stu.setScore(95.5);System.out.println("姓名:"+stu.getName());System.out.println("年龄:"+stu.getAge());System.out.println("成绩:"+stu.getScore());// 测试数据校验stu.setAge(-100);// 输出:年龄不合法!stu.setScore(150);// 输出:成绩必须在0-100之间!}}

12.3.3 只读属性与只写属性

publicclassUser{privateStringusername;privateStringpassword;// username:可读可写publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this.username=username;}// password:只写(没有getter,外部无法读取)publicvoidsetPassword(Stringpassword){this.password=password;}// 内部可以使用passwordpublicbooleancheckPassword(Stringinput){returnthis.password.equals(input);}}

12.4 this关键字

12.4.1 问题引出

publicvoidsetAge(intage){age=age;// 两个age都是局部变量,成员变量没被赋值!}

成员变量局部变量同名时,Java会"就近原则"优先使用局部变量。

12.4.2 this的含义

this代表当前对象的引用,即调用该方法的对象。

publicvoidsetAge(intage){this.age=age;// this.age是成员变量,age是局部变量}

12.4.3 this的常见用法

用法说明示例
区分同名变量this.成员变量this.name = name
调用本类方法this.方法名()this.show()
调用构造方法this(参数)this("", 0)

12.4.4 完整示例

publicclassPerson{privateStringname;privateintage;publicPerson(Stringname,intage){this.name=name;// this.name是成员变量this.age=age;// this.age是成员变量}publicvoidshow(){System.out.println("name="+this.name+", age="+this.age);}publicvoidcompareAge(Personother){if(this.age>other.age){System.out.println(this.name+"比"+other.name+"大");}elseif(this.age<other.age){System.out.println(this.name+"比"+other.name+"小");}else{System.out.println(this.name+"和"+other.name+"同龄");}}}

12.5 构造方法

12.5.1 什么是构造方法

构造方法(Constructor)是一种特殊的方法,用于在创建对象时初始化对象的成员变量

newStudent();// 这里调用的就是构造方法

12.5.2 构造方法的特点

特点说明
方法名必须与类名完全相同
返回值没有返回值类型(连void都没有)
调用时机new的时候自动调用,只调用一次
作用初始化成员变量
默认如果不写,编译器会自动提供一个无参构造

12.5.3 定义构造方法

publicclassStudent{privateStringname;privateintage;// 无参构造方法publicStudent(){System.out.println("Student对象被创建了!");}// getter/setter省略...}
publicclassTest{publicstaticvoidmain(String[]args){Studentstu=newStudent();// 控制台输出:Student对象被创建了!}}

12.5.4 带参构造方法

publicclassStudent{privateStringname;privateintage;privatedoublescore;// 带参构造方法publicStudent(Stringname,intage,doublescore){this.name=name;this.age=age;this.score=score;}// getter/setter省略...publicvoidshow(){System.out.println(name+","+age+"岁,成绩:"+score);}}
Studentstu=newStudent("张三",20,95.5);stu.show();// 输出:张三,20岁,成绩:95.5

📌重要提醒:一旦你写了任何构造方法,编译器就不再自动提供无参构造。建议永远手动写上无参构造


12.6 构造方法重载

一个类可以有多个构造方法,参数列表不同即可。

publicclassStudent{privateStringname;privateintage;privatedoublescore;// 无参构造publicStudent(){this("未知",0,0);// 调用三参构造}// 两参构造publicStudent(Stringname,intage){this(name,age,0);// 调用三参构造}// 三参构造(全参构造)publicStudent(Stringname,intage,doublescore){this.name=name;this.age=age;this.score=score;}publicvoidshow(){System.out.println(name+","+age+"岁,成绩:"+score);}}

调用示例

Students1=newStudent();// 未知,0岁,成绩:0.0Students2=newStudent("张三",20);// 张三,20岁,成绩:0.0Students3=newStudent("李四",21,92.5);// 李四,21岁,成绩:92.5s1.show();s2.show();s3.show();

this()调用其他构造方法

publicStudent(){this("未知",0,0);// 必须是构造方法的第一行}

📌this(参数)只能在构造方法中使用,且必须是第一行语句。不能和super()同时出现。


12.7 JavaBean规范

JavaBean是一种符合特定编写规范的Java类,广泛用于企业级开发。

JavaBean规范

规则说明
类必须是public公开访问
成员变量必须private私有化
必须有无参构造方法便于框架反射创建对象
必须有getter/setter方法通过方法访问属性
实现Serializable接口可序列化(推荐)

标准JavaBean示例

importjava.io.Serializable;publicclassStudentimplementsSerializable{privatestaticfinallongserialVersionUID=1L;privateStringname;privateintage;privatedoublescore;// 无参构造publicStudent(){}// 全参构造publicStudent(Stringname,intage,doublescore){this.name=name;this.age=age;this.score=score;}// getter/setterpublicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}publicdoublegetScore(){returnscore;}publicvoidsetScore(doublescore){this.score=score;}// toString@OverridepublicStringtoString(){return"Student{name='"+name+"', age="+age+", score="+score+"}";}}

💡 在实际开发中,我们常用Lombok@Data@Getter@Setter@AllArgsConstructor@NoArgsConstructor注解来自动生成getter/setter和构造方法,减少样板代码。


12.8 综合案例:学生管理系统

需求

设计一个简单的学生类,要求:

  • 使用private封装所有属性
  • 提供有参和无参构造方法
  • 在setter中进行数据校验
  • 提供一个显示信息的方法

代码实现

publicclassStudent{privateStringname;privateintage;privateStringmajor;privatedoublegpa;// 无参构造publicStudent(){}// 全参构造publicStudent(Stringname,intage,Stringmajor,doublegpa){this.setName(name);this.setAge(age);this.setMajor(major);this.setGpa(gpa);}// getter/setter(带校验)publicStringgetName(){returnname;}publicvoidsetName(Stringname){if(name==null||name.trim().isEmpty()){System.out.println("姓名不能为空!");return;}this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){if(age<15||age>60){System.out.println("年龄必须在15-60之间!");return;}this.age=age;}publicStringgetMajor(){returnmajor;}publicvoidsetMajor(Stringmajor){this.major=major;}publicdoublegetGpa(){returngpa;}publicvoidsetGpa(doublegpa){if(gpa<0.0||gpa>4.0){System.out.println("GPA必须在0.0-4.0之间!");return;}this.gpa=gpa;}// 显示信息publicStringgetInfo(){return"姓名:"+name+" | 年龄:"+age+" | 专业:"+major+" | GPA:"+gpa;}// 判断是否优秀publicbooleanisExcellent(){returnthis.gpa>=3.5;}@OverridepublicStringtoString(){returngetInfo();}}

测试类

publicclassStudentManager{publicstaticvoidmain(String[]args){// 使用全参构造创建学生Students1=newStudent("张三",20,"计算机科学",3.8);Students2=newStudent("李四",21,"软件工程",3.2);Students3=newStudent("王五",19,"人工智能",3.9);// 使用无参构造 + setter创建学生Students4=newStudent();s4.setName("赵六");s4.setAge(22);s4.setMajor("数据科学");s4.setGpa(3.6);// 存入数组统一管理Student[]students={s1,s2,s3,s4};System.out.println("========== 学生信息 ==========");for(Students:students){System.out.println(s.getInfo());System.out.println("是否优秀:"+(s.isExcellent()?"✅ 是":"❌ 否"));System.out.println("------------------------------");}// 测试数据校验Students5=newStudent();s5.setAge(10);// 输出:年龄必须在15-60之间!s5.setGpa(5.0);// 输出:GPA必须在0.0-4.0之间!}}

输出结果

========== 学生信息 ========== 姓名:张三 | 年龄:20 | 专业:计算机科学 | GPA:3.8 是否优秀:✅ 是 ------------------------------ 姓名:李四 | 年龄:21 | 专业:软件工程 | GPA:3.2 是否优秀:❌ 否 ------------------------------ 姓名:王五 | 年龄:19 | 专业:人工智能 | GPA:3.9 是否优秀:✅ 是 ------------------------------ 姓名:赵六 | 年龄:22 | 专业:数据科学 | GPA:3.6 是否优秀:✅ 是 ------------------------------ 年龄必须在15-60之间! GPA必须在0.0-4.0之间!

12.9 本章总结

知识回顾

知识点核心内容
封装隐藏实现细节,只暴露必要接口
private修饰成员变量/方法,只在本类可访问
getter/setter公开的访问方法,可在setter中做校验
this关键字代表当前对象引用,区分同名变量
构造方法与类同名、无返回值、new时调用
构造方法重载多个构造方法参数不同
JavaBeanprivate属性 + getter/setter + 无参构造 + Serializable

练习题

  1. 定义一个BankAccount类(银行账户),要求:

    • 属性:账号(accountNo)、户主名(ownerName)、余额(balance)
    • balance只能通过deposit(存款)和withdraw(取款)方法修改
    • withdraw需要校验余额是否充足
    • 提供showBalance()方法显示余额
  2. 定义一个Rectangle类(矩形),要求:

    • 属性:长(length)、宽(width)必须为正数
    • 提供无参和有参构造方法
    • 提供计算面积和周长的方法

💬 互动时间

  • 为什么JavaBean要求必须有无参构造方法?
  • this关键字有几种用法?分别在什么场景下使用?

📢下篇预告:[13-继承]—— 学习如何用继承实现代码复用,以及方法重写的奥秘!


📚 参考资料

  • Oracle Java 官方文档 - Controlling Access
  • JavaBean 规范
  • 《Java核心技术 卷I》第4章
http://www.rkmt.cn/news/1450054.html

相关文章:

  • 告别远程桌面!在Win10/11上优雅管理AD域控的保姆级教程(含RSAT工具安装与避坑)
  • 从聊天到执行:Claude Opus 4.8、GPT-5.5/Codex、Qwen3.7-Max、RAGFlow 0.25.6 热点盘点
  • 从任务到挑战:重塑众包理念,构建激发群体智慧的系统方法论
  • 猫抓Cat-Catch:浏览器资源嗅探扩展的终极技术指南与深度解析
  • 语音助手开发实战:从ASR到TTS的全栈构建与行业应用
  • GoF设计模式——装饰模式
  • Boss直聘智能投递助手:三步实现求职效率提升10倍的终极解决方案
  • OpenCore配置的技术挑战与OpCore-Simplify的智能化解决方案:从手动调试到自动化配置的演进之路
  • 告别手动拼接SQL!用Hackbar插件快速生成Payload的5个实战技巧
  • 那一天
  • 2026实测盘点:16款降AIGC网站测评,论文降重降ai率终极答案!
  • 如何快速实现AI桌面自动化:面向普通用户的完整指南
  • 手把手教你用Simulink搭建PMSM位置三闭环模型(附模型下载与参数详解)
  • WorkshopDL终极指南:无需Steam客户端,轻松获取创意工坊模组的完整解决方案
  • 资源强的大湾区EMBA推荐:5大高含金量优质项目盘点
  • 快速掌握mootdx:Python通达信数据读取的终极解决方案
  • 华硕笔记本终极轻量控制神器:5分钟快速上手G-Helper完全指南
  • Solon 框架热加载与热插拔机制揭秘:从开发到生产的完整技术链路
  • 数据科学如何预测奥斯卡:从多元数据到动态概率模型的实战解析
  • HsMod:炉石传说终极增强插件,55项功能全面优化游戏体验
  • 突破性防撤回实战:3步完全掌握微信QQ消息永久保存技巧
  • 保姆级教程:在PVE 8.0上安装Debian 12 KDE桌面(附软件源配置避坑指南)
  • 我用 HarmonyOS 写了个「饮品特调研究所」,边学 ArkUI 边调奶茶
  • 2026年论文降AIGC攻坚战:实测验证工具榜与精准选型导航
  • 开源即自由:MyEMS 能源管理系统的技术栈解耦与兼容性架构
  • 基于Arduino与MAX4466的可调数字声级计设计与实现
  • 终极指南:用Zotero-Style开源工具快速提升文献管理效率
  • Steam Achievement Manager:5分钟解锁全成就的终极解决方案
  • C++四大设计模式:单例、工厂、观察者、策略
  • 如何用Qwen-Image-Edit-Rapid-AIO实现4步闪电级AI图像编辑:新手终极指南