1.封装
1.1 概述
面向对象编程语言是对客观世界的模拟,客观世界里每一个事物的内部信息都是隐藏在对象内部的,外界无法直接操作和修改,只能通过指定的方式进行访问和修改。封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。正如现实生活中,每一个个体与个体之间是有边界的,每一个团体与团体之间是有边界的,而同一个个体、团体内部的信息是互通的,只是对外有所隐瞒。
随着业务系统越来越复杂,类会越来越多,那么类之间的访问边界必须把握好,面向对象的开发原则要遵循“高内聚、低耦合”,而“高内聚,低耦合”的体现之一:
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅对外暴露少量的方法用于使用
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的讲,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
Q:封装就是把该隐藏的隐藏起来,该暴露的暴露出来。那么暴露的程度如何控制呢?
A: 依赖访问控制修饰符,也称为权限修饰符来控制。
访问控制修饰符来控制相应的可见边界,边界有如下:类、包、子类、模块(Java9之后引入)。权限修饰符:public,protected,缺省,private。
修饰符 | 本类 | 本包 | 其他包子类 | 其他包非子类 | 其他模块 |
---|---|---|---|---|---|
private | √ | × | × | × | × |
缺省 | √ | √ | × | × | × |
protected | √ | √ | √ | × | × |
public | √ | √ | √ | √ | 默认不可以,可以建立依赖 |
1.2 成员变量/属性私有化问题
成员变量(field)私有化之后,提供标准的get/set方法,我们把这种成员变量也称为属性(property)。 或者可以说只要能通过get/set操作的就是事物的属性,哪怕它没有对应的成员变量。
1.2.1 成员变量封装目的
- 隐藏类的实现细节
- 保证对象信息的完整性,提高代码的安全性。让使用者只能通过事先预定的方法来访问数据,从而可在该方法里面加入控制逻辑,限制对成员变量的不合理访问。还可以进行数据检查,从而有利于保证对象信息的完整性。
- 便于修改,提高代码的可维护性。主要体现在隐藏的部分,在内部修改了,如果其对外可以的访问方式不变,外部根本感觉不到它的修改。例如:Java8->Java9,String从char[]转为byte[]内部实现,而对外的方法不变,使用者根本感觉不到它内部的修改。
1.2.2 成员变量封装实现
-
使用
private
修饰成员变量public class Chinese{ private static String Country; private String name; private int age; private boolean marry; }
-
提供
getXxx
方法 /setXxx
方法,可以访问成员变量package JavaBase; public class Chinese { private static String country; private String name; private int age; private boolean marry; public static void setCountry(String c) { country = c; } public static String getCountry() { return country; } public void setName(String n) { name = n; } public String getName() { return name; } public void setAge(int a) { age = a; } public int getAge() { return age; } public void setMarry(boolean m) { marry = m; } public boolean isMarry(){ return marry; } }
1.2.3 如何解决局部变量与成员变量同名问题
当局部变量与类变量(静态成员变量)同名时,在类变量前面加“类名.";
当局部变量与实例变量(非静态成员变量)同名时,在实例变量前面加“this.”。
public class Chinese {
private static String country;
private String name;
private int age;
public static void setCountry(String country) {
Chinese.country = country;
}
public static String getCountry() {
return country;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
1.3 包(Package)
1.3.1 包的作用
- (1)可以避免类重名:有了包之后,类的全名称就变为:包.类名【便于使用】
- (2)分类组织管理众多的类【便于管理类】
- (3)可以控制某些类型或成员的可见范围【便于管理类成员】
Java中常见的包:
包名 | 作用 |
---|---|
java.lang | Java语言的核心类,如String、Math、Integer、 System和Thread等,提供常用功能 |
java.net | 执行与网络相关的操作的类和接口 |
java.io | 提供多种输入/输出功能的类 |
java.util | 实用工具类,如集合框架类、日期时间、数组工具类Arrays,文本扫描仪Scanner,随机值产生工具Random |
java.text | Java格式化相关的类 |
1.3.2 如何声明包?
package 包名;
注意:
(1)必须在源文件的代码首行
(2)一个源文件只能有一个声明包的语句
包名命名规范与习惯:
-
- 所有单词都小写,每一个单词之间使用.分割
-
- 习惯用公司的域名倒置
1.3.3 如何跨包使用类?
前提:被使用的类或成员的权限修饰符是>缺省的,即可见的。
-
- 使用类型的全名称
java.util.Scanner input = new java.util.Scanner(System.in);
-
- 使用import 语句之后,代码中使用简名称
import 包.类名; import 包.*; import static 包.类名.静态成员;
2.构造器(Constructor)
2.1 构造器的作用
在创建对象的时候为实例变量赋初始值。
注意:构造器只为实例变量初始化,不为静态类变量初始化
2.2 构造器的语法格式
构造器又称为构造方法,由于构造器很像方法。但是和方法还有有所区别的。
【修饰符】构造器名(){
// 实例初始化代码
}
【修饰符】构造器名(参数列表){
// 实例初始化代码
}
package JavaBase;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
注:
-
- 构造器名必须与它所在的类名必须相同。
-
- 它没有返回值,所以不需要返回值类型,甚至不需要void
-
- 如果不提供构造器,系统会给出无参数构造器,并且该构造器的修饰符默认与类的修饰符相同
-
- 如果提供了构造器,系统将不再提供无参数构造器,除非你自己定义。
-
- 构造器是可以重载的,既可以定义参数,也可以不定义参数。
-
- 构造器的修饰符只能是权限修饰符,不能被其他任何修饰
3.标准JavaBean
JavaBean
是 Java语言编写类的一种标准规范。符合JavaBean
的类,要求:
-
(1)类必须是具体的和公共的;
-
(2)具有无参数的构造方法;
-
(3)成员变量私有化,并提供用来操作成员变量的
set
和get
方法。public class ClassName{ //成员变量 //构造方法 //无参构造方法【必须】 //有参构造方法【建议】 //getXxx() //setXxx() //其他成员方法 }
编写符合
JavaBean
规范的类,以学生类为例,标准代码如下:public class Student { // 成员变量 private String name; private int age; // 构造方法 public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } // get/set成员方法 public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } //其他成员方法列表 public String getInfo(){ return "姓名:" + name + ",年龄:" + age; } }
4.总结