前言
Java语言是一个纯的面向对象程序设计语言,所以它有封装,继承,多态的特性,今天要学习的是封装特性。
学习之前,我们应该知道什么是封装,为什么要封装,如何实现封装
在Java中,封装是一种面向对象编程的概念,用于将相关的数据和行为封装到一个单独的实体中,称为类。通过使用访问修饰符(如public、private、protected)来控制类的成员的可见性,从而实现对数据的隐藏和访问的限制。
在Java中,封装的主要目的是保护对象的内部状态不受外部直接访问和修改,只允许通过定义的方法来操作数据。以下是封装的几个原因和好处:
- 数据隐藏:封装通过将数据声明为私有(private),可以防止外部直接访问和修改对象的内部状态。只提供公有(public)的方法来控制对数据的访问,这样可以确保数据的完整性和安全性。
- 信息隔离:封装将数据和操作封装在类的内部,对外部代码隐藏了具体的实现细节。这样,外部代码只需要关心如何使用公有方法来与对象交互,而无需了解内部的实现逻辑,降低了代码的复杂性。
- 代码重用:封装使得代码更加模块化和可维护。通过将相关的数据和方法封装在一个类中,可以提高代码的重用性。其他代码可以通过创建对象并调用公有方法来使用封装的类,而不必关心具体的实现细节。
- 灵活性和可扩展性:封装提供了一种独立性,使得类的内部实现可以自由修改,而对外部代码没有影响。这样可以增强系统的灵活性和可扩展性,方便对类进行修改、优化或扩展功能。
总之,封装是Java面向对象编程的重要特性,通过隐藏和限制对数据的访问,提供清晰的接口和信息隔离,带来了数据安全性、代码复用性和系统灵活性等好处。
要实现类的封装,可以按照以下步骤进行操作:
- 将类的属性私有化:在定义类时,使用private关键字修饰类的属性,即将属性设置为私有(private)访问权限。这样外部代码就无法直接访问该属性。
public class MyClass { private int myPrivateVariable; // 私有属性 }
- 提供公有的setter和getter方法:通过公有(public)的方法来设置和获取私有属性的值。setter方法用于设置属性的值,getter方法用于获取属性的值,并且这两个方法通常以"set"和"get"开头,后面加上属性名首字母大写的形式。
public class MyClass { private int myPrivateVariable; // 私有属性 public void setMyPrivateVariable(int value) { myPrivateVariable = value; } public int getMyPrivateVariable() { return myPrivateVariable; } }
- 通过setter和getter方法来访问属性:外部代码需要通过调用对象的公有方法(setter和getter)来设置和获取属性的值。这样就可以实现对私有属性的间接访问和操作。
public class Main { public static void main(String[] args) { MyClass obj = new MyClass(); obj.setMyPrivateVariable(10); // 通过setter方法设置属性值 int value = obj.getMyPrivateVariable(); // 通过getter方法获取属性值 System.out.println(value); // 输出: 10 } }
通过以上步骤,我们将属性私有化,并通过公有的setter和getter方法提供对属性的访问方式,实现了类的封装。这样可以确保属性的访问受到限制,同时提供了一种控制数据访问和保护数据安全的机制。
this关键字
在Java开发中,当成员变量与局部变量发生重名问题时,可以使用this关键字来区分它们。this关键字的主要作用有以下三种:
- 调用本类中的属性:通过使用this关键字,可以引用当前对象的成员变量。这样可以在方法或构造方法内部访问到同名的成员变量,而不是局部变量。
public class MyClass { private int myVariable; public void setMyVariable(int myVariable) { this.myVariable = myVariable; // 使用this关键字访问成员变量 } }
- 调用成员方法:使用this关键字调用当前对象的其他成员方法。通过this.methodName()的形式,可以在一个成员方法内部调用同一个对象的其他方法。
public class MyClass { public void method1() { System.out.println("这是方法1"); } public void method2() { this.method1(); // 使用this关键字调用成员方法 System.out.println("这是方法2"); } }
- 调用本类的构造方法:在构造方法内部,使用this关键字可以调用本类的其他构造方法。这样可以实现构造方法的重载和代码复用。
class Student { private String name; private int age; public Student () { System.out.println("实例化了一个新的Student对象。"); } public Student (String name,int age) { this(); // 调用无参的构造方法 this.name = name; this.age = age; } public String read(){ return "我是:"+name+",年龄:"+age; } } public class myclass { public static void main(String[] args) { Student stu = new Student ("张三",18); // 实例化 Student对象 System.out.println(stu.read()); } }
在使用this关键字调用类的构造方法时,需要注意以下几点:
- 只能在构造方法中使用this调用其他构造方法:this关键字只能在构造方法内部使用,并且用于调用同一个类的其他构造方法。它不能在普通的成员方法中通过this调用构造方法。
- 在构造方法中,使用this调用构造方法的语句必须位于第一行:如果在一个构造方法中使用了this调用另一个构造方法,那么这个this调用语句必须出现在构造方法的第一行代码位置。这是因为构造方法在创建对象时会先执行被调用的构造方法,所以确保调用语句在第一行可以避免出现逻辑错误。
- 不能在一个类的两个构造方法中使用this互相调用。
静态代码块
在之前的文章里讲过静态变量,同学们如果有哪些不懂的地方,可以转回去再看看,这是传送门:Java基础篇--变量类型
在Java中,静态代码块的内容会在类第一次使用时加载,并且只会加载一次。它们在类加载过程中执行,优先于其他代码块和构造方法。
静态代码块用来初始化静态变量或执行只需执行一次的操作,因此通常被用来进行一些全局性的初始化工作。
构造代码块是在每次创建对象时都会执行的,在构造方法之前执行。它主要用于在多个构造方法中避免重复的代码逻辑,并且可以在对象创建之前对实例变量进行赋值。
总体而言,执行顺序为:
- 静态代码块(在类加载时执行,只执行一次)
- 构造代码块(在每次创建对象时执行,先于构造方法)
- 构造方法
需要注意的是,当有继承关系存在时,父类的静态代码块会在子类的静态代码块之前执行;而构造代码块和构造方法则以实际创建对象的顺序依次执行。
接下来通过一个案例学习静态代码块的使用。
public class myclass {
private static int staticVariable; // 静态变量
private int instanceVariable; // 实例变量
// 静态代码块
static {
staticVariable = 10;
System.out.println("静态代码块被执行");
}
// 构造代码块
{
instanceVariable = 20;
System.out.println("构造代码块被执行");
}
// 构造方法
public myclass() {
System.out.println("构造方法被执行");
}
public static void main(String[] args) {
myclass example1 = new myclass();
myclass example2 = new myclass();
}
}
运行结果:
静态代码块被执行
构造代码块被执行
构造方法被执行
构造代码块被执行
构造方法被执行
从输出结果可以看出,静态代码块在类第一次使用时被执行,只执行一次。构造代码块在每次创建对象时被执行,先于构造方法执行。