JavaEE - 05OOP封装
(1)面向对象特征之一: 封装与隐藏
(1.1)问题的引入
- 当我们创建一个类的对象以后,可以通过"对象.属性"的方式,给对象的属性进行赋值。
- 赋值操作要受属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。
- 在实际问题中,往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,只能通过方法进行限制条件的添加。
- 同时,需要避免用户再使用"对象.属性"的方式对属性进行赋值。需要将属性声明为私有的(private)。
- 此时,针对属性就提现了封装性。
(1.2)封装性概述
- 为什么需要封装?封装的作用和含义?
- 给属性添加额外的限制条件
- 程序设计追求"高内聚,低耦合"。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅对外暴露少量的方法用于使用。
- 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。
- 通俗的说,把该隐藏的隐藏起来,把该暴露的暴露出来。这就是封装性的设计思想。
- 通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。
- 面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。
- 可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程 接口。
> 未对类的属性进行限制前:
public class Animal { String name; int age; int legs; public void show(){ System.out.println("我有"+ legs +"条腿"); } }
public class AnimalTest { public static void main(String[] args) { Animal a = new Animal(); a.name = "大红"; a.age = 1; a.legs = 4; a.show(); // 我有4条腿 a.legs = -4; // -4不合理 a.show(); // 我有-4条腿 } }
> 对类的属性设置限制,添加方法对属性进行设置和获取
public class Animal { String name; int age; private int legs; // 对属性的设置 public void setLegs(int i){ if(i >= 0 && i%2==0){ legs = 1; }else{ legs = 0; } } // 对属性的获取 public int getLegs(){ return legs; } public void show(){ System.out.println("我有"+ legs +"条腿"); } }
public class AnimalTest { public static void main(String[] args) { Animal a = new Animal(); a.name = "大红"; a.age = 1; // a.legs = 4; //' legs' has private access in 'Animal' a.setLegs(4); a.show(); // 我有1条腿 System.out.println(a.getLegs()); // 1 } }
(1.3)封装性的体现
- 将类的属性xxx私有化(private),同时提供公共的(public)方法来获取(getXxx)和设置(setXxx)属性。
- 不对外暴露的私有方法
- 单例模式
(2)四种访问权限修饰符
- 四种权限可以用来修饰类及类的内部结构: 属性、方法、构造器、内部类。
- Java权限修饰符public、protected、private置于类的成员定义之前,用来限定对象对该类成员的访问权限。
- 对于class的权限修饰符只可以用public和 default(缺省)。
- public 类可以在任意地方被访问。
- default类只可以被同一个包内部的类访问。
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
private | Yes | |||
缺省 | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |
> 出了Order类,私有属性和私有方法都不能调用;出了同一包,缺省的就不能访问了
public class OrderTest2 { public static void main(String[] args) { Order order = new Order(); // 'orderDefault' is not public in 'com.bearpx.java.Order'.Cannnot be accessed from outside package. // order.orderDefault = 111; order.orderPublic = 112; // 出了Order类之后,私有属性不可以调用了 // order.orderPrivate = 113; // order.methodDefault(); order.methodPublic(); //'methodPrivate()' has private access in 'Order' // order.methodPrivate(); } }
(3)类的成员之三: 构造器(构造方法)
(3.1)构造器特征
- 它具有与类相同的名称
- 它不声明返回值类型。(与声明为void不同)
- 不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值。
(3.2)构造器作用
- 构造器作用:
- 创建对象。 new + 构造器 Person p = new Person();
- 给对象进行初始化 Person p = new Person("Peter",15);
- 如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器。
- 定义构造器的格式: 权限修饰符 类名(形参列表) {}
- 一个类中定义的多个构造器,彼此构成重载
- 一旦我们显示的定义了类的构造器之后,系统就不再提供默认的空参构造器
(3.3)属性赋值的先后顺序
先后顺序: 默认初始化 显示初始化 构造器中赋值 通过"对象.方法" 或"对象.方法"的方式赋值
public class User { String name; int age = 1; public User(){ } public User(int a){ age = a; } public void setAge(int a){ age = a; } }
public class UserTest { public static void main(String[] args) { User u = new User(); System.out.println(u.age); //1 User u1 = new User(2); System.out.println(u1.age); //2 u1.setAge(3); System.out.println(u1.age); //3 } }
(4)拓展知识
(4.1)JavaBean
- JavaBean是一种Java语言写成的可重用组件。
- 所谓JavaBean, 是指符合以下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法
- 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创建的对象进行打包,
- 并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。
- 用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
(4.2)UML类图
- + 表示 public 类型, - 表示private类型, #表示 protected类型
- 方法的写法: 方法的类型(+、-) 方法名(参数名: 参数类型) : 返回值
- 方法有下划线 表示为构造器
(5)关键字: this
- this表示当前对象,可以调用类的属性、方法和构造器
- 它在方法内部使用,即 这个方法所属对象的引用;
- 它在构造器内部使用,表示该构造器正在初始化的对象。
- 什么时候使用this关键字?
- 当在方法内部需要用到调用该方法的对象时,就用this。
- 具体的:方法的形参和类的属性同名时,用this来区分局部变量和属性。 比如: this.name = name; 构造器同理。
- 在类的方法中,使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。通常,省略"this."。
- this调用构造器
- 在类的构造器中,可以显式的使用"this(形参列表)"方法,调用本类中指定的其他构造器。
public class User { private String name; private int age = 1; public User(){ } public User(int age){ this.age = age; } public void setAge(int age){ this.age = age; } public void eat(){ System.out.println("人吃饭"); this.study(); } public void study(){ System.out.println("学习"); } }
public User(int age){ this.age = age; } public User(String name, int age){ this(age); this.name = name; // this.age = age; // 初始化时,可以抽象的共同的代码, 使用this(age)先一步处理。 }
(6)关键字: package、import
(6.1)package关键字
- 为了更好的实现项目中类的管理,提供包的概念。
- 使用package声明类或接口所属的包,声明在源文件的首行。
- 包,属于标识符,遵循标识符的命名规则、规范,"见名知意"
- 每"." 一次,就代表一层文件目录。
- 同一包下,不能命名同名的接口、类;不同的包下,可以命名同名的接口、类。
(6.2)import关键字
- 在源文件中显式的使用import结构导入指定包下的类、接口
- 声明在包的声明和类的声明之间
- 如果需要导入多个结构,则并列写出即可。
- 使用"xxx.*"的方式,表示可以导入xxx包下的所有结构
- 如果使用的类或接口是java.lang包下定义的类或接口,可以省略import结构
- 如果使用的类或接口是本包下定义的,可以省略import结构
- 如果源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
- 使用"xxx.*"方式声明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,仍需要显式导入。
- import static : 导入指定类或接口中的静态结构。