Java面向对象编程三大特征 - 封装

简介: Java面向对象编程三大特征 - 封装

封装是面向对象编程中的三大特征之一,在对封装性进行解释时我们有必要先了解一些面向对象的思想,以及相关的概念。当我们想要去描述一系列的关系时我们要用到的最基本结构就是类,其中存在着成员变量和方法,用于记录属性和表达行为,相关知识请进传送门: Java中的基本操作单元 - 类和对象

一、名词解读

为了解释封装的概念和作用,需要先来了解一下几个相关的概念,这有助于我们接下来的理解。

1. 权限修饰符

当我们在一个类中定义成员变量时,会指定一个变量的类型,除此之外,还会有修饰符的部分,在此给出定义成员变量的规范格式:

// 定义变量
[修饰符] 变量类型 变量名称;
[修饰符] 变量类型 变量名称 = 初始值;

修饰符起到的作用从字面就可以解释,起到一个修饰和限定的作用,可以使用在成员变量之前的修饰符可以是:publicprotectedprivate、final、static。

修饰符与修饰符之间的顺序没有强制要求,其中public、protected、private被称为权限修饰符,可以用来限定类的属性和方法的访问权限,指明在哪些包的哪些类中能够调用到这些属性或方法,是一种一定会存在的修饰符。需要注意的是,这三个单词不能同时出现,当这三个单词都不出现的时候会被认为是默认访问权限,所以权限修饰符一共有四种:private、默认、protected、public。

2. 权限对应关系表

  • private:私有权限,只能在定义的类中访问,在其他类中创建的实例均无法访问
  • 默认:同包可访问权限,在没有声明权限修饰符时为默认权限,允许在同包的其他类访问
  • protected:受保护权限,允许有继承关系的子类访问
  • public:公共权限,允许任何类访问

3. 属性访问

由于权限修饰符在封装特性中的作用只是实现封装性的一种途径,所以在这里只演示private与public的作用,权限修饰符的其他作用将在后续的文章中继续介绍。

src
└──edu
    └──sandtower
        └──bean
            │    Person.java
        └──test
            │    Test.java

以上为实体类与测试类所在的目录结构,Person实体类所在包:edu.sandtower.bean,Test测试类所在包:edu.sandtower.test,相应代码如下:

package edu.sandtower.bean;
public class Person{
    // 声明公开属性
    public String name;
    // 声明私有属性
    private double money;
}
package edu.sandtower.test;
import edu.sandtower.bean.Person;
public class Test{
    public static void main(String[] args){
        // 在test包中的Test类中创建Person实例
        Person person = new Person();
        person.name = "小张";// 编译通过,可以访问name属性
        person.money = 500.0;// 编译失败,无法访问money属性
    }
}

从上面的例子可以看出,虽然依然是使用Person自己的实例在进行属性的调用,但是我们是在另外一个包中的类发生的调用,所以是不能够访问到private修饰的属性的,在刚开始学习时一定要注意区分。

二、概念阐释

1. 封装有什么用

通过使用权限修饰符,我们可以限定类的成员的被访问权限,那为什么要这样做呢?在很多场景下,我们需要确保我们对属性值的操作均是有效操作,不能违背某些规则。

比如,我们定义了一个Person类,具有name和money两个属性,在买东西时需要扣掉相应的金额,原始写法如下:

public class Person{
    public String name;
    public double money;
}
public class Test{
    public static void main(String[] args){
        Person person = new Person();
        person.money = 500;// 初始金额500元
        System.out.println("购买一张桌子,花费200元");
        person.money -= 200;
        System.out.println("购买二手PSP,花费350元");
        person.money -= 350;
        System.out.println("目前余额为:" + person.money);// -50
    }
}

可以看到,经过代码操作以后可能会导致money的属性为负。看官甲:你自己不加判断赖代码?没错,这个问题我们可以增加判断代码来解决,由于这个操作是对money属性值的操作,我们将它封装成一个方法写在实体类中,于是有了改进之后的代码:

public class Person{
    public String name;
    public double money;
    // 定义一个方法,用于设置money属性的值
    public void setMoney(double money){
        if(money >= 0){
            this.money = money;
        }
    }
}
public class Test{
    public static void main(String[] args){
        Person person = new Person();
        person.money = 500;// 初始金额500元
        System.out.println("购买一张桌子,花费200元");
        person.setMoney(person.money - 200);
        System.out.println("购买二手PSP,花费350元");
        person.setMoney(person.money - 350);
        System.out.println("目前余额为:" + person.money);// 300
    }
}

经过上面的改进,我们可以确保money的值不为负数,同时可以看到,当在实体类中定义方法后,使用者需要修改属性值时直接调用方法就可以保证不出问题。但是由于属性值依然可以被直接访问,还不能保证万无一失,于是我们利用权限修饰符使得变量不能被直接访问,同时需要定义一个能够取得属性值的方法。

public class Person{
    public String name;
    // 声明money属性为private权限
    private double money;
    // 定义一个方法,用于设置money属性的值
    public void setMoney(double money){
        if(money >= 0){
            this.money = money;
        }
    }
    // 定义一个方法,用于获取money属性的值
    public double getMoney(){
        return this.money;
    }
}
public class Test{
    public static void main(String[] args){
        Person person = new Person();
        person.setMoney(500);// 初始金额500元,此时已经不能使用对象.属性的方法赋值
        System.out.println("购买一张桌子,花费200元");
        person.setMoney(person.getMoney() - 200);
        System.out.println("购买二手PSP,花费350元");
        person.setMoney(person.getMoney() - 350);
        System.out.println("目前余额为:" + person.getMoney());// 300
    }
}

通过以上的案例,我们可以看到进行封装有以下几个作用:

  • 防止类的属性被外部代码随意的修改和访问,保证数据的完备性
  • 将对属性的操作转换为方法,更加灵活和安全
  • 使用封装可以隐藏实现的细节:使用者只需要关心作用,不需要知道过程
  • 在类的定义结构中修改,提高了代码的可维护性,同时又可以不影响外部的使用
  • 通过封装方法可以有效减少耦合
  • 耦合:模块与模块之间,代码与代码之间的关联程度,对属性封装后,和调用相关的代码就会变得相对简单,可以降低耦合

2. 如何进行封装

在进行封装时都是出于对属性保护的考虑,可以按照以下两个步骤来进行:

  • 使用权限修饰符
  • 使用private作用在属性上,关闭直接访问的入口
  • 使用public作用在方法上,提供调用的入口
  • 定义与属性存取相关的方法

在属性关闭后,我们需要通过方法来获取属性的值以及对属性值进行修改。由于有了方法结构,我们就可以对存入的数据进行判断,对不符合逻辑的数据进行处理。

3. 常规封装方法

明白了封装的作用后,我们可以通过自定义方法的方式完成对属性的封装。封装方法和类中定义的其他方法在结构上没有任何的区别,同样都是普通的方法,区别主要在于体现在用途方面:

  • 普通方法主要表达该类所能产生的行为
  • 封装方法主要为属性的访问和使用提供了一个入口,作用相对单一

在进入到框架的学习之后,很多对实体类属性自动赋值的操作都是通过调用封装方法实现的,所以我们必须要知道常规封装方法的名称定义和类型设置规则。

对于属性来说我们只会进行两种操作:存和取。那么相应的封装方法应该有一对儿

  • get代表取用:既然是取值,那么就要把属性值进行返回,方法的返回值类型与属性类型相同
  • set代表存储:既然是存值,那么就要在参数列表中接收想要存入的值,类型与属性类型相同

对于命名方面只要遵从驼峰命名法就好,以get或set开头,大写属性名称的首字母,其余不变,看下面一个例子:

public class Person{
    // 使用private声明属性
    private String name;
    private double money;
    // 使用public声明方法,作为操作属性的入口
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setMoney(double money){
        // 如有需要,可以在方法中可以自定义其他逻辑
        this.money = money;
    }
    public double getMoney(){
        return this.money;
    }
}

由于常规封装方法定义的格式和名称都相对固定,所以一般的编译器都自带自动生成封装方法的功能,这样既方便又能降低出错率,大家一定要掌握。

  • Eclipse:

属性定义完成后,选择source菜单 -> Generate Getters and Setters…

点击Select All(选择所有属性) -> Generate

  • IDEA:

与Eclipse类似,在定义好类的私有属性后,使用快捷键:Alt + Insert

可以一次性选择多个属性 -> 点击OK

目录
相关文章
|
1月前
|
安全 Java 编译器
Java的封装详解
封装和多态是面向对象编程(OOP)的重要概念。封装通过私有属性和公共方法实现数据隐藏和保护,使类的内部细节对外部不可见;多态则通过方法重载和重写实现同一方法在不同对象上的不同表现形式,增强了代码的灵活性和可维护性。两者结合使用,可以使Java程序更加安全、灵活且易于维护。
|
14天前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
28天前
|
SQL Java 编译器
Java——类与对象(封装)
封装是面向对象编程中的概念,指将数据(属性)和相关操作(方法)组合成独立单元(类),使外部无法直接访问对象的内部状态,只能通过提供的方法进行交互,从而保护数据安全。例如,手机将各种组件封装起来,只暴露必要的接口供外部使用。实现封装时,使用`private`关键字修饰成员变量,并提供`get`和`set`方法进行访问和修改。此外,介绍了包的概念、导入包的方式及其注意事项,以及`static`关键字的使用,包括静态变量和方法的初始化与代码块的加载顺序。
26 10
Java——类与对象(封装)
|
2天前
|
SQL 安全 Java
JAVA代码审计SAST工具使用与漏洞特征
JAVA代码审计SAST工具使用与漏洞特征
11 2
|
16天前
|
安全 Java 数据安全/隐私保护
Java 封装怎么理解
封装是Java中的一种重要机制,它将对象的状态(数据)和行为(方法)打包在一起并控制外部访问权限,以保护数据不被随意修改。封装的主要目的包括数据保护、接口设计和增强模块性。通过使用`private`、`protected`及`public`等访问控制修饰符,结合getter和setter方法,可以有效隐藏对象内部实现细节。下面是一个简单的`BankAccount`类示例,展示了如何通过封装保护类的内部状态,确保数据安全和一致性,简化类的使用。理解封装有助于编写高质量代码和设计优秀程序架构。
|
16天前
|
Java 数据安全/隐私保护
Java 封装详解
在 Java 中,封装是面向对象编程的关键特性,通过将对象的状态(数据)和行为(方法)结合并利用访问控制保护数据,防止外部随意访问和修改。主要特点包括访问控制(如 `private` 和 `protected`)、数据隐藏及方法暴露(如 getter 和 setter)。封装的优点在于保护数据、隐藏实现细节、易于维护以及提高代码可读性。下面是一个简单的 `Person` 类封装示例,展示了如何通过 getter 和 setter 控制对类内部状态的访问,并进行合法性检查。总结而言,封装有助于构建清晰、易用且可维护的代码结构,是编写高质量 Java 程序的重要原则。
|
12天前
|
SQL 安全 Java
JAVA代码审计SAST工具使用与漏洞特征
JAVA代码审计SAST工具使用与漏洞特征
33 1
|
14天前
|
安全 Java 开发者
Java修饰符与封装:理解访问权限、行为控制与数据隐藏的重要性
Java中的修饰符和封装概念是构建健壯、易维护和扩展的Java应用程序的基石。通过合理利用访问权限修饰符和非访问修饰符,开发者能够设计出更加安全、灵活且高效的代码结构。封装不仅是面向对象编程的核心原则之一,也是提高软件项目质量和可维护性的关键策略。
13 1
|
13天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
34 2
|
2天前
|
Java 关系型数据库 MySQL
如何用java的虚拟线程连接数据库
本文介绍了如何使用Java虚拟线程连接数据库,包括设置JDK版本、创建虚拟线程的方法和使用虚拟线程连接MySQL数据库的示例代码。
16 6
如何用java的虚拟线程连接数据库