前言
我们之前学的都是面向过程,面向过程研究的是对单个对象的一种方法实现过程,比如求一个数的阶乘,强调的是怎么实现这个方法的过程,但对我们以后来说,如果想要应用到更广的层面,不能只是学习一个方法的过程,而是通过用对象的方法与其他对象建立联系来实现一个项目,那么怎么让对象与对象建立联系呢?我们就需要学习面向对象的相关知识。
1. 面向对象的初步认知
1.1 什么是面向对象
Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。
1.2 面向对象与面向过程
1.传统的洗碗过程
传统的方式:注重的是洗碗的过程,少了一个环节可能都不行,按照该种方式来写代码,将来扩展或者维护起来会比较麻烦。
2. 现代洗碗过程
总共四个对象:人 碗 洗洁精 洗碗机
整个过程就人打开洗碗机,把碗放到洗碗机,放洗洁精,关上洗碗机,洗碗机自己把碗洗完然后烘干。
整个过程就人,碗,洗洁精,洗碗机这四个对象相互完成,不需要管洗碗机是怎么把碗洗干净的,怎么烘干的。
以面向对象方式来进行处理,就不关注洗碗的过程,具体洗碗机是怎么来洗碗,如何来烘干的,用户不用去关
心,只需要将碗放进洗碗机,倒入洗洁精,启动开关即可,通过对象之间的交互来完成的。
注意:面向过程和面相对象并不是一门语言,而是解决问题的方法,没有那个好坏之分,都有其专门的应用场景。
2. 类定义和使用
2.1 简单认识类“
就我而言,类是指描述一个物品的大致摸样,是一个比较抽象的东西,类是不实的,也可以说是一个抽象的概念。
百度百科:java类就是具备某些共同特征的实体的集合,他是一种抽象的数据类型,它是对所具有相同特征的抽象。在面向对象的程序设计语言中,类是对一类“事物”的属性与行为的抽象。
那么在java中怎么去定义一个类?
2.2 类的定义格式
在java中定义类时需要用到class关键字,具体语法如下:
class Dog{//成员变量 属性 字段public String name;public int age;public String colour;//成员方法public void eat() {System.out.println("正在吃..........");}public void barks() {System.out.println(name + ": 旺旺旺~~~");}}
class为定义类的关键字,Dog为类的名字,{}中为类的主体。
类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法。
注意事项:
类名注意采用大驼峰定义
成员前写法统一为public,后面会详细解释
此处写的方法不带 static 关键字. 后面会详细解释
3. 类的实例化
3.1 什么是实例化
定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:PetDog类和Student类。它们都是类(一种新定义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。
用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。
用代码实现在狗类中实例化一个狗的对象:
class Dog {//成员变量 属性字段String name;int age;String colour;//成员方法public void eat() {System.out.println(name+"正在吃............");}public void barks() {System.out.println(name+"正在汪汪汪.........");}public void wag() {System.out.println(name+"正在摇尾巴.........");}}public class Test {public static void main(String[] args) {Dog dog = new Dog();dog.name = "旺财";dog.age = 2;dog.colour = "黑色";dog.wag();dog.eat();dog.barks();}}
在main方法中创建一个dog对象,通过dog.成员方法去访问Dog类中的成员方法,运行出来的结果:
类中的成员变量是存储子在堆的实例化空间,每一个对象都有一个私有的实例化变量空间。当对象被创建时,它的实例化变量就会被初始化,并会储存该对象的成员变量值。
成员方法时存储在方法区的。
这是定义了两个类,一个Dog类,一个Test类,我在Test类中实例化了一个Dog类的对象dog,并且通过dog.成员方法以及dog.成员变量都能访问到Dog类中的成员变量和成员方法。
在同一个类中,如果我不实例化一个对象,我用类名Test.成员变量或成员方法都会报语法错误,我在这个类中实例化一个test对象之后,再用test.成员变量或者成员方法 这个时候是可以去访问Test类中成员变量和成员方法。
总结:不管是多个类还是一个类,想要去访问类中的成员变量或者成员方法,都需要去实列化一个对象,然后用对象+点号去访问成员变量和成员方法。
注意事项
new 关键字用于创建一个对象的实例.
使用 . 来访问对象中的属性和方法.
同一个类可以创建多个实例.
3.2 类和对象的说明
- 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
- 类是一种自定义的类型,可以用来定义变量.
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东
西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空
间
4. this引用
4.1 为什么要有this引用
先看一个日期类的例子:
class Date {public int year;public int month;public int day;public void setDay(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}public void printDate() {System.out.println(year + "/" + month + "/" + day);}}public class Test {public static void main(String[] args) {Date date1 = new Date();Date date2 = new Date();Date date3 = new Date();date1.setDay(2021,10,10);date2.setDay(2022,11,11);date3.setDay(2023,12,12);date1.printDate();date2.printDate();date3.printDate();}}
以上代码定义了一个日期类,然后main方法中创建了三个对象,并通过Date类中的成员方法对对象进行设置和打印,代码整体逻辑非常简单,没有任何问题。
但是细思之下有以下两个疑问:
- 形参名不小心与成员变量名相同:
public void setDay(int year, int month, int day){year = year;month = month;day = day;}
那函数体中到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量?成员变量参数?估计
自己都搞不清楚了。
在调试的情况下可以看出访问这次方法并没有将值赋给类中的成员变量,而是赋给了该方法中的局部变量。
这是运行出来的结果:
修改一下这个代码:
public void setDay(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}
加上this后的再看调试下的现象:
成功将值赋给了类中的成员变量。
我们再看看这个this的地址和对象的地址:
两个地址是相同的,说明this在这的作用就是代表当前对象的引用。
- 三个对象都在调用setDate和printDate函数,但是这两个函数中没有任何有关对象的说明,setDate和
printDate函数如何知道打印的是那个对象的数据呢?
public static void main(String[] args) {Date date1 = new Date();Date date2 = new Date();Date date3 = new Date();date1.setDay(2021,10,10);date2.setDay(2022,11,11);date3.setDay(2023,12,12);date1.printDate();date2.printDate();date3.printDate();}
通过上面几组图片可以来得到一个小细节,在你实例化了多个对象的时候,还有在成员有参方法中形参和成员变量相同时,用this关键字,这样计算机就知道哪一个对象在调用哪一个方法。
4.2 什么是this引用
this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
4.3 this引用的特性
- this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
- this只能在”成员方法”中使用
- 在”成员方法”中,this只能引用当前对象,不能再引用其他对象
- this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收
this关键字的用法:
1.this.成员变量
2.this.成员方法
3.this() (这个在后面讲)
5. 对象的构造及初始化
5.1 如何初始化对象
通过前面知识点的学习知道,在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败.
public static void main(String[] args) {int a;System.out.println(a);}// Error:(26, 28) java: 可能尚未初始化变量a
要让上述代码通过编译,非常简单,只需在正式使用a之前,给a设置一个初始值即可。如果是对象:
public static void main(String[] args) {Date d = new Date();d.printDate();d.setDate(2021,6,9);d.printDate();}// 代码可以正常通过编译
为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?
要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:
我上面就讲了每实例化一个对象就会有一个私有的实例化变量空间,这个实例化变量空间当对象被创建之后就会初始化,也会存储改对象的变量值。
5.2默认初始化
class Date {public int year;public int month;public int day;public void printDate() {System.out.println(this.year + "/" + this.month + "/" + this.day);}}public class Test {public static void main(String[] args) {Date date1 = new Date();date1.printDate();
这是运行后的结果:
5.3就地初始化
在声明成员变量时,就直接给出了初始值。
class Date {public int year = 2023;public int month = 11;public int day = 11;public void printDate() {System.out.println(this.year + "/" + this.month + "/" + this.day);}}public class Test {public static void main(String[] args) {Date date1 = new Date();date1.printDate();
重点我们要讲一下构造方法去初始化:
5.4 构造方法
5.4.1 概念
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
class Date {public int year;public int month;public int day;public Date() {this.year = 2023;this.month = 11;this.day = 11;}public void printDate() {System.out.println(this.year + "/" + this.month + "/" + this.day);}}public class Test {public static void main(String[] args) {Date date1 = new Date();date1.printDate();
5.4.2 特性:
- 名字必须与类名相同
- 没有返回值类型,设置为void也不行
- 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
- 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
方法重载:名字相同,参数列表不一样。
public Date(int year, int day) {this.year = year;this.day = day;}public Date(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}public Date() {this.year = 2023;this.month = 11;this.day = 11;}
上述代码就构造了方法重载,有两个参数,有三个参数,和没有参数。
在idea中可以快速创建重载方法:单击右键或者快捷键Alt+Insert
如果用户自己没有去定义构造方法,那么编译器会自己默认生成一个无参的构造方法并且调用。
如果用户定义了构造方法,那么编译器就不会去自己生成一个无参的构造方法。
上面讲到this不是还有这样的一种用法吗?
在这里就可以知道this的这种方法怎么用的了。
构造方法中,可以通过this调用其他构造方法来简化代码
class Date {public int year;public int month;public int day;public Date(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}public Date() {this(2023,11,11);}public void printDate() {System.out.println(this.year + "/" + this.month + "/" + this.day);}}public class Test {public static void main(String[] args) {Date date1 = new Date();date1.printDate();
在这里我们通过this(2023,11,11)调用含三个参数的构造方法来实现对代码的简化。
注意:this(…)必须是构造方法中第一条语句
如果this()不是在构造方法中的第一条语句,那么就会报错。
不能成环,通过this()调用了三个参数的构造方法,再到那个三个参数构造方法通过this()调用无参数的构造方法,这是不被允许的。
如果是通过this()调用了一个含参数的构造方法,之后再这个含参数的构造方法利用this()去调用另一个含参数的方法,这样是被允许的。总之是不能闭环。
public Date( int month) {this.month = month;}public Date(int year, int day) {this(11);this.year = year;this.day = day;}public Date() {this(2023,11);}
本章完>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>