【Java SE】封装的详解(上)

简介: 如果把封装的概念放在语言中,那就是:将数据和操作数据的方法进行结合,隐藏对象的属性,和实现细节,仅仅对外公开接口来和对象进行交互。

1、封装

1.1 什么是封装?

不知道小伙伴对冰箱有没有观察过,市面上大多数的冰箱他们的嵌入式主板,芯片,制冷装置,以及内部电线,应该都没有暴露在我们的视野中,但是他们给我们提供了一些对外可见的接口,比如,插电头,你插上就有电了, 再比如给我们提供了冰箱门上的按钮,你需要操作这几个按钮或者显示屏就能让冰箱帮你干活,那他的地层一些制冷的装置,以及一些功能的机制实现我们都不了解,也从表面上看不到,但是我们却可以通过他们提供的接口去使用,简而言之这就是封装!

如果把封装的概念放在语言中,那就是:将数据和操作数据的方法进行结合,隐藏对象的属性,和实现细节,仅仅对外公开接口来和对象进行交互。

2.2 访问权限

记得之前,写方法写任何东西,我都是写的 public 为什么呢?也浅提了一个,这个是访问权限限定符,既然是封装,就需要限制外部对类或类的属性设置访问权限,在Java中,主要是通过类和访问权限来实现封装, 类可以将数据及实现数据的方法结合在一起,而访问权限用来控制方法或字段能否直接在类外使用,在Java中,一共提供了四种访问限定符:


private:只允许在同一个包中和同一个类中访问,其他地方均不能访问

默认:只允许在同一个包中任意位置访问,不同的包,其他地方均不能访问(什么都不写就是默认)

portected: 主要用在继承当中,我们下期讲解

public:任意地方都能访问

注意:修饰符除了限定类中的成员,也能限制类的可见性,本期没有讲到的范围,后续会讲到

2.3 private 简单使用

class Student {
    //成员变量【属性】
    private String name; //姓名
    private int age; //年龄
    private float score; //分数
    //构造方法
    public Student() {}
    public Student(String name, int age, float score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    //成员方法【行为】
    public void studentScores() {
        System.out.println(this.name + "考了" + this.score + "分");
    }
}
public class Test {
    public static void main(String[] args) {
        Student student = new Student("张三", 20, 59.9f);
        //这里我将成员变量的访问限定符设置为了 private 代表只能在同一个类中访问
        //student.name = "张三" //error -> 不同类中不能访问
        //student.age = 20; //error -> 不同类中不能访问
        //System.out.println(student.name); //error -> 不同类中不能访问
        student.studentScores(); //yes -> 因为这个类成员方法访问限定符是 public
    }
}

这里我们可以简单来看一下 Student 这个类(同一份Java文件,只能有一个被public修饰的类),首先我们把成员变量都设置成的 private 属性,也就代表着,这些成员变量只能在 Student 这个类的内部访问,所以我们下边 Test 类就不能直接通过对象访问他们了,但是可以通过对象访问 studentScores 成员方法,因为他是被 public 修饰的!一般我们会将成员变量设置为 private,成员方法设置成 public。

后面我们在讲完包之后,会介绍默认修饰符,也就是什么都不加的情况。

2、封装之包的概念

2.1 什么是包?

女孩子们喜欢买各种包包,主要是背着好看,但是计算机中包可不是这样的,我们可以把文件夹当成一个包,文件夹是用来干嘛的?主要是为了更方便的管理,所以面向对象的体系中,提出了一个软件包的概念,也就是为了更好的管理类,把多个类收集到一起成为一组,成为软件包。

在Java中,也引入了包,包是对类,结构等封装机制的体现,可以更好组织类和接口等,如果一个包中的类,不想被其他包使用,就修改包中类的权限限定符,同时如果你有相同的类名,你只需要让他们俩处在不同的包里即可!

2.2 如何导入包中的类?

记得之前我们了解过输入方法,当我们创建了一个输入对象,编译器则会在最顶部给我们添加一行 import java.util.Scanner; 那如果我们没有这个 import 语句我们要如何用 Scanner 类中的方法呢?

2.2.1 使用完整类名

这里我们用一个我们之前没见过的类,我现在要获取一个时间戳,已知 java.util 包中里面 Date类里面有一个 getTime(); 方法可以获取时间戳,假设我们现在不知道 import 语句,也没有添加 import 语句,该如何做到获取时间戳呢?

public class Test {
    public static void main(String[] args) {
        java.util.Date data = new java.util.Date();
        System.out.println(data.getTime()); //得到一个毫秒级时间戳并打印
    }
}

我们是不是应该这么写,首先我们需要用 Date 类来实例化一个对象,而这个类在 java.util 这个包中,所以我们要通过这个包找到这个类,进行实例化,实例化哪个类呢?还是要通过这个包,里面的类来实例化,最后通过对象来访问类中对应的成员方法进行获取时间戳,并打印!

2.2.2 使用 import 导入包

这样写是不是好麻烦,有那么多重复的地方,所以这里就可以使用 import 语句来导入包,所以当我们需要使用 java.util.Date 类里面方法的时候,我们只需要在类的前面 imprt java.util.Date,导入了这个包即可:

import java.util.Date;
public class Test {
    public static void main(String[] args) {
        Date data = new Date();
        System.out.println(data.getTime()); //得到一个毫秒级时间戳并打印
    }
}

那如果你还要使用 java.util 里面的其他类呢?其实有一个方法可以不需要一个个导入,直接写成: import java.util.* 只要是 util 里面的公开的类你都可以像上面一样使用,但是我们更推荐显示式的指定要导入的类名,否则容易出现冲突的情况:

2.2.3 使用* 发现冲突的情况

import java.util.*
import java.sql.*
public class Test {
    public static void main(String[] args) {
        Date data = new Date();
        System.out.println(data.getTime()); //得到一个毫秒级时间戳并打印
    }
}

如上代码会报错,也就是出现冲突,因为 java.sql 和 java.util 这两个包中都有 Date 类,编译器也无法识别你需要使用哪个类,所以在这种情况下,我们就需要使用完整的类名:

java.util.Date date = new java.util.Date();

2.2.4 使用 import static 导入静态的方法和字段

至于静态的方法和字段这个我们后面会讲解,这里主要先看下怎么使用,等学了后面内容你就明白了:

import static java.lang.Math.*;
public class Test {
    public static void main(String[] args) {
        double x = 30;
        double y = 40;
        // 静态导入的方式写起来更方便一些.
        // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        double result = sqrt(pow(x, 2) + pow(y, 2));
        System.out.println(result);
    }
}

这样就可以直接使用方法名了,不需要加类名,但这里必须是静态的方法或者成员才可以,后面会讲到,我们这样用的情况不是很多。

注意: import 跟 C/C++ 的 include 是不一样的,他们差别很大,#include在编译会展开头文件,是来引用其他文件内容,而Java不需要,import只是为了写代码更方便,更类似于C++ 的 namespace 和 using

2.3 自定义包

自定义包也就是我们用户自己建一个包,在IEDA下可以通过右键 src->New->Package 文件的最上方需要加上 package 包名; 来指定该代码在哪个保重,但IDEA编译器会自动帮我们加上,如果你创建的包名叫做 com.lqg.demo,那么则会存在一个对应的路径 com/lqg/demo 来存储代码,要是类中没有 package语句,则表明该类被放在一个默认包中,IDEA对应是 src

有了上面的一些包的学习,相信你们以及能理解 默认 访问限定符的作用了,下来你可以自己建一个包,然后写一个类,类的修饰符是默认,再去另一个包中就会发现无法使用这个类了,这里就教给大家下去自行学习。

这里介绍以下 java.util 包,他是java提供的工具程序包,(集合类等),在后续的学习中我们会接触到更多,还有其他的包,随着我们学习的深入慢慢了解。

3、static修饰符

3.1 为什么需要 static 修饰成员?

这里我们来回顾下之前写过的 Student 类,假设我们有三个学生,对应着三个对象,假设这三个学生为张三,李四,王五, 而他们又是同班同学,那我现在需要给类中加一个教室信息,是直接添加一个教室成员变量吗?在之前的类中,每个对象都会包含一份成员变量,称之为实例变量,但是这次我们要添加的教室属性,并不属于某个对象啊,他是属于所有学生对象共享的!所以在Java中,static 的出现,就是说,被 static 修饰的成员,称之为静态成员,也可也成为类成员,不属于某个具体的对象,所有对象都能共享!

3.2 static 修饰成员变量

这里我们就来给学生类添加一个 static 成员变量,也就是静态成员变量 -> classRoom;

public class Student {
    //这里表示 name age 成员变量只能在 Student 类中访问
    private String name; 
    private int age;
    public static String classRoom = "八年级二班"; //静态成员变量
    public static void main(String[] args) {
        Student stu1 = new Student();
        Student stu2 = new Student();
        //静态的不依赖于对象!
        System.out.println(Student.classRoom); //可以直接通过类名访问
        System.out.println(stu1.classRoom); //也可也通过对象访问,但不推荐
        System.out.println(stu2.classRoom); //也可也通过对象访问,但不推荐
    }
}

注意:

static 修饰的成员变量,不属于某个具体的对象,不存储在某个具体对象的空间中,静态成员变量存储在方法区中,生命周期伴随类的一生,即随类的加载而创建,类的销毁而销毁,他既可以通过类名访问,也可也通过对象访问,但更推荐类名访问方式!

相关文章
|
6月前
|
Java 数据库连接 数据库
Java 组件详细使用方法与封装实战指南
本指南详解Java核心组件使用与封装技巧,涵盖跨平台开发、面向对象编程、多线程、数据库操作等关键内容,并提供工具类、连接池、异常及响应结果的封装方法。结合Spring框架、MyBatis、Spring Boot等主流技术,助你掌握高质量Java组件设计与开发实践。
215 2
|
3月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
466 1
|
6月前
|
设计模式 算法 Java
Java SE 与 Java EE 组件封装使用方法及实践指南
本指南详细介绍了Java SE与Java EE的核心技术使用方法及组件封装策略。涵盖集合框架、文件操作、Servlet、JPA、EJB和RESTful API的使用示例,提供通用工具类与基础组件封装建议,如集合工具类、文件工具类、基础Servlet、实体基类和服务基类等。同时,通过分层架构集成示例展示Servlet、EJB和JPA的协同工作,并总结组件封装的最佳实践,包括单一职责原则、接口抽象、依赖注入、事务管理和异常处理等。适合希望提升代码可维护性和扩展性的开发者参考。
212 0
|
Oracle Java 关系型数据库
Java(TM) Platform SE binary 已停止工作”的解决方法
Java(TM) Platform SE binary 已停止工作”的解决方法
1581 141
|
10月前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
10月前
|
安全 网络协议 Java
Java网络编程封装
Java网络编程封装原理旨在隐藏底层通信细节,提供简洁、安全的高层接口。通过简化开发、提高安全性和增强可维护性,封装使开发者能更高效地进行网络应用开发。常见的封装层次包括套接字层(如Socket和ServerSocket类),以及更高层次的HTTP请求封装(如RestTemplate)。示例代码展示了如何使用RestTemplate简化HTTP请求的发送与处理,确保代码清晰易维护。
|
9月前
|
人工智能 JSON Java
列表结构与树结构转换分析与工具类封装(java版)
本文介绍了将线性列表转换为树形结构的实现方法及工具类封装。核心思路是先获取所有根节点,将其余节点作为子节点,通过递归构建每个根节点的子节点。关键在于节点需包含 `id`、`parentId` 和 `children` 三个属性。文中提供了两种封装方式:一是基于基类 `BaseTree` 的通用工具类,二是使用函数式接口实现更灵活的方式。推荐使用后者,因其避免了继承限制,更具扩展性。代码示例中使用了 Jackson 库进行 JSON 格式化输出,便于结果展示。最后总结指出,理解原理是进一步优化和封装的基础。
303 0
|
11月前
|
Java
Java 面向对象编程的三大法宝:封装、继承与多态
本文介绍了Java面向对象编程中的三大核心概念:封装、继承和多态。
579 15