文章目录
上篇我们了解了什么是面向对象以及this引用,本篇将继续介绍类和对象中剩余的部分,从这里开始难度也逐渐上升啦,但我相信本篇文章能让你很轻松地搞定它~(小小臭美一下)👊
5. 对象的构造及初始化
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
5.1 如何初始化对象
在定义成员变量的时候直接赋值,这就叫就地初始化。
通过前面知识点的学习知道,在java方法内部定义一个局部变量时,必须要初始化,否则会编译失败。
要让上述代码通过编译,非常简单,只需在正式使用a之前,给a设置一个初始值即可。
如果是对象,即使不初始化,正式使用时也不会报错,因为其会自动设置为对应的0值(上篇中介绍过各类型变量对应的零值)。
(这里回顾一下上篇中写过的代码)
需要调用之前写的setDate方法(具体看上篇中的代码)才可以将具体的日期设置到对象中。通过上述例子发现两个问题:
1、每次对象创建好后调用setDate方法设置具体日期,比较麻烦,那对象该如何初始化?
2、局部变量必须要初始化才能使用,为什么字段(成员变量)声明之后没有给值依然可以使用?
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
5.2 构造方法(重要)
5.2.1概念
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
注意:即使自己构造了一个不带参数的构造方法,编译器也不会再默认帮你生成一个构造方法。如果自己构造了一个带参数的构造方法,则在调用构造方法(即创建对象)时也要传对应的参数,否则会报错。
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
5.2.1 构造方法的特性
- 名字必须与类名相同2
- 没有返回值类型,设置为void也不行
- 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
- 构造方法可以重载(用户根据自己的需求提供不同参数)
上述两个构造方法:名字相同,参数列表不同,因此构成了方法重载
- 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
注意:一旦用户定义,编译器则不再生成。
IDEA中生成构造方法的快捷键:可以自己选择生成几个参数(按住shift再用鼠标多选)
- 构造方法中,可以通过this调用其他构造方法来简化代码(只能在构造方法中使用)
运行结果:
注意: this(…)必须是构造方法中第一条语句(注释不算)
通过this调用构造方法不能形成环(即不能让this调用的构造方法形成一个圈,从而无休止的调用)
形成环的例子:
总结:
- 构造方法是没有返回值的方法,方法名和类名是一样的
- 构造方法不止一个,可以有多个,多个构造方法之间构成了重载
- 当我们写了一个类之后,没有写构造方法的时候,编译器会帮我们默认生成一个不带参数的构造方法
- 当我们写了任何一个构造方法之后,编译器不再为我们提供不带参的构造方法
- 一个类至少会有1个构造方法,即使你自己没有写
- 构造方法本质就是来实例化对象的时候调用 实例化对象时:(1) 分配内存 (2) 调用合适的构造方法
- this可以用来调用本类中其他的构造方法【只能在构造方法当中使用】,this(…)必须放到构造方法的第一行,所以在当前构造方法当中只能调用一个this(…)
- this的三种用法: a. this . data 访问属性 b. this . func() 访问方法 c. this() 调用本类中其他的构造方法
- this不能形成环
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
5.3 默认初始化
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
- 检测对象对应的类是否加载了,如果没有加载则加载
- 为对象分配内存空间
- 处理并发安全问题 比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突
- 初始化所分配的空间 即:对象空间被申请好之后,对象中包含的成员已经设置好了初始化,比如:
5. 设置对象头信息(关于对象内存模型后面会介绍)
6. 调用构造方法,给对象中各个成员赋值
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
5.4 就地初始化
在声明成员变量时,就直接给出了初始值
注意:就地初始化时,代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中。
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
5.5 打印成员变量的值
我们每次都要自己手动写一个打印的方法,然后来打印变量,这样很麻烦。
这里涉及到了重写,因为还没有学到重写,所以只需要简单了解下,知道能在IDEA中用快捷键自动生成打印的方法就可以了。
当不生成toString时,直接打印cat1打印出来的是对象的地址,写了toString后打印出来的是成员变量的内容。
注意:toString中的字符串内容和变量是可以自己修改的,但是方法名部分不能修改,否则会报错。
快捷键生成toString
生成toString方法后,只要直接打印对象的引用,就可以打印出成员变量的内容了。
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
6. 封装
6.1 封装的概念
面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节。
比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行 交互
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
6.2 访问限定符
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:
比如:
public:可以理解为一个人的外貌特征,谁都可以看得到
default(什么都不写,不是写一个default): 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
private:只有自己知道,其他人都不知道
即
- public:在任何地方都能使用
- default(默认,不写修饰限定符):只能在当前包中使用(下面就会介绍包的概念)
- private:只能在当前类中使用
【说明】
- protected主要是用在继承中,继承部分详细介绍
- default权限指:什么都不写时的默认权限
- 访问权限除了可以限定类中成员的可见性,也可以控制类的可见性
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
6.3 包
6.3.1 包的概念
在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件下,也可以对某个文件夹下的音乐进行更详细的分类。
在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
6.3.2 导入包中的类
Java中已经提供了很多现成的类供我们使用,例如Date类:可以使用 java.util.Date 导入java.util这个包中的Date类。
但是这种写法比较麻烦一点,可以使用import语句导入包
如果需要使用 java.util 中的其他类,可以使用 import.java.util.* ,这时就可以使用这个包中的所有类(使用哪个类时就会导入哪个类)(.*不能省略)
但是我们更建议显式的指定要导入的类名,否则还是容易出现冲突的情况。
在这种情况下需要使用完整的类名
可以使用 import static 导入包中的静态的方法和字段。(不推荐使用)
注意事项:
import和C++的 #include 差别很大,C++必须 #include来引入其他文件内容,但是Java不需要,import 只是为了写代码的时候更方便,import 更类似于 C++ 的 namespace 和using。
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
6.3.3 自定义包
基本规则
- 在文件的最上方加上一个 package 语句指定该代码在哪个包中.
- 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ).
- 包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码.
- 如果一个类没有 package 语句, 则该类被放到一个默认包中.
操作步骤
- 在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包
- 在弹出的对话框中输入包名, 例如 com.bit.demo1
- 在包中创建类, 右键包名 -> 新建 -> 类, 然后输入类名即可
- 此时可以看到我们的磁盘上的目录结构已经被 IDEA 自动创建出来了
- 同时我们也看到了, 在新创建的 Test.java 文件的最上方, 就出现了一个 package 语句
创建一个包其实就是创建文件夹,只是Java给了一个高大上的名字而已。
之前所说的不加修饰限定符时,对应的就是包权限,也就是只能在当前包中访问,这个包就是上文中介绍的包。
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
6.3.4 常见的包
- java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
- java.lang.reflect:java 反射编程包;
- java.net:进行网络编程开发包。
- java.sql:进行数据库开发的支持包。
- java.util:是java提供的工具程序包。(集合类等) 非常重要
- java.io:I/O编程开发包
🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇
总结:
本篇介绍了对象的初始化方式及构造方法,还介绍了封装以及引出了包的概念,补充了this的三种用法。如果对于概念还感觉很模糊,后面的篇章中会有更详细的介绍,当把类和对象都学完后我相信你就会有一种醍醐灌顶、茅塞顿开的感觉,不要纠结于这些变量在内存中到底存储在哪,也不要纠结方法是怎么创建的,这些都是JVM去实现的,在后面学习JVM中这些都会详细学习。
前两篇其实并不算很难,接下来一篇会介绍static和代码块,等你弄明白了static后就会知道为什么写主函数时要写public static void,也会明白为什么平常写方法时都会默认写上static,下篇会非常精彩,同时难度也会有所增长,如果你想详细了解一定要关注我哟~~!!💪💪
版权归原作者 夏.冬 所有, 如有侵权,请联系我们删除。