封装的实现
封装的概念和特点
什么是封装?
该类的某些信息隐藏在类的内部,不允许外部程序直接访问;通过该类提供的方法来实现对隐藏信息的操作和访问简单地来说就是“隐藏对象的信息”、“留出访问的接口”。
既然需要隐藏对象的信息,为什么还需要外部进行访问呢?这不是自相矛盾吗?
我们举一个生活中存款和取款的案例:
①首先我们使用的钞票是ATM机器存储的重要信息,我们是不可以随意取走钞票的。
②但是为了实现取款的功能,ATM机提供了操作面板、插卡口、取钞口。我们只需要提供银行卡和正确的密码就可以得到我们想要的钞票了。
我们从上面举例就可以看出ATM机器的巧妙之处在于即保证了重要信息(钞票)的安全性,同时也提供了相应的外部接口来实现与人物进行交互的功能。无论机器内部发生怎样的变化,只要外部提供的接口不变就可以照常的完成相应的操作。这就是封装的特点。
封装的特点
① 只能通过规定的方法访问数据
② 隐藏类的实例细节,方便修改和实现
封装代码的实现
实现步骤
属性设为private,表示私有的,只能在本类的内部访问,实现了属性对外部隐藏
方法设为public,表示公共的,为外部提供了访问内部私有属性的入口
代码实现
我们通过封装的实现步骤来描述熊猫班卜BanBo.java
package object.encapsulation;
public class BanBo {
// 1.修改属性的可见性
private String name; //名字
private int weight; //体重
private String sex; //性别
private String species; //品种
public BanBo(){
}
public BanBo(String name, int weight, String sex, String species) {
setName(name);
setWeight(weight);
setSex(sex);
setSpecies(species);
}
// 2.创建get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getSex() {
return sex;
}
// 3.加入属性控制语句
public void setSex(String sex) {
if(sex.equals("公")||sex.equals("母")){
this.sex = sex;
}else{
System.out.println(this.name+"性别设置失败!");
return;
}
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
}
在测试类中EncaTest.java中测试
package object.encapsulation;
public class EncaTest {
public static void main(String[] args) {
BanBo banBo1 = new BanBo();
//通过set设置属性
banBo1.setName("班卜1号");
banBo1.setWeight(100);
banBo1.setSpecies("panda");
banBo1.setSex("公");
//通过get获取属性
System.out.println(banBo1.getName());
BanBo banBo2 = new BanBo();
banBo2.setName("班卜2号");
banBo2.setWeight(80);
banBo2.setSpecies("panda");
banBo2.setSex("女");
//通过get获取属性
System.out.println(banBo2.getName());
}
}
运行结果:
班卜1号
班卜2号
性别设置失败!
班卜2号
性别设置失败的原因是我们在setSex方法中加入了控制语句,如果性别不是“公”或“母”,则无法对属性进行设置。
使用包进行类管理
我们在计算机中的文件都是存放在文件夹中,一个文件夹可以存放多个文件;多个同名文件只能存放在不同的文件夹中。
在java中如何进行不同类文件的管理呢?
为了便于管理大量的Java文件,Java系统引入了包的概念,包可以管理Java文件,解决同名文件的冲突问题。
创建包
在同一个包下是不能存在同名类的,因此如果创建同名文件,需要将文件放入不同包下。
包的命名规则(建议全部小写):
域名倒序+模块+功能
上面我们封装的BanBo.java存放在object.encapsulation包下,我们在该包下再创建一个entity包,并在entity包下创建BanBo.java
package object.encapsulation.entity;//定义包
public class BanBo {
// 1.修改属性的可见性
private String name; //名字
private int weight; //体重
private String sex; //性别
private String species; //品种
public BanBo() {
}
public BanBo(String name, int weight, String sex, String species) {
setName(name);
setWeight(weight);
setSex(sex);
setSpecies(species);
}
// 2.创建get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getSex() {
return sex;
}
// 3.加入属性控制语句
public void setSex(String sex) {
if (sex.equals("公") || sex.equals("母")) {
this.sex = sex;
} else {
System.out.println(this.name + "性别设置失败!");
return;
}
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
}
注意:第一行定义包的package语句必须放在第一行
导入包
如何在使用时区分不同包下的同名类?如何实现跨包的类调用?
方法一:使用import加载语句,使用 .* 的方式加载指定包下的所有类
package object.encapsulation.test;
import object.encapsulation.*; //方式一:加载object.encapsulation下的所有类
public class PackTest {
public static void main(String[] args) {
BanBo banBo = new BanBo();//实例化该包下的BanBo类
}
}
方法二:使用import导入指定包下的指定类
package object.encapsulation.test;
import object.encapsulation.entity.BanBo;//方式二:导入object.encapsulation.entity包下的BanBo类
public class PackTest {
public static void main(String[] args) {
BanBo banBo = new BanBo();//实例化object.encapsulation.entity包下的BanBo类
}
}
方法三:直接在程序中加载类
package object.encapsulation.test;
public class PackTest {
public static void main(String[] args) {
//方式三:直接在代码块内加载相应的类
object.encapsulation.BanBo banBo1 = new object.encapsulation.BanBo();
object.encapsulation.entity.BanBo banBo2 = new object.encapsulation.entity.BanBo();
}
}
建议采用 “import 包名.类名” 的方式进行加载,提高效率
加载类的顺序跟import导入的语句位置无关
“import 包名.*”只能访问指定包下的所有类,无法访问子包下的所有类
static关键字
我们之前的学习中,static关键字位于主方法中,static表示静态信息。
那么static在java程序中可以和哪些信息组合使用?用它修饰的信息具有哪些特征?
static成员变量
我们在之前创建的BanBo.java中添加一个public公共的静态属性年龄age
package object.encapsulation.entity;//定义包
public class BanBo {
// 1.修改属性的可见性
private String name; //名字
private int weight; //体重
private String sex; //性别
private String species; //品种
public static int age;//年龄
public BanBo() {
}
public BanBo(String name, int weight, String sex, String species) {
setName(name);
setWeight(weight);
setSex(sex);
setSpecies(species);
}
// 2.创建get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getSex() {
return sex;
}
// 3.加入属性控制语句
public void setSex(String sex) {
if (sex.equals("公") || sex.equals("母")) {
this.sex = sex;
} else {
System.out.println(this.name + "性别设置失败!");
return;
}
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
}
我们创建一个测试类StaticTest.java去访问一下这个静态属性
package object.encapsulation.test;
import object.encapsulation.entity.BanBo;
public class StaticTest {
public static void main(String[] args) {
BanBo banBo1 = new BanBo();
banBo1.setName("班卜1号");
banBo1.setSex("公");
banBo1.setSpecies("熊猫");
banBo1.setWeight(200);
banBo1.age = 3;
BanBo banBo2 = new BanBo();
banBo2.setName("班卜2号");
banBo2.setSex("公");
banBo2.setSpecies("熊猫");
banBo2.setWeight(220);
banBo2.age = 5;
System.out.println(banBo1.getName()+"的年龄为"+banBo1.age);
System.out.println(banBo2.getName()+"的年龄为"+banBo2.age);
}
}
运行结果:
班卜1号的年龄为5
班卜2号的年龄为5
我们发现实例化的两个对象,它们的年龄属性值都是5。
明明实例化了两个不同的对象,为什么年龄属性值会相同呢?
被static修饰的成员称为静态成员、类成员。无论实例化多少个对象,都共用一块内存空间。
静态成员的特征
① 类对象共享
② 类加载时产生,销毁时释放,生命周期长
静态成员的访问方式:对象名.静态成员 类名.静态成员
静态方法
当方法被static修饰时,该方法就成为了静态方法、类方法。
静态方法的访问方式:对象名.静态方法 类名.静态方法
静态方法和普通成员有什么区别呢?
在BanBo.java中添加一个普通成员方法和一个静态方法
//普通方法
public void run(){
this.name = "班卜";//访问成员属性
this.age = 2;//访问静态成员
System.out.println(this.age+"岁的"+this.name+"快跑!");
eat();//调用静态方法
}
//静态方法
public static void eat(){
//run();无法调用非静态方法
//this.name = "小胖";无法访问非静态成员属性
age =5;//访问静态成员变量
System.out.println("吃东西");
}
我们发现实例方法可以访问非静态成员变量、静态成员变量;也可以调用静态方法。但是静态方法是无法访问直接访问同一个类中非静态成员的,只能直接调用同一个类中的静态成员。
没有渠道可以在静态方法中访问非静态成员吗?
我们可以通过在静态方法中实例化对象,通过对象去调用该对象的实例方法。
public static void eat(){
//实例化对象
BanBo banBo = new BanBo();
banBo.name = "班卜";//设置成员属性
banBo.eat();//访问实例方法
age = 5;
System.out.println("吃东西");
}
静态代码块
在Java中,以一对“ {} ”将多行代码封装在一起,形成一个独立的代码区,这就构成了代码块。
代码块的分类:
-
普通代码块
-
构造代码块
-
静态代码块
普通代码块
普通代码块是最常见的代码块,在方法中用一对"{}"括起来的数据,就是普通代码块。普通代码块可以有多个。
在BanBo.java文件中创建一个normalCode()方法,并创建多个普通代码块
public void normalCode(){
{
System.out.println("普通代码块1");
}
{
System.out.println("普通代码块2");
}
}
构造代码块
构造代码块是在类中直接定义的,用“{}”括起来的代码。构造代码块可以有多个。
在BanBo.java文件中,直接在类下创建两个构造代码块
{
System.out.println("构造代码块1");
}
{
System.out.println("构造代码块2");
}
静态代码块
静态代码块是在类中直接定义,用“{}”括起来的代码,使用static关键字进行修饰。
在BanBo.java文件中,直接在类下创建静态代码块
static{
System.out.println("静态代码块1");
}
static{
System.out.println("静态代码块2");
}
这三种代码块的执行顺序是什么?如果实例化多个对象,代码块都会多次执行吗?
我们创建StaticTest2.java来测试一下
package object.encapsulation.test;
import object.encapsulation.entity.BanBo;
public class StaticTest02 {
public static void main(String[] args) {
BanBo banBo1 = new BanBo();
banBo1.normalCode();
System.out.println("-----------------------");
BanBo banBo2 = new BanBo();
banBo2.normalCode();
}
}
运行结果:
静态代码块1
静态代码块2
构造代码块1
构造代码块2
普通代码块1
普通代码块2
构造代码块1
构造代码块2
普通代码块1
普通代码块2
- 普通代码块
- 顺序执行,先出现先执行。
- 构造代码块
- 创建对象时调用,优于构造方法执行
- 静态代码块
- 类加载时调用,优先于构造方法块执行
- 无论产生多少类实例,静态代码块都只会执行一次
- 仅希望执行一次的代码可以放在静态代码块中



