Java 封装

本文详细介绍了Java封装的概念,包括信息隐藏和类的属性、方法的封装,以及实现封装的步骤。此外,还深入解析了this关键字的用法,如this.属性名、this.方法名以及this( )调用构造方法。通过示例代码,展示了如何在类中使用this关键字以及封装的实践应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

达者为先  师者之意


1 封装的概念

  • 将东西包在一起,然后以新的完整的形式呈现出来
  • 将方法和字段包装到一个单元中,单元以类的形式实现
  • 信息隐藏,隐藏对象的实现细节,不让外部直接访问到
  • 将数据和方法包装进类,加上具体实现的隐藏(访问修饰符),共同被称作封装,其结果是一个同时带有特征和行为的数据类型

什么是封装类?
"定义类,定义其属性、方法的过程"成为封装类

封装将类的某些信息隐藏在类内部,不允许外部程序直接访问,只能通过该类提供的方法来实现对隐藏信息的操作和访问。例如:一台计算机内部极其复杂,有主板、CPU、硬盘和内存, 而一般用户不需要了解它的内部细节,不需要知道主板的型号、CPU 主频、硬盘和内存的大小,于是计算机制造商将用机箱把计算机封装起来,对外提供了一些接口,如鼠标、键盘和显示器等,这样当用户使用计算机就非常方便。

封装的特点:

  • 只能通过规定的方法访问数据。
  • 隐藏类的实例细节,方便修改和实现。

2 实现Java封装的步骤

实现封装的具体步骤如下:

  • 修改属性的可见性来限制对属性的访问,一般设为 private。
  • 为每个属性创建一对赋值(setter)方法和取值(getter)方法,一般设为 public,用于属性的读写。
  • 在赋值和取值方法中,加入属性控制语句(对属性值的合法性进行判断)

在这里插入图片描述

以下举例说明:

  1. 修改属性的可见性来限制对属性的访问(一般限制为private),例如:
public class Person {
    private String name;
    private int age;
}

这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。

  1. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:
public class Person{
    private String name;
    private int age;public int getAge(){
      return age;
    }public String getName(){
      return name;
    }public void setAge(int age){
      this.age = age;
    }public void setName(String name){
      this.name = name;
    }
}

采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。

实例
让我们来看一个java封装类的例子:
EncapTest.java 文件代码:

/* 文件名: EncapTest.java */
public class EncapTest{
 
   private String name;
   private String idNum;
   private int age;
 
   public int getAge(){
      return age;
   }
 
   public String getName(){
      return name;
   }
 
   public String getIdNum(){
      return idNum;
   }
 
   public void setAge( int newAge){
      age = newAge;
   }
 
   public void setName(String newName){
      name = newName;
   }
 
   public void setIdNum( String newId){
      idNum = newId;
   }
}

以上实例中public方法是外部类访问该类成员变量的入口。

通常情况下,这些方法被称为gettersetter方法。

因此,任何要访问类中私有成员变量的类都要通过这些gettersetter方法。

通过如下的例子说明EncapTest类的变量怎样被访问:

RunEncap.java 文件代码:

/* F文件名 : RunEncap.java */
public class RunEncap{
   public static void main(String args[]){
      EncapTest encap = new EncapTest();
      encap.setName("James");
      encap.setAge(20);
      encap.setIdNum("12343ms");
 
      System.out.print("Name : " + encap.getName()+ 
                             " Age : "+ encap.getAge());
    }
}
/*
以上代码编译运行结果如下:
Name : James Age : 20
*/

3 this关键字详解

this 关键字是 Java 常用的关键字,可用于任何实例方法内指向当前对象,也可指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用。

下面我们根据示例分别讲解 this 关键字的作用。

3.1 this.属性名

大部分时候,普通方法访问其他方法、成员变量时无须使用 this 前缀,但如果方法里有个局部变量和成员变量同名,但程序又需要在该方法里访问这个被覆盖的成员变量,则必须使用 this 前缀。

例 1
假设有一个教师类 Teacher 的定义如下:

public class Teacher {
    private String name;    // 教师名称
    private double salary;    // 工资
    private int age;    // 年龄
}

在上述代码中 namesalaryage 的作用域是 private,因此在类外部无法对它们的值进行设置。为了解决这个问题,可以为 Teacher 类添加一个构造方法,然后在构造方法中传递参数进行修改。代码如下:


// 创建构造方法,为上面的3个属性赋初始值
public Teacher(String name,double salary,int age) {
    this.name = name;    // 设置教师名称
    this.salary = salary;    // 设置教师工资
    this.age = age;    // 设置教师年龄
}

在 Teacher 类的构造方法中使用了 this 关键字对属性 namesalaryage 赋值,this 表示当前对象。this.name=name语句表示一个赋值语句,等号左边的 this.name 是指当前对象具有的变量 name,等号右边的 name 表示参数传递过来的数值。

创建一个 main() 方法对 Teacher 类进行测试,代码如下:

public static void main(String[] args) {
    Teacher teacher = new Teacher("王刚",5000.0,45);
    System.out.println("教师信息如下:");
    System.out.println("教师名称:"+teacher.name+"\n教师工资:"+teacher.salary+"\n教师年龄:"+teacher.age);
}
/*
运行该程序,输出的结果如下所示。
教师信息如下:
教师名称:王刚
教师工资:5000.0
教师年龄:45
*/

提示:当一个类的属性(成员变量)名与访问该属性的方法参数名相同时,则需要使用 this 关键字来访问类中的属性,以区分类的属性和方法中的参数。

3.2 this.方法名

this 关键字最大的作用就是让类中一个方法,访问该类里的另一个方法或实例变量。
例 2
假设定义了一个 Dog 类,这个 Dog 对象 run( ) 方法需要调用它的 jump( ) 方法,Dog 类的代码如下所示:

/**
 * 第一种定义Dog类方法
 **/
public class Dog {
    // 定义一个jump()方法
    public void jump() {
        System.out.println("正在执行jump方法");
    }
    // 定义一个run()方法,run()方法需要借助jump()方法
    public void run() {
        Dog d = new Dog();
        d.jump();
        System.out.println("正在执行 run 方法");
    }
}

使用这种方式来定义这个 Dog 类,确实可以实现在 run( ) 方法中调用 jump( ) 方法。下面再提供一个程序来创建 Dog 对象,并调用该对象的 run( ) 方法。


public class DogTest {
    public static void main(String[] args) {
        // 创建Dog对象
        Dog dog = new Dog();
        // 调用Dog对象的run()方法
        dog.run();
    }
}

在上面的程序中,一共产生了两个 Dog 对象,在 Dog 类run( ) 方法中,程序创建了一个 Dog 对象,并使用名为 d 的引用变量来指向该 Dog 对象。在 DogTest 的 main() 方法中,程序再次创建了一个 Dog 对象,并使用名为 dog 的引用变量来指向该 Dog 对象

下面我们思考两个问题。

  1. 在 run( ) 方法中调用 jump( ) 方法时是否一定需要一个 Dog 对象
    答案是肯定的,因为没有使用 static 修饰的成员变量和方法都必须使用对象来调用。

  2. 是否一定需要重新创建一个 Dog 对象
    不一定,因为当程序调用 run( ) 方法时,一定会提供一个 Dog 对象,这样就可以直接使用这个已经存在的 Dog 对象,而无须重新创建新的 Dog 对象了。因此需要在 run() 方法中获得调用该方法的对象,通过 this 关键字就可以满足这个要求。

this 可以代表任何对象,当 this 出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的只能是当前类的实例。只有当这个方法被调用时,它所代表的对象才被确定下来,谁在调用这个方法,this 就代表谁。

将前面的 Dog 类run( ) 方法改为如下形式会更加合适,run( ) 方法代码修改如下,其它代码不变。

/**
 * 第二种定义Dog类方法
 **/
// 定义一个run()方法,run()方法需要借助jump()方法
public void run() {
    // 使用this引用调用run()方法的对象
    this.jump();
    System.out.println("正在执行run方法");
}

从第一种 Dog 类定义来看,在 Dog 对象run( ) 方法内重新创建了一个新的 Dog 对象,并调用它的 jump( ) 方法,这意味着一个 Dog 对象run( ) 方法需要依赖于另一个 Dog 对象jump( ) 方法,这不符合逻辑。

第二种 Dog 类定义是当一个 Dog 对象调用 run( ) 方法时,run( ) 方法需要依赖它自己的 jump( ) 方法,与第一种定义类的方法相比,更符合实际情形。

在现实世界里,对象的一个方法依赖于另一个方法的情形很常见,例如,吃饭方法依赖于拿筷子方法,写程序方法依赖于敲键盘方法。这种依赖都是同一个对象两个方法之间的依赖。因此,Java 允许对象的一个成员直接调用另一个成员,可以省略this前缀。也就是说,将上面的 run( ) 方法改为如下形式也完全正确。

public void run() {
    jump();
    System.out.println("正在执行run方法");
}

大部分时候,一个方法访问该类中定义的其他方法、成员变量时加不加 this 前缀的效果是完全一样的。

注意:对于 static 修饰的方法而言,可以使用类来直接调用该方法,如果在 static 修饰的方法中使用 this 关键字,则这个关键字就无法指向合适的对象。所以,static 修饰的方法中不能使用 this 引用。并且 Java 语法规定,静态成员不能直接访问非静态成员。

省略 this 前缀只是一种假象,虽然程序员省略了调用 jump() 方法之前的 this,但实际上这个 this 依然是存在的。

3.3 this( )访问构造方法

this( ) 用来访问本类的构造方法(构造方法是类的一种特殊方法,方法名称和类名相同,没有返回值,括号中可以有参数,如果有参数就是调用指定的有参构造方法。

例 3
下面定义一个 Student 类,使用 this( ) 调用构造方法给 name 赋值,Student 类的代码如下所示:


public class Student {
    String name;
    // 无参构造方法(没有参数的构造方法)
    public Student() {
        this("张三");
    }
    // 有参构造方法
    public Student(String name) {
        this.name = name;
    }
    // 输出name和age
    public void print() {
        System.out.println("姓名:" + name);
    }
    public static void main(String[] args) {
        Student stu = new Student();
        stu.print();
    }
}
/*
输出结果为:
姓名:张三
*/

注意:

  • this( ) 不能在普通方法中使用,只能写在构造方法中。
  • 在构造方法中使用时,必须是第一条语句。

4 封装例子

下面以一个员工类的封装为例介绍封装过程。一个员工的主要属性有姓名、年龄、联系电话和家庭住址。假设员工类为 Employee,示例如下:

public class Employee {
    private String name; // 姓名
    private int age; // 年龄
    private String phone; // 联系电话
    private String address; // 家庭住址
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        // 对年龄进行限制
        if (age < 18 || age > 40) {
            System.out.println("年龄必须在18到40之间!");
            this.age = 20; // 默认年龄
        } else {
            this.age = age;
        }
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

如上述代码所示,使用 private 关键字修饰属性,这就意味着除了 Employee 类本身外,其他任何类都不可以访问这些属性。但是,可以通过这些属性的 setXxx() 方法来对其进行赋值,通过 getXxx() 方法来访问这些属性。

在 age 属性的 setAge() 方法中,首先对用户传递过来的参数 age 进行判断,如果 age 的值不在 18 到 40 之间,则将 Employee 类的 age 属性值设置为 20,否则为传递过来的参数值。

编写测试类 EmployeeTest,在该类的 main() 方法中调用 Employee 属性的 setXxx() 方法对其相应的属性进行赋值,并调用 getXxx() 方法访问属性,代码如下:

public class EmployeeTest {
    public static void main(String[] args) {
        Employee people = new Employee();
        people.setName("王丽丽");
        people.setAge(35);
        people.setPhone("13653835964");
        people.setAddress("河北省石家庄市");
        System.out.println("姓名:" + people.getName());
        System.out.println("年龄:" + people.getAge());
        System.out.println("电话:" + people.getPhone());
        System.out.println("家庭住址:" + people.getAddress());
    }
}
/*
运行该示例,输出结果如下:
姓名:王丽丽
年龄:35
电话:13653835964
家庭住址:河北省石家庄市
*/
码字不易  求个三连

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大红烧肉

赠人玫瑰,手留余香。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值