什么是封装?
封装是指在将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部的信息,而是通过该类所提供的方法来实现对内部信息的操作和访问
封装的作用
-
隐藏类的实现细节
-
让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制堆成员变量的不合理访问
-
可以进行数据检查,,从而有利于保证对象信息的完整性
-
便于修改,提高代码的可维护性
-
减少耦合:可以独立的开发、测试、优化、使用
-
便于调节性能,可以通过剖析确定哪些模块影响了系统的性能
-
降低了构建大型系统的风险:即使整个系统不可用,但是这些独立的模块可能是可用的
不封装可能出现问题
class Student{
//姓名
String name;
//年龄
int age;
//show()方法,显示所有成员变量
public void show(){
System.out.println("姓名:"+name);
System.out.println("年龄:"+age);
}
}
class StudentDemo{
public static void main(String[] args){
//创建学生对象
Student s=new Student();
s.show();
System.out.println("-----------");
//给成员变量赋值
s.name="林青霞";
s.age=16;
s.show();
System.out.println("-----------");
//给age重新赋值
s.age=-27;//数据不合理
s.show();
System.out.println("-----------");
}
}
通过示例可以发现,通过对象给成员变量赋值,常常可以赋值一些非法的数据,在现实场景中常常是不合理的
对数据进行判断,可以在构造方法,可以在普通方法,但是如果是较为复杂的逻辑,在构造方法中就会存在很大的问题
因此,对于这种情况,我们常常是限制用户对成员变量的使用权限,而是提供一个开放的方法, 用于将用户传递进来的数据做数据处理或逻辑判断后,再赋值给对象
示例:该动物园新来了一个动物,添加了编号、姓名、年龄、种类、品种,需要存储到数据库进行保存
package com.carl.javacore.encapsulation;
/**
* @PackageName com.carl.javacore.encapsulation
* @Auther carl
* @Description: TODO
* @Version V1.0
* @Date 2022-09-12 16:38
* Modified By:TODO
**/
public class Animal {
/**
* 编号
*/
private String id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 种类
*/
private String type;
/**
* 品种
*/
private String varieties;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
if(age>100 || age<0){
//抛出异常
System.out.println("该变量赋值不合法!");//使用输出的方式代替异常的输出
return;
}
this.age = age;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getVarieties() {
return varieties;
}
public void setVarieties(String varieties) {
this.varieties = varieties;
}
@Override
public String toString() {
return "Animal{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", type='" + type + '\'' +
", varieties='" + varieties + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) {
Animal a=new Animal();
a.setId("8790");
a.setName("巴顿");
a.setAge(-24);
a.setType("猫");
a.setVarieties("蓝白");
//然后将这个对象调用Mybatis的insert方法存储
System.out.println(a);//这里通过输出的方式代替存储的操作
}
}
输出结果:
该变量赋值不合法!
Animal{id='8790', name='巴顿', age=null, type='猫', varieties='蓝白'}
通过这种方式,我们确实可以避免用户保存脏数据,因为脏数据的存在极大可能性会导致程序的崩溃,因此封装是必要的
封装的原则
-
将不需要对外提供的内容都隐藏起来
-
把属性隐藏,提供公共方法对其访问
访问权限控制符
Java提供了四个访问权限控制符:private、public、protected、default,分别代表四个访问控制级别,控制级别由小到大
private | default | protected | public | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一个包中 | √ | √ | √ | |
子类中 | √ | √ | ||
全局范围内 | √ |
-
private:当前类访问权限
如果类里的一个成员(包括成员变量、方法和构造器等)使用private访问控制符来修饰,则这个成员只能在当前类的内部被访问,一般用于修饰成员变量和一些不愿意暴露给其他类访问的方法
-
protected:子类访问权限
如果一个成员(包括成员变量、方法和构造器等)使用protected修饰,那么这个成员既可以被同一个包中的其他类访问,也可以被不同包中的子类访问,通常情况下,使用protected修饰的目的是希望其子类来重写这个方法
-
default:包访问权限
如果类中的一个成员(包括成员变量、方法和构造器等)或一个外部类不使用任何访问控制符修饰,就称它为包访问权限,default访问控制的成员或外部类可以被相同包下的其他类访问
Java8 中也作用于声明接口函数的默认实现
-
public:公共访问权限
最大的访问控制级别,如果一个成员(包括成员变量、方法和构造器等)或者一个外部类使用public访问控制符修饰,那么这个成员或外部类就可以被所有类访问,不管访问类和被访问类是否处于同一个包,是否具有父子继承关系