封装
1 封装概述
封装是面向对象的三大特征之一,面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性
下面是封装的一些关键概念和实践:
-
类:类是Java封装的基础,它是一种用户自定义的数据类型,用于描述具有相同属性和行为的对象。
-
访问修饰符:Java提供了四种访问修饰符来控制对类、属性和方法的访问权限。其中,
private
表示私有的,只能在当前类内部访问;public
表示公有的,可以在任何地方访问;protected
表示受保护的,可以在当前类、同一包内、以及其子类中访问;默认(不指定修饰符)表示包级私有的,可以在同一包内访问。 -
属性私有化:通过将类的属性声明为私有的,可以限制对属性的直接访问,避免外部直接修改属性的值。通常使用
private
关键字修饰属性。 -
公共方法:为了让外部能够访问和操作私有的属性,可以提供公共方法(也称为 Getter 和 Setter 方法)来间接访问和修改属性的值。公共方法通常使用
public
关键字修饰。
-
举例:
就拿一辆汽车来说,外部有一个壳,将内部的原件封装起来,至于汽车内部的细节是什么,我们不需要关心,对于用户来说,我们只需要会操作这辆汽车就可以,汽车对外提供方向盘、离合器、油门、以及一些娱乐设备,这样就将内部的东西不在直接暴露给外部,增加了安全性;
我们来举例一段代码,看看没有封装的对象会存在什么问题:
准备一个Student类,具备姓名、年龄等属性
public class Student {
// 学生姓名
String name;
// 学生年龄
int age;
}
编写测试类:
public class Demo01 {
public static void main(String[] args) {
Student s1 = new Student();
s1.name = "小灰";
s1.age = 2800;
intro(s1);
Student s2 = new Student();
s2.name = "小蓝";
s2.age = -280;
intro(s2);
}
public static void intro(Student student) {
System.out.println("大家好,我叫" + student.name + ",今年" + student.age + "岁");
}
}
上述代码是可以正常运行的(编译不会报错),但是对于我们程序逻辑来说是错误的;
Student类未进行封装,其所有属性直接暴露给外部,外部程序可以任意的对Student的属性就行修改,这是非常有安全隐患的,我们的正常年龄可以设置一个正常区间如0~120岁,不可能到2800多岁,也不可能是负的岁数;因此我们要对属性加以管控,而不是直接暴露给外端;
封装数据的优点:
- 数据隐藏:封装可以隐藏实现细节,防止外部直接访问和修改对象的内部状态。
- 数据安全:通过公共方法控制对属性的访问,可以进行额外的安全验证和控制。
- 代码重用:通过封装数据和行为,可以将相关的操作放在一起,提高代码的重用性和可维护性。
- API设计:封装可以提供清晰的公共接口,方便其他开发人员使用和理解。
封装是Java面向对象编程中非常重要的概念,它帮助我们构建更加健壮、安全和可维护的程序。通过合理地设计类、属性和方法的访问权限,可以有效地封装和保护对象的状态,并提供符合对象语义的公共接口。
2 priavte 关键字
在Java中,private
是一种访问修饰符,用于限制类的成员(字段、方法和内部类)的访问范围。当一个成员被声明为private
时,它只能在当前类内部被访问,而无法从其他类中直接访问。
下面是private
关键字的一些特点和用途:
- 访问限制:
private
关键字用于将成员限制为仅在当前类内部访问,这样其他类就无法直接访问这些私有成员。 - 数据隐藏:通过将属性声明为
private
,可以隐藏实现细节,防止外部直接访问和修改对象的内部状态。这样可以保护数据的完整性和安全性。 - 封装实现:
private
关键字是封装的重要工具之一,它使得我们可以将类的内部实现细节隐藏起来,只暴露出必要的公共接口。 - 公共方法:通常使用公共方法(Getter 和 Setter 方法)来间接访问和修改私有属性的值。这样可以在公共方法中添加额外的逻辑、验证或控制,确保数据的有效性和安全性。
- 类的封装:通过将类的构造方法声明为
private
,可以限制类的实例化,只能在类的内部创建对象。这种模式常用于实现单例模式或工具类。
需要注意以下几点:
private
只能修饰类的成员(字段、方法和内部类),不能修饰类本身。private
成员只能在当前类的作用域内被直接访问,如果要从其他类中访问私有成员,可以通过公共方法来间接访问。- 在类的继承关系中,子类无法直接访问父类的私有成员,即使是通过继承关系也不行。
封装的原则:将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问
1)使用private
修饰成员变量,代码如下:
public class Student {
// 学生姓名
private String name;
// 学生年龄
private int age;
}
2)提供 getXxx
方法 / setXxx
方法,可以访问成员变量,代码如下
public class Student {
// 学生姓名
private String name;
// 学生年龄
private int age;
public String getName() {
return name;
}
public void setName(String _name) {
name = _name;
}
public int getAge() {
return age;
}
public void setAge(int _age) {
if (_age > 0 && _age < 120) {
age = _age;
System.out.println("赋值成功,您的年龄为: " + _age);
} else {
System.out.println("您输入的年龄不合法," + _age);
}
}
}
3)测试类:
public class Demo01 {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("小灰");
s1.setAge(2888);
s1.setAge(-280);
s1.setAge(20);
}
public static void intro(Student student) {
System.out.println("大家好,我叫" + student.getName() + ",今年" + student.getAge() + "岁");
}
}
经过封装后,属性再也不是直接暴露给外部了,我们可以在外部操作属性之前加以控制;
通过合理使用private
关键字,可以提高代码的安全性和可维护性,同时实现封装的设计原则,将对象的内部状态和实现细节隐藏起来,仅暴露出必要的公共接口。这样可以使代码更加健壮和可靠。
3 this 关键字
this是Java中的一个关键字,代表所在类的当前对象的引用(地址值),即对象自己的引用;
在Java中,this
是一个特殊的关键字,代表当前对象的引用。它可以用于以下几种情况:
-
引用当前对象:
this
关键字可以用于引用当前对象本身。当需要在当前对象的方法内部访问该对象的成员变量或方法时,可以使用this
关键字来引用当前对象。例如:
public class MyClass { private int value; public void setValue(int value) { this.value = value; // 使用this引用当前对象的成员变量 } public void someMethod() { // 调用当前对象的另一个方法 this.setValue(10); } }
-
区分同名的成员变量和局部变量:当方法中存在与成员变量同名的局部变量时,可以使用
this
关键字来区分二者。例如:
public class MyClass { private int value; public void setValue(int value) { this.value = value; // 使用this引用当前对象的成员变量 } public void someMethod(int value) { this.setValue(value); // 使用this引用当前对象的方法,并传入参数 } }
-
在构造方法中调用其他构造方法:如果一个类有多个构造方法重载,可以使用
this
关键字在一个构造方法中调用另一个构造方法。例如
public class MyClass { private int value; public MyClass() { this(0); // 调用带参数的构造方法 } public MyClass(int value) { this.value = value; } }
案例:
修改Student中的set方法:
public class Student {
// 学生姓名
private String name;
// 学生年龄
private int age;
public String getName() {
return name;
}
public void setName(String name) {
// this代表当前对象的内存地址值
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0 && age < 120) {
// this代表当前对象的内存地址值
this.age = age;
System.out.println("赋值成功,您的年龄为: " + age);
} else {
System.out.println("您输入的年龄不合法," + age);
}
}
}
tips :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
需要注意以下几点:
this
关键字只能在非静态方法和构造方法中使用,因为它代表当前对象,而静态方法和构造方法属于类级别,没有当前对象的引用。- 在实例方法以外的地方(如静态方法、静态初始化块等),不能使用
this
关键字。 - 当前对象的引用
this
是隐式的,可以省略不写。但在需要明确指定当前对象时,可以显式地使用this
关键字。
总的来说,this
关键字在Java中用于引用当前对象,并在特定的情况下提供了更多的灵活性和语义清晰性。它可以用于访问当前对象的成员变量、调用当前对象的方法,以及在构造方法中调用其他构造方法。
4 构造方法
构造方法也叫构造器,顾名思义就是用来构造类的;当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
tips:无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法,一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。
- 构造方法的定义格式
修饰符 构造方法名(参数列表){
// 方法体
}
构造方法的写法上,方法名与它所在的类名相同。它没有返回值,所以不需要返回值类型,甚至不需要void。使用构造方法后,代码如下:
public class Phone {
private String name;
private int price;
// 无参构造方法
public Phone() {
}
// 有参构造方法
public Phone(String name, int price) {
this.name = name;
this.price = price;
}
}
Java中的构造方法有以下几个特点:
- 构造方法名称与类名相同,且不能用任何返回类型(包括void)进行定义。
- 无参构造方法:如果一个类没有定义任何构造方法,编译器会自动生成一个无参数的构造方法。如果自己定义了构造方法,编译器就不再默认生成无参数构造方法。
- 每个类可以有多个构造方法重载,它们的参数列表可以不同,这样可以通过不同的方式来初始化对象。
- 如果一个类没有定义任何构造方法,那么编译器会默认生成一个无参构造方法;如果定义了有参构造方法,需要显式定义无参构造方法,否则无法使用无参构造方法创建对象。
需要注意以下几点:
-
构造方法是一种特殊的方法,用于创建和初始化对象。与其他方法不同,构造方法没有返回值,其名称必须与类名相同。
-
每个类可以有多个构造方法重载,它们的参数列表可以不同,这样可以通过不同的方式来初始化对象。
-
如果一个类没有定义任何构造方法,那么编译器会默认生成一个无参构造方法;如果定义了有参构造方法,需要显式定义无参构造方法,否则无法使用无参构造方法创建对象。
-
在构造方法内部,可以调用其他的构造方法,比如通过
this
关键字来调用另一个构造方法。这种方式可以避免重复初始化代码的出现,提高代码的复用性。 -
构造方法的访问修饰符可以是public、private、protected或者不写,默认为public,但private的构造方法只能在当前类中被调用,protected的构造方法可以被其子类调用。
-
构造方法不能被静态修饰符修饰,因为构造方法的主要目的就是创建对象,而静态方法属于类级别而不是对象级别。
5 标准JavaBean
JavaBean
是 Java语言编写类的一种标准规范。符合 JavaBean
的类,要求类必须是和公共的,并且具有无参数的构造方法,提供用来操作成员变量的 set
和 get
方法,采用private修饰成员变量。
-
格式如下:
public class ClassName{ //成员变量 //构造方法 //无参构造方法【必须】 //有参构造方法【建议】 //成员方法 //getXxx() //setXxx() }