关于类与对象,内容较多,我们分为两篇进行讲解:
📚 Java-类与对象-上篇:————<传送门:Java-类与对象-上篇-CSDN博客>
📕 面向对象的概念
📕 类的定义格式
📕 类的使用
📕 this关键字
📕 构造方法
📚 Java-类与对象-下篇:————<就是本篇>
📕 封装(概念与访问限定符)
📕 static关键字
📕 代码块
📕 内部类
一、封装
① 封装的概念
要研究继承与多态,我们首先需要了解"封装",面向对象程序的三大特征为:封装,继承,多态。而封装面向对象中非常重要的一环,那么什么是封装呢?其实就是为了保护某种内在程序所创建的表象。
这样说可能比较抽象,封装的概念可以用以下比喻来解释:
假设你有一辆汽车,它有许多复杂的部件和属性,例如发动机、轮胎、刹车等等。如果所有的这些部件和属性都暴露在外部,别人可以直接操作它们,那么这辆汽车可能会被错误地使用或者破坏。
而为了保护这辆汽车,我们可以将其封装在一个保护壳中,只暴露一些必要的接口,例如启动引擎、加速、刹车和打开车门等等。这样,外部使用者就只能通过这些接口来操作汽车,而无法直接访问和修改汽车的内部部件。
类似地,Java中的封装就是将一个类的数据和方法封装在一起,只暴露一些必要的接口。
📌 封装的作用:
📕 可以隐藏内部实现的复杂性
📕 防止外部直接访问和修改类的内部数据
📕 我们可以控制对数据和方法的访问,并提供一些公开的接口来与外部进行交互
📕 提高代码的安全性、可维护性和实用性
② 访问限定符
既然要对某些东西进行保护,就需要界定一个可访问的范围,而"访问限定符"就具备了这种功能:
No | 范围 | private | default | protected | public |
1 | 同一包中 的同一类 | 可以 | 可以 | 可以 | 可以 |
2 | 同一包中 的不同类 | 可以 | 可以 | 可以 | |
3 | 不同包中 的子类 | 可以 | 可以 | ||
4 | 不同包中 的非子类 | 可以 |
📚 让我们写段代码逐个举例进行说明:
📕 首先我们在本包本类中创建一个Test3:
📕 然后我们在本包非本类中创建一个Test4:
📕 然后我们在非本包子类中创建一个Test5:
📕 然后我们在非本包非子类中创建一个Test6:
最后我们回到Main中进行测试:
📚 注意事项:
📕 public修饰的成员可以被任何类访问
📕 如果没有明确指定访问限定符,即不加任何修饰符,成员的访问权限为默认(default)
📕 private修饰的成员只能被定义它的类访问
📕 最常用的是:public 和 private
二、static关键字
在讲static这个关键字之前,让我们回想一下之前讲到的类与对象:
我们可以通过定义学生类来实例化几个学生对象,并为他们赋予独有的属性数据:
但如果此时我们想将这几个学生都放入一个班级中呢,难道我们还要对每一名学生都加上"班级"并赋值嘛?那太麻烦了,并且有很多相同的数据发生了重复。
而此时我们就能够使用,static,它用于修饰成员变量,被称为静态成员变量,其最大的特征就是:不属于某个具体的对象,而是所有对象共享的,也就是说属于类。
① 静态成员变量
📌 静态成员变量具有以下特点:
📕 不论创建多少个类的实例,静态成员变量都只会分配一次内存。
📕 静态成员变量在程序运行期间始终存在,直到程序结束
📕 可以被所有的对象实例共享,一次修改将会影响到所有的对象。
📕 可以通过类名直接访问静态成员变量,也可以通过对象实例访问。
既然稍微了解了static关键字,那么让我们回到最初的问题:
将几个学生都放入一个班级中,需要进行怎样的操作可以既节省空间,又节省代码呢?
没错,我们在学生类里加一个static班级不就好了嘛~:
这样当我们再次运行代码时:
📌 这样做的好处就是:
📕 能够有效的节省内存空间
📕 不需要使用过多冗余的代码来依次定义班级
而静态成员变量的调用其实与非静态成员变量是稍微有所差别的:
虽然通过成员进行访问和通过类进行访问,都能够成功的使用Class,但是其实我们并不推荐使用成员访问,因为当Class成为静态成员变量时,就代表它实质上是属于类的,而非属于类中某个成员,虽使用某个成员可以调用Class,但理论上这并不合理。
② 静态成员方法
📌 静态成员方法具有以下特点:
📕 不依赖于类的实例,可以直接通过类名调用,也可以通过对象实例调用。
📕 不能访问非静态成员变量和非静态成员方法,因为非静态成员依赖于实例的创建。
📕 可以访问静态成员变量和静态成员方法,因为它们与类关联,不依赖于实例。
📕 静态方法在类加载时就存在于内存中,并且一直存在直到程序结束。
我们可以看这三个方法,先来看第一个:
同样的,通过成员进行访问和通过类进行访问Print1,都能够成功的使用,我们也不推荐使用成员访问,因为当Print1成为静态成员方法时,就代表它实质上是属于类的,而非属于类中某个成员,虽使用某个成员可以调用Print1,但理论上这并不合理。
接下来我们看第二个:
我们使用非静态成员方法时,是可以访问静态成员变量的,但是接下来我们要看的方法三就与此恰恰相反了:
我们可以看到,成员变量都发生了报错,而唯独静态成员变量Class没有,这是因为静态成员方法不能访问非静态成员变量和非静态成员方法,因为非静态成员依赖于实例的创建。
三、代码块
代码块是一段被大括号{}括起来的代码段。在Java中,有以下几种类型的代码块:
① 普通代码块
通常用于限定变量的生命周期或者在局部作用域中定义临时变量。
普通代码块可以在任何合法的位置使用,包括方法中、类中、循环中等等。当代码块执行完毕后,其中定义的变量将被销毁。
② 构造代码块
构造代码块是在创建对象时执行的一段代码块,用于对对象进行初始化操作。
构造代码块是在所有构造方法执行之前执行的,而且每次创建对象时都会执行一次。
📚 我们可以尝试使用在刚刚的学生类中:
然后我们回到Main中:
我们可以看到,构造代码块的运行优先等级要高于构造方法,并且构造代码块中将name = "无名"的操作也在构造方法执行也再次证明了这一点。
而构造代码块的作用主要可以用于为某些成员变量赋初值。
③ 静态代码块
这是三种代码块中最为重要的一种代码块,它的实用性远远大于前两种代码块。
静态代码块用于对类进行初始化操作。
📌 静态代码块有以下特点:
📕 在类加载时执行的一段代码块
📕 静态代码块只会执行一次
📕 在第一次使用该类时被调用,并且在静态变量初始化之前执行。
📕 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行
大家还记得我们之前学习过的"学生管理系统"吗?当时我们并没有学习过代码块,所以我们在使用"学生管理系统"时就需要先创建一个能够使用的用户,然后才进行登录,使用系统。
而静态代码块就能够在此处大显神威~我们可以使用静态代码块来对一个账户数据进行初始化:
如此便在程序加载时便初始化了一个初始用户:
📌 而至于为什么静态代码块是最实用的代码块,这是因为:
📕 可以控制的只执行一次
📕 可以访问静态成员
四、内部类
内部类是一个定义在另一个类内部的类。它可以访问外部类的成员变量和方法,并且可以被外部类或其他类实例化和使用。
public class OuterClass {
...
public class InnerClass {
...
}
}
当一个对象的内部,有一部分数据还需要多一个完整结构进行描述,那么就可以使用内部类。
内部类可以分为以下几种类型:
① 实例内部类
实例内部类是一种定义在另一个类的内部的类,并且与外部类的实例相关联的内部类。
在内部类使用外部类成员变量并未报错~
📌 实例内部类的特点:
📕 可以访问外部类的实例变量和方法
📕 可以被外部类或其他类实例化和使用
📕 实例内部类的非静态方法中包含了一个指向外部类对象的引用
② 静态内部类
静态内部类是在另一个类的内部定义的静态类。
让我们对上一个示例代码稍加修改:
我们会发现,将实例内部类变成静态内部类后,外部类中的num便无法使用了,这是因为:
📕 在静态内部类中只能访问外部类中的静态成员
那么这篇关于(类与对象-下篇)的知识,就暂时为大家分享到这里啦,作者能力有限,如果有哪里说的不够清楚或者不够简洁,还请大家在评论区多多指出,那么我们下期再见啦~