面向对象编程有三大特征:封装、继承、多态。下面给大家介绍面向对象中的封装。
基本概念:
封装就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,外部不可以直接访问到内部的数据。只有访问类中公共的方法,从而间接的访问类中私有数据。
官方描述:是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问
通俗来讲就是数据私有化,只提供对应的方法。例如 日常生活中遥控器对电视机的操作,我们操作遥控器就可以对电视机进行控制(开机,关机,换台),我们不需要去知道遥控器和电视机内部的构造细节,只需要操控遥控器即可!
封装的优点:
- 隐藏实现细节 :例如有一个实现两数之和的方法,我们将这个方法封装起来,每次调用这个方法只需要传递两个参数,并不需要去了解其内部构造,我们只要知道该方法是计算两数之和就好。
- 提高代码复用性。
- 可以对数据进行验证,保证数据的安全合理。
封装具体实现步骤:
编写people类:
/*People类中有两个被private修饰的字段,外部不可以直接访问*/
public class People {
private String name;
private int age;
public void setName(String name) {
//对数据验证 保证数据的合理性
if(name.length()>=2 && name.length() <=6){
//设置的姓名符合就将参数赋给成员变量name
this.name=name;
}else{
System.out.println("请设置长度为2~6的姓名!");
}
}
public void setAge(int age) {
if(age>=0 && age<=100){ //年龄为0~100
//设置的年龄符合就将参数赋给成员变量name
this.age=age;
}else{
System.out.println("设置年龄不符合!");
}
}
/* 提供公共方法来访问私有数据*/
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
this关键字:this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)
对People类进行测试:
/*对People类进行测试:*/
public class PeopleTest {
public static void main(String[] args) {
People people1 = new People();
//通过公共方法给私有属性赋值(设置合理的值)
people1.setName("张三");
people1.setAge(18);
System.out.println(people1.getName()); //输出 张三
System.out.println(people1.getAge()); //输出 18
System.out.println("==============");
People people2 = new People();
//通过公共方法给私有属性赋值(设置不合理的值)
people2.setName("勿以浮沙建筑高台");
people2.setAge(101);
System.out.println(people2.getName()); //输出 null
System.out.println(people2.getAge()); //输出 0
}
}
控制台输出:
张三
18
==============
请设置长度为2~6的姓名!
设置年龄不符合!
null
0
由以上案例可以发现,封装可以使我们编写的代码更加的安全,外界不可以直接访问私有属性,并且对数据进行验证其合理性,我们只需要使用提供的公共方法来进行对数据的访问即可。
出现问题:
如果在People方法中使用构造器来对类属性进行初始化怎么办?也就是说使用构造器进行初始化会绕开set和get方法,这样数据就避开了验证,破坏了封装性!具体如下:
对People添加一个有参构造方法:
/*People类中有两个被private修饰的字段,外部不可以直接访问*/
public class People {
private String name;
private int age;
//创建一个有参构造
public People(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
//对数据验证 保证数据的合理性
if(name.length()>=2 && name.length() <=6){
//设置的姓名符合就将参数赋给成员变量name
this.name=name;
}else{
System.out.println("请设置长度为2~6的姓名!");
}
}
public void setAge(int age) {
if(age>=0 && age<=100){
//设置的年龄符合就将参数赋给成员变量age
this.age=age;
}else{
System.out.println("设置年龄不符合!");
}
}
/* 提供公共方法来访问私有数据*/
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
对People进行测试:
/*对People类进行测试:*/
public class PeopleTest {
public static void main(String[] args) {
People people = new People("勿以浮沙建筑高台", 101);
System.out.println(people.getName());
System.out.println(people.getAge());
}
}
控制台打印:
勿以浮沙建筑高台
101
由控制台打印结果可以看出,使用构造器进行初始化破坏了封装性!
解决方法:
我们可以将构造器中的代码修改成调用本类的set的方法。当创建对象时,执行有参构造的时候,会调用里面的方法,从而进一步对数据进行了验证,如下:
修改构造器:
public People(String name, int age) {
//调用本类中的set方法
setName(name);
setAge(age);
}
测试结果:
请设置长度为2~6的姓名!
设置年龄不符合!
null
0
有结果可知,这样一来,就解决了构造初始化时破坏封装性的问题。
目标越接近,困难越增加。——歌德