封装的概述
在面向对象编程中,封装(encapsulation)是将对象运行所需的资源封装在程序对象中——基本上,是方法和数据。对象是“公布其接口”。其他附加到这些接口上的对象不需要关心对象实现的方法即可使用这个对象。
/*
* 需求:要求定义一个狗类,拥有姓名,品种,健康度,亲密度
* 联想:QQ宠物。
*/
public class Dog {
// 姓名
public String name;
// 品种
public String bread;
// 健康值
public int healthl;
// 亲密度
public int love;
/*
* 自我介绍
*/
public void showSelf() {
System.out.println("狗名:" + name);
System.out.println("品种:" + bread);
System.out.println("健康值:" + healthl);
System.out.println("亲密度:" + love);
}
public void setLove(int love) {
if(love < 0 || love > 100) {
System.out.println("亲密值违法!已设为默认值!");
love = 60;
}
this.love = love;
}
}
// 创建对象
Dog dog = new Dog();
dog.name = "大黄";
dog.bread = "大黄";
dog.healthl = 90;
// dog.love = -80;
// 从业务角度看,是错误的。[0, 100]
dog.love = 80;
dog.showSelf();
从业务角度,dog亲密度属性赋值不能出现负数。
但是从程序语法角度,它没有出现错误!
- 亲密度(love)属性的数据类型是:int
**解决方法: **
- 在赋值后,进行业务判断
// 创建对象
Dog dog = new Dog();
dog.name = "大黄";
dog.bread = "大黄";
dog.healthl = 90;
// dog.love = 80;
// 从业务角度看,是错误的。[0, 100]
dog.love = -80;
if(dog.love < 0 || dog.love > 100) {
System.out.println("亲密值违法!已设为默认值!");
dog.love = 60;
dog.showSelf();
但是,这种方案在每次使用 Dog 类创建对象时,都需要采用一下(都要判断)。
我们将这种重复的代码段,提取到了 Dog 类的方法中。
// 定义方法用于对属性进行合理值判断
public void setLove(int love) {
if(love < 0 || love > 100) {
System.out.println("亲密值违法!已设为默认值!");
love = 60;
}
// 给成员变量赋值
this.love = love;
}
赋值方式以后采用调用 setLove 方法即可保证每次赋值时都会执行业务验证。
// 键盘录入信息
Scanner input = new Scanner(System.in);
// 创建对象
Dog dog = new Dog();
System.out.print("请输入狗狗的名字:");
dog.name = input.next();
System.out.print("请输入狗狗的品种:");
dog.bread = input.next();
System.out.print("请输入狗狗的健康值:");
dog.healthl = input.nextInt();
System.out.print("请输入狗狗的亲密度:");
dog.setLove(input.nextInt());
dog.showSelf();
}
虽然定义了一个方法用于进行属性赋值,但是因为语法角度的原因,很可能有使用者没有采用该方法,那么刚才的问题就依然存在。
经过分析,导致该问题存在的原因是访问权限修饰符是 public,这种修饰符允许其他类操作 Dog 的属性。(联想思路:进入教室有门和窗口,正常应该走门,但有些人非要走窗口。可以考虑把窗口 “封上” (加上防盗网),这样就只能通过门进入教室。)
解决方法:** 修改亲密度(love)的访问权限修饰符为 private(只能在 Dog 类中使用该属性)**
封装: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操>作和访问,把尽可能多的东西藏起来,对外提供便捷的接口。
封装的使用
- 属性私有化:将访问权限修饰符更改为 private
- 提供公共的操作和访问方法 (setter/getter方法):每个属性创建两个方法,1个是设值setXX,1个是取值getXX
- 根据需要,在操作和访问方法中添加合理的判断和处理
public class Dog2 {
// 属性私有化
// 姓名
private String name;
// 品种
private String bread;
// 健康值
private int healthl;
// 亲密度
private int love;
public Dog2() {
super();
}
// 提供公共的getter/setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBread() {
return bread;
}
public void setBread(String bread) {
this.bread = bread;
}
public int getHealthl() {
return healthl;
}
public void setHealthl(int healthl) {
if(healthl < 0 || healthl > 100) {
System.out.println("健康值违法!已设为默认值!");
healthl = 60;
}
this.healthl = healthl;
}
public int getLove() {
return love;
}
public void setLove(int love) {
if(love < 0 || love > 100) {
System.out.println("亲密值违法!已设为默认值!");
love = 60;
}
this.love = love;
}
/*
* 自我介绍
*/
public void showSelf() {
System.out.println("狗名:" + name);
System.out.println("品种:" + bread);
System.out.println("健康值:" + healthl);
System.out.println("亲密度:" + love);
}
}
// 键盘录入信息
Scanner input = new Scanner(System.in);
// 创建对象
Dog2 dog = new Dog2();
System.out.print("请输入狗狗的名字:");
dog.setName(input.next());
System.out.print("请输入狗狗的品种:");
dog.setBread(input.next());
System.out.print("请输入狗狗的健康值:");
dog.setHealthl(input.nextInt());
System.out.print("请输入狗狗的亲密度:");
dog.setLove(input.nextInt());
dog.showSelf();
以后,在定义 Java 类时,基本都要使用封装的这些步骤实现。
一般 JavaBean 规范:
- 属性私有化
- 提供公共的操作和访问方法
- 编写无参构造方法
- 实现序列化接口(了解)
封装的优势
- 便于使用者正确使用系统,防止错误修改属性。 (安全性、健壮)
- 有助于系统之间的松耦合(低耦合),提高系统独立性。
- 提高软件的可重用性(相对独立的整体,高内聚)
包组织结构
在 Java 中可以通过建立 package 来实现对类的分类整理。而且从系统的角度,一个文件夹下不允许出现两个同名文件。
在硬盘上,package 实际上就是一个文件夹而已。
包名的规范:
- 包名应该全部小写(根据需要,也可以考虑部分名词大写,保持正常简写)
- 公司/组织的域名倒序 + 项目名 + 部门/项目组 + 分类名 + …(前面基本一致,后面看公司情况)
QQ程序:com.tencent.mobileqq.xx
package 包名; // 包声明,明确该类属于哪个包下的
// 导包(不导包,使用某个类时,将无法定位到指定类)
// 包名 + 类名被称为该类的全限定名/全类名
import 包名.类名;
public class 类名 {
// 类体
}
注意事项:
- 在一个类中,使用另一个包中的类,需要进行导包操作。
- java.lang 包下的类使用时不需要导包
- 在一个类中,如果使用了两个同名的类,其中至少有一个需要使用全类名写法(包名+类名)。
- 如果在使用某个类时,发现命名该类有这个方法,但就是使用不了!考虑是不是导错包了。
访问权限修饰符
访问权限修饰符:用于限制访问权限的。
修饰符\访问权限范围 | 同一个类中 | 同一个包的不同类中 | 不同包的子类中 | 同一个项目中 |
---|---|---|---|---|
private | ✔️ | |||
default(默认的/包级的,不用写修饰符) | ✔️ | ✔️ | ||
protected(先了解,学完继承就可以掌握了) | ✔️ | ✔️ | ✔️ | |
public | ✔️ | ✔️ | ✔️ | ✔️ |
可以使用访问权限修饰符来修饰:类、成员变量、成员方法。
其实,在Java源代码文件中(.java)可以编写很多类,但是只能有一个类是被 public 修饰,且该类的类名和源文件名保持一致。
建议:没有特殊情况,一个源文件只写一个类。