一、概念
封装就是把属性和方法封装在一起,将数据保护在内部,程序的其他部分只有通过被授权的操作(方法),才能对数据进行操作。例如遥控器随便点点,就能控制电视的操作,而电视内部的具体实现方法,我们并不用关心。
优点:
- 隐藏实现细节。比如现在有一个方法(连接数据库)<---调用(传入参数...),我想连接数据库,只需要传入参数即可,调用者并不关心是怎么实现的。
- 可以对数据进行验证,保证安全合理。(在set方法里面可以加上业务逻辑,对设置属性进行控制)
- 将属性设置为private,这样就无法直接修改,必须通过set方法才能设置属性值。
二、封装的步骤
- 将属性私有化(即不能直接修改属性)
- 提供一个公共的set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){ //加入数据验证的业务逻辑 属性 = 参数名; }
- 提供一个公共的get方法,用于获取属性的值
public 类型 getXxx(){ //权限判断 return xx; }
三、将构造器与set方法结合
如果同时存在构造器和set方法,通过构造器初始化的对象实例会破解set方法中的逻辑判断。此时在构造器中调用set方法,即可解决这种问题,达到即使通过构造器初始化对象,也能实现数据验证的效果。
package com.hspedu.encap;
public class Encapsulation01 {
public static void main(String[] args) {
Person smith = new Person("smith", 2000, 50000);
System.out.println("======smith的信息======");
System.out.println(smith.info());
}
}
/*
1.不能随便查看人的年龄、薪水等隐私。
2.对设置的年龄进行合理性验证,合理就设置,否则就给默认值。
3.年龄是1~120;工资不能直接查看;name的长度在2~6个字符之间。
*/
class Person{
public String name; //名字公开
private int age; //age私有化
private double salary;
//构造器
public Person() {
}
//有三个属性的构造器
public Person(String name, int age, double salary) {
//将set方法写在构造器中,这样仍然可以验证属性是否合理
this.setName(name);
this.setAge(age);
this.setSalary(salary);
}
public String getName() {
return name;
}
public void setName(String name) {
//加入对数据的校验,相当于增加了业务逻辑
if (name.length() >=2 && name.length() <= 6){
this.name = name;
}else {
System.out.println("名字的长度不对,需要2~6个字符,给一个默认名字");
this.name = "大侠";
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
//判断
if (age >= 1 && age <= 120){ //如果是合理范围
this.age = age;
}else {
System.out.println("你设置的年龄不对,需要在1~120之间,因此我给你一个默认年龄18");
this.age = 18; //给一个default年龄
}
}
public double getSalary() {
//可以在这里增加一个对当前对象的权限判断,有权限的才能getSalary
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//写一个方法,返回属性信息
public String info(){
return "信息为 name=" + name + " age=" +age + " salary=" +salary;
}
}
四、封装的练习
下面是Account类:
package com.hspedu.encap;
/*
创建程序,在其中定义两个类:Account和AccountTest类,体会Java的封装性
Account类要求具有属性:姓名(长度为2或3或4)、余额(必须>20)
密码(必须是6位),如果不满足,则给出提示信息,并给默认值
通过setXxx的方法给Account的属性赋值
在AccountTest类中测试
*/
public class Account {
//为了封装,将3个属性设置为private
private String name;
private double balance;
private String pwd;
//提供两个构造器
public Account() { //使用默认的无参构造器实例化对象,然后再用实例对象调用set方法也能控制住属性;用下面的有参构造器也能控制住属性
}
public Account(String name, double balance, String pwd) {
this.setName(name);
this.setBalance(balance);
this.setPwd(pwd);
}
public String getName() {
return name;
}
//姓名(长度为2或3或4)
public void setName(String name) {
if (name.length()>=2 && name.length()<=4){
this.name = name;
}else {
System.out.println("姓名要求是(长度为2或3或4),给个默认值");
this.name = "nobody";
}
}
public double getBalance() {
return balance;
}
//余额(必须>20)
public void setBalance(double balance) {
if (balance > 20){
this.balance = balance;
}else {
System.out.println("余额(必须>20),给个默认值");
this.balance = 0;
}
}
public String getPwd() {
return pwd;
}
//密码(必须是6位)
public void setPwd(String pwd) {
if (pwd.length() == 6){
this.pwd = pwd;
}else {
System.out.println("密码(必须是6位),给个默认值123456");
this.pwd = "123456";
}
}
//显示账号信息
public void showInfo(){
//可以增加一个权限校验,比如在这里先判断一下身份是否合法,合法才可以查看
System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码=" + pwd);
}
}
下面是AccountTest类:
package com.hspedu.encap;
//AccountTest类和Account类再同一个包中,因此可以互相访问
public class AccountTest {
public static void main(String[] args) {
Account account1 = new Account();
account1.setName("mg");
account1.setBalance(60);
account1.setPwd("123456");
account1.showInfo();
Account account2 = new Account("fg",60000, "456789");
account2.showInfo();
}
}
输出结果如下:
账号信息 name=mg 余额=60.0 密码=123456
账号信息 name=fg 余额=60000.0 密码=345789