
Java面向对象进阶构造器、封装与权限修饰符前言学完类、对象、属性、方法这些基础后你已经能用Java描述现实中的事物了。但真正的面向对象编程还差几块关键拼图。本文将带你走进构造器、封装、权限修饰符、this关键字与JavaBean规范的世界。它们是写出规范、安全、可维护Java代码的基石。一、构造器Constructor1.1 什么是构造器构造器是类的第三个成员前两个是成员变量和成员方法它是一种特殊的方法。打个比方类是生产产品的图纸而构造器就是生产流水线上的组装工人。每次你想造一个对象都得请这位工人来组装。它的写法如下publicclassStudent{privateStringname;// 实例变量姓名privateintscore;// 实例变量成绩// 这就是构造器名字和类名一样没有返回值类型publicStudent(Stringn,ints){namen;scores;}}1.2 构造器的特点构造器有四个鲜明特征和普通方法区别开名称必须与类名完全一致大小写也要一样。没有返回值类型连 void 都不能写。一旦写了返回值类型它就变成了普通方法不再是构造器。修饰符只能是public、protected、缺省不写、private 这四种之一。每个类都有构造器绝不会出现一个构造器都没有的情况。小贴士构造器与普通方法最大的区别就是无返回值类型。新手常犯的错误是给构造器加上 void结果它就不再是构造器了。1.3 默认构造器如果你一个构造器都没写编译器会贴心地帮你加上一个无参构造器publicclassStudent{privateStringname;// 你没写任何构造器编译器自动补上// public Student() { }}但要注意一条铁律只要你手动写了任何一个构造器无论有参无参编译器就不再帮你补默认无参构造了。注意这是非常常见的坑。很多框架如Spring、MyBatis创建对象时会调用无参构造如果你只写了有参构造而忘了无参构造程序会报错。建议只要写了有参构造就顺手补一个无参构造。1.4 构造器的作用构造器有两个核心使命与 new 一起创建对象——它是对象诞生的接生婆。为实例变量初始化——在对象出生的瞬间就给它赋上合理的值。publicclassStudentTest{publicstaticvoidmain(String[]args){// new Student(张三, 89) 做了两件事// 1. 创建一个 Student 对象// 2. 调用构造器把 name 设为张三score 设为 89StudentsnewStudent(张三,89);System.out.println(s.getInfo());}}如果没有构造器初始化实例变量只会是默认值int 为 0引用类型为 null往往不是我们想要的。1.5 构造器的重载和方法一样构造器也可以重载名字相同参数列表不同。这样就能用多种方式创建对象。publicclassStudent{privateStringname;privateintscore;// 构造器1只传姓名publicStudent(Stringn){namen;}// 构造器2传姓名和成绩publicStudent(Stringn,ints){namen;scores;}// 构造器3只传成绩publicStudent(ints){scores;}publicStringgetInfo(){return姓名name成绩score;}}调用时根据传入参数的个数和类型Java会自动匹配合适的构造器就像点餐时选不同的套餐。1.6 快捷键生成构造器在IDEA中按Alt Insert部分笔记本需要Fn Alt Insert选择 Constructor勾选要初始化的属性即可一键生成构造器。这能避免手写时漏掉字段或拼错名字是日常开发的高效利器。二、封装2.1 封装的概念与意义面向对象有三大特征封装、继承、多态。封装是其中最基础的一个。生活中的封装就像快递包裹纸箱把商品包起来既保护商品不被损坏又隐藏了里面具体装了什么还方便搬运。Java中的封装就是把对象的内部细节隐藏起来只对外暴露必要的访问方式。它带来三大好处安全保护内部成员变量外部不能随意修改只能通过规定的方法访问。简便外部使用者不需要关心内部如何实现只要会调方法即可。可维护内部实现变了只要对外接口不变外部代码无需改动。2.2 四种权限修饰符Java通过权限修饰符来实现封装。共有四种可见性范围由小到大修饰符本类内部本包的其他类其他包的子类其他包的非子类private可以不可以不可以不可以缺省不写可以可以不可以不可以protected可以可以可以不可以public可以可以可以可以记忆口诀从 private 到 public可见范围像洋葱一样一层层扩大。private 最严只对自己开放public 最宽对全世界开放。小贴士缺省default不是关键字而是什么都不写时的默认状态。它允许同包访问但不允许跨包。2.3 修饰类与修饰成员的规则权限修饰符既可以修饰类的成员属性、方法、构造器也可以修饰类本身但规则略有不同修饰类只能用 public 或缺省。不能用 private、protected 修饰外部类内部类除外。修饰成员四种修饰符都可以用。换句话说一个类对外的可见性只有两档要么全包可见缺省要么全工程可见public。而类内部的成员则有更细粒度的控制。2.4 属性私有化与 getter/setter封装最典型的应用就是属性私有化把成员变量声明为 private然后提供公开的 getter/setter 方法来访问它。为什么这样做假设有个年龄属性如果直接 public 暴露谁都能赋值为 -100 或 9999。但通过 setter我们就能加校验逻辑publicclassEmployee{privateStringname;// 属性私有化外部无法直接访问privateintage;// getter供外部读取属性值// 命名规范get 属性名首字母大写publicintgetAge(){returnage;}// setter供外部修改属性值// 命名规范set 属性名首字母大写publicvoidsetAge(intage){// 在这里可以做合法性校验保证数据安全if(age0||age150){System.out.println(年龄不合法已设为默认值0);this.age0;}else{this.ageage;}}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.namename;}}getter/setter 的规范要点getter 以get开头属性名首字母大写boolean 类型用is代替get如isMarry()。getter 有返回值、无参数setter 无返回值void、有参数。静态变量的 getter/setter 也都是静态的实例变量的 getter/setter 是非静态的。注意boolean 类型属性的 getter 用 is 开头更符合英语习惯比如isMarry()、isEmpty()。生成 getter/setter 同样用Alt Insert选择 Getter / Setter / Getter and Setter 即可批量生成。三、this关键字详解3.1 this是什么this是一个代词代表当前正在调用这个方法的对象。谁调用了这个方法this 就指向谁。它可以用在构造器、实例方法、非静态代码块。它不能出现在静态方法、静态代码块。原因很简单静态方法属于类本身不属于任何对象自然没有当前对象一说。3.2 this.成员变量——区分重名当方法的局部变量包括参数与实例变量同名时Java遵循就近原则会优先使用局部变量。这时如果想让编译器认出实例变量就要加this.publicclassEmployee{privateStringname;privatedoublesalary;// 参数 name 和实例变量 name 重名// 不加 this. 的话name name 相当于自己赋值给自己实例变量没变publicEmployee(Stringname,doublesalary){this.namename;// this.name 表示实例变量this.salarysalary;// this.salary 表示实例变量}publicvoidsetName(Stringname){this.namename;// this 代表调用 setName 的那个对象}}注意如果局部变量和实例变量不重名可以省略 this.编译器会自动识别为实例变量。但养成加 this. 的习惯能让代码可读性更强。3.3 this()——调用本类其他构造器this 还有一种用法this(实参列表)用于在一个构造器中调用本类的另一个构造器实现代码复用。publicclassEmployee{privateStringname;privatedoublesalary;privatechargender;// 无参构造publicEmployee(){System.out.println(一个员工对象被创建了);}// 部分参数构造复用无参构造的代码publicEmployee(Stringname,doublesalary){this();// 调用本类的无参构造复用其中的代码this.namename;this.salarysalary;}// 全参构造复用上面那个部分参数构造publicEmployee(Stringname,doublesalary,chargender){this(name,salary);// 调用本类的另一个构造器this.gendergender;}}注意this()调用必须放在构造器的第一行。一个构造器中只能调用一次其他构造器。这个位置限制是为了保证对象初始化的顺序清晰。四、对象数组4.1 什么是对象数组数组不仅能存基本类型int、double也能存对象。所谓对象数组就是元素类型为某个类的数组。关键理解数组中存的并不是对象本身而是对象的引用首地址。就像一排信箱每个信箱里装的不是房子而是房子的门牌号。// 声明一个矩形对象数组Rectangle[]arrnewRectangle[3];此时数组有3个格子但每个格子的默认值是 null——还没装任何对象进去。4.2 对象数组的使用下面是一个完整示例创建3个矩形对象存入数组遍历输出再按面积排序后输出。// 矩形类属性私有、有构造器、getter/setter、业务方法publicclassRectangle{privatedoublelength;privatedoublewidth;publicRectangle(){}publicRectangle(doublelength,doublewidth){this.lengthlength;this.widthwidth;}publicdoublegetLength(){returnlength;}publicvoidsetLength(doublelength){this.lengthlength;}publicdoublegetWidth(){returnwidth;}publicvoidsetWidth(doublewidth){this.widthwidth;}// 面积publicdoublearea(){returnlength*width;}// 周长publicdoubleperimeter(){return2*(lengthwidth);}// 综合信息publicStringgetInfo(){return长length宽width面积area()周长perimeter();}}测试类publicclassRectangleTest{publicstaticvoidmain(String[]args){// 动态初始化创建长度为3的矩形数组元素默认值是 nullRectangle[]arrnewRectangle[3];// 给数组元素赋值每个位置都要 new 一个对象arr[0]newRectangle(5,2);arr[1]newRectangle(6,3);arr[2]newRectangle(5,1);// 遍历输出普通for循环for(inti0;iarr.length;i){// arr[i] 是一个对象引用可以调用它的属性和方法System.out.println(arr[i].getInfo());}// 按面积从小到大排序冒泡排序for(inti0;iarr.length-1;i){for(intj0;jarr.length-1-i;j){// 对象不能直接比较大小要用某个属性或方法返回值if(arr[j].area()arr[j1].area()){// 交换的是数组中的引用门牌号不是对象本身Rectangletemparr[j];arr[j]arr[j1];arr[j1]temp;}}}// 排序后遍历输出增强for循环for(Rectangler:arr){System.out.println(r.getInfo());}}}注意对象数组中数组元素本身是引用交换元素交换的是引用门牌号对象本身在堆内存中并没有移动。对象之间不能直接用比较要用具体属性如area()来比较。五、标准JavaBean规范5.1 JavaBean是什么JavaBean 是Java中一种标准的类编写规范。符合规范的类被称为 JavaBean它们能被各种框架、工具识别和使用。5.2 编写规范一个标准的JavaBean要满足以下几点属性私有化成员变量都用 private 修饰。提供无参构造方便框架反射创建对象。提供有参构造可选方便快速初始化。提供 getter/setter供外部读写属性。下面是一个完整的标准JavaBean示例publicclassCustomer{// 1. 属性私有化privateStringname;privatechargender;privateintage;privateStringtel;privateStringemail;// 2. 无参构造publicCustomer(){}// 3. 有参构造全参publicCustomer(Stringname,chargender,intage,Stringtel,Stringemail){this.namename;this.gendergender;this.ageage;this.teltel;this.emailemail;}// 4. getter/setter 方法publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.namename;}publicchargetGender(){returngender;}publicvoidsetGender(chargender){this.gendergender;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.ageage;}publicStringgetTel(){returntel;}publicvoidsetTel(Stringtel){this.teltel;}publicStringgetEmail(){returnemail;}publicvoidsetEmail(Stringemail){this.emailemail;}// 通常还会提供一个 getInfo 方法方便打印对象信息publicStringgetInfo(){return姓名name性别gender年龄age电话tel邮箱email;}}5.3 IDE快捷键大全IDEA为JavaBean的编写提供了强大的快捷键支持熟练使用能极大提升效率Alt Insert弹出生成菜单包含以下所有选项。Constructor生成构造器可选无参、有参。Getter生成getter方法。Setter生成setter方法。Getter and Setter同时生成getter和setter。toString()生成toString方法方便打印对象。equals() and hashCode()生成equals和hashCode方法。Ctrl P查看构造器/方法的参数列表调用时按。数组名.fori快速生成普通for循环。iter快速生成增强for循环。小贴士写完属性后依次用 AltInsert 生成 Constructor全选属性生成有参构造再生成一个无参、Getter and Setter、toString一个标准JavaBean几秒就能搭好。六、小结本文围绕写出规范的Java类这一目标串联了几个核心知识点构造器与类同名、无返回值类型负责创建对象和初始化实例变量。不写时编译器补默认无参构造写了就不再补。可重载可用 AltInsert 快速生成。封装隐藏内部细节对外暴露必要接口。通过权限修饰符实现带来安全、简便、可维护三大好处。权限修饰符private只对本类、缺省本包、protected本包其他包子类、public全部。类只能用 public 或缺省成员四种皆可。属性私有化属性用 private配 getter/setter 访问可在 setter 中加校验。boolean 的 getter 用 is 开头。this关键字代表当前对象。用于区分重名变量this.成员变量、调用本类构造器this() 必须在首行。静态方法中不能用 this。对象数组存储对象引用的数组。元素默认 null需 new 对象赋值。通过 arr[i].方法() 调用。比较对象要用具体属性。JavaBean规范属性私有 无参构造 有参构造 getter/setter。配合 AltInsert 快捷键几秒钟搭好一个标准类。掌握这些你就具备了写出工业级Java类的能力。下一篇我们将进入继承与多态看看如何让类之间产生血缘关系复用更多代码。