封装概述
java中的封装指的是将一系列有关的事物的共同属性和行为提取出来放到一个类中,隐藏对象的实行和现实细节,仅对外提供公共的访问方式的操作。这样说起来感觉很抽象,也不好理解,这里不妨举一个例子。将配置电脑这个动作看成封装。
这个要怎么理解呢?一般情况下,现在大多数人使用的是笔记本电脑,但是在排除风险的情况下,台式机的性价比要高于笔记本,这里不讨论如何配置一台好的台式机,也不需要理解如何配置台式机,只要理解,所谓的台式机就是将电脑需要的显卡、声卡、内存条、散热装置等放到一个盒子里,然后在这个盒子上开了一些口,用来连接键盘、耳机、电源、显示器等。配置完一台电脑后,只需要通过键盘和鼠标就能对电脑进行操作了。这里将显卡、声卡、内存条等装置放入机箱的过程看成封装,就相当于隐藏对象的实行和现实细节,预留的电源和usb接口就是提供公共的访问方式。
那么封装带来了一些什么样的好处呢?依然以台式机的主机作为例子,如果台式机的主机没有机箱,那么它里面的声卡啊、显卡啊什么的都将直接暴露在空气中,且无法直接固定,那么各个装置之间的连接极有可能因为使用者的粗心而频繁失效,同时用电也会成为安全隐患,所以封装首先就提供了安全性。其次,封装之后提供了对外的公共访问接口,一台没有进行封装的电脑主机,它与外界的连接不一定是标准接口,那么就不是所有的外接设备都能使用这个电脑主机,它的复用性也就大大降低了。最后,如果不是电脑高手,而是一个电脑小白,那么要使用台式电脑,可以直接购买电脑主机,不需要对电脑主机进行配置,将原本复杂的配置流程直接简化。这就是封装的好处,大大降低了事情的复杂程度。
在java中,封装体包括了方法和类。方法的安全性体现在调用者不知道方法是如何实现的,只知道方法的功能,并将其调用;复用性体现在方法可以重复使用;简单化体现为将冗杂的代码用一个方法体现出来,通过调用方法就可以实现方法的功能,代码的维护也变得更加方便。类的安全性体现在调用者不知道类是如何实现的,只能通过访问定义类中的对象,但这个类中定义的对象属性以及方法究竟是怎样的,调用者并不知道;复用性体现为一个类中可以定义多个对象;简单化体现为类中的对象,拥有的方法功能并不单一,但只要调用者合法访问就能调用对象方法,实现对象功能。
封装的实现——访问控制符
在java中,访问控制符一共有四个,即private,default(即下表中的默认)、protected以及public。它们的访问权限如下表所示,接下来对它们的作用一一叙述。
private,权限修饰符,表示私有,当用来修饰类中的成员时,被修饰的成员只能在本类中被访问。使用private时的具体格式为:
private 数据类型 变量名;
private 返回值类型 方法名(参数列表){};
default,表示没有修饰符,可以写,也可以不写。当用default来修饰类中的成员时,被修饰的成员不仅在本类中能被访问,与本类处于同一个包中的类也能对被defanlt修饰的成员进行访问。但本类的子类以及其他的类无法访问default修饰的成员。
protected,表示被保护的,当用protected来修饰成员时,被修饰的成员不仅能被本类和与本类处于同一个包下的类访问,还能被本类的子类访问,但是除此之外,其他的类不能访问被protected修饰的成员。这里要注意,当本类的子类要访问被protected修饰的成员时,有一个注意事项,那就是如果父类和子类在同一个包中,子类可以访问父类的protected成员,也可以访问父类对象的protevted成员,但当父类和子类不在同一个包中时,子类可以访问父类的protected成员,但不能访问父类对象的protected成员。
public公共的,即所有的类都可以访问public修饰的成员。
接下来用代码来具体演示这四个关键字的使用,以加深理解。首先创建两个包,分别为cn.fengzhuang.demo和cn.fengzhuang.demo1。在cn.fengzhuang.demo中创建三个对象,分别为Person、Student和Student1,其中Student1为Person的子类。在cn.fengzhuang.demo1中创建两个类,分别为Teacher和Teacher1,其中Teacher1为Person类的子类。以下为这5个类的关系以及创建代码:
public class Person {
private int testPrivate = 100;
int testDefault = 200;
protected int testProtected = 300;
public void test(){
System.out.println(this.testPrivate);
System.out.println(this.testDefault);
System.out.println(this.testProtected);
}
}
package cn.fengzhuang.demo;
public class Student {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p.testPrivate);
System.out.println(p.testDefault);
System.out.println(p.testProtected);
}
}
package cn.fengzhuang.demo;
public class Student1 extends Person {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.Private);
System.out.println(person.testDefault);
System.out.println(person.testProtected);
}
}
package cn.fengzhuang.demo1;
import cn.fengzhuang.demo.Person;
public class Teacher extends Person {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println(p1.testPrivate);
System.out.println(p1.testDefault);
System.out.println(p1.testProtected);
}
}
package cn.fengzhuang.demo1;
import cn.fengzhuang.demo.Person;
public class Teacher1 extends Person {
public void test(){
System.out.println(super.testProtected);
}
public static void main(String[] args) {
Person p3 = new Person();
System.out.println(p3.testPrivate);
System.out.println(p3.Default);
System.out.println(p3.testProtected);
}
}
在以上的五个代码中,每一个代码都会报错,接下来,根据四个关键字的作用来分析这些错误。首先,对于private关键字,它修饰的成员只能在本类中被访问,所以除了Person类能正常访问成员testPrivate外,其他的类访问testPrivate均会报错。
其次,对于default关键字 ,被它修饰的成员不仅在本类中能被访问,与本类处于同一个包中的类也能对被defanlt修饰的成员进行访问,因此,对于testDefault成员,Person、Student、Student1这三个类不会报错,而cn.fengzhuang.demo1下的Teacher和Teacher1两个类在访问testDefault成员时会报错。
对于protected关键字,由于被修饰的成员不仅能被本类和与本类处于同一个包下的类访问,还能被本类的子类访问,但如果父类和子类在同一个包中,子类可以访问父类的protected成员,也可以访问父类对象的protevted成员,但当父类和子类不在同一个包中时,子类可以访问父类的protected成员,但不能访问父类对象的protected成员。因此Person、Student、Student1这三个类访问testProtect成员时不会报错,但Teacher访问testProtect成员时会报错。而对于,Teacher1类,因为它和Person类不再同一个包中,因此如果在Teacher1类中访问父类的protected成员就不会报错,但是如果在这个类中访问父类对象的protected成员就会报错。简单来说就是,如果通过对象来访问protected成员时,protected成员已经属于了类,所以叫对象的protected成员,会报错。但是如果通过super关键字直接访问父类中的protected成员,则不会报错。错误提示如下图。
封装的使用
前面,用电脑主机的配置来比喻java中的封装,那么会有人想,如果电脑主机中的配件坏了怎么办呢?得拆开来修吗?其实,一般情况下,电脑会提供一套方法来检测电脑中软件或者硬件是否出现问题,这就涉及到了访问电脑主机中的配件的问题。同样,对于java中的封装体,一般情况下,属性类通常用private关键字来修饰,也就是只能在本类中访问这些成员变量,所以也得有算法来帮助访问封装体中的成员。
在java中一般提供set和get方法来访问相关的私有属性,用来对属性进行赋值或者读取操作,值得注意的是,boolean类型的get方法不是get开头,而是is开头。
接下来用一个简单的javabean代码来演示set和get方法。
Person1 {
private String name;
private int age;
private boolean flag;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
if(age<=0||age >150){
System.out.println("非法输入");
}
else{
this.age = age;
}
}
public int getAge(){
return age;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public class TestPerson1 {
public static void main(String[] args) {
Person1 p = new Person1();
p.setAge(100);
System.out.println(p.getAge());
}
}
从上面的代码当中,能够看到,boolean类型的成员flag的set方法采用的方法名称为 isFlag。
而值得注意的是,java中的set和get方法可以自己写,也可以通过快捷键ALT+INS调出窗口,然后根据窗口提示快速生成。