------------------ (正文开始)------------------
Java
是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来设计程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。
传统洗衣服:拿盆->放水->放衣服->放洗衣粉->手搓->换水->放洗衣粉->手搓->拧干->晾衣服
现代洗衣服:人将衣服放进洗衣机,倒入洗衣粉,启动洗衣机,洗衣机开始洗衣并甩干。
通过对比不难发现:
- 传统洗衣服是面向过程的,更注重于洗衣服的过程,缺少任何一个环节都可能不行。并且针对不同的衣物可能存在不同的洗衣方式,这就导致处理起来比较麻烦,如果按照这种方式写代码,将来拓展维护也会比较困难。
- 现代洗衣服是面向对象的,主要依靠用户、衣服、洗衣粉、洗衣机四个对象之间的交互完成的用户只需要放入衣服,倒入洗衣粉,启动洗衣机即可,并不需要关注洗衣的具体细节。
大象装进冰箱需要几步? 第一步:打开冰箱。第二步:将对象放进冰箱。第三步:关上冰箱门
汽车拼装: 搭建底盘->组装轮子->装发动机->装车灯……
显然前者是面向对象的,不关心中间的具体步骤。后者更注重中间的每一个步骤是面向过程的。
注: 面向过程和面相对象并不是一门语言,而是解决问题的方法,面向对象和面向过程没有好坏之分,都有其专门的应用场景。
面相对象程序设计关注的是对象,而对象是现实生活中的实体,比如:洗衣机。但是洗衣机计算机并不认识,需要开发人员告诉给计算机什么是洗衣机。这时我们就需要是一个模型一样的东西,借助语言工具来对一个洗衣机这个实体进行描述。这里就引出了——类
类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性
(名字、外观尺寸等),哪些功能
(用来干啥),描述完成后计算机就可以识别了。
比如:在Java中将洗衣机可以将其看成是一个类别。
属性:产品品牌,型号,产品重量,外观尺寸,颜色…
功能:洗衣,烘干、定时…
在java中定义类时需要用到class
关键字,具体语法如下图:
注解: 类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法。
了解了上面介绍的定义类的方法,下面我们就可以尝试着定义类了👇
我们已知洗衣机具有以下属性和功能:
属性:品牌、型号、重量、长、宽、高、颜色……
功能:洗衣、脱水、定时……
class WashMachine{//属性public String brand; // 品牌public String type; // 型号public double weight; // 重量public double length; // 长public double width; // 宽public double height; // 高public String color; // 颜色//功能public void washClothes(){ // 洗衣服System.out.println("洗衣功能");}public void dryClothes(){ // 脱水System.out.println("脱水功能");}public void setTime(){ // 定时System.out.println("定时功能");}
}
已知学生具有以下属性和行为:
属性:姓名、年龄、身高、体重……
行为:吃饭、睡觉、敲代码……
class Student {//属性public String name;//姓名public int age; //年龄public double height;//身高public double weight;//体重//行为public void eat() {System.out.println("吃饭!");}public void sleep() {System.out.println("睡觉!");}public void coding() {System.out.println("敲代码!");}
}
注意事项:
1、一般一个文件当中只定义一个类(非强制要求,但是只能有一个public
修饰的类)
2、main
方法所在的类一般要使用public修饰(非强制要求)
3、public
修饰的类必须要和文件名相同(硬性要求)
4、 不要轻易去修改public
修饰的类的名称,如果要修改,通过开发工具修改。如使用idea修改:
通过上面的两个练习你可能会多多少有些疑问,为什么成员前要写public
?为什么方法中不带 static
关键字?至于为什么,这里先埋个伏笔,下期会详细介绍。
定义了一个类,就相当于在计算机中定义了一种新的类型,只不过不同于内置类型int、double……类是用户自定义的一个新的类型,有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。
用类类型创建对象的过程,称为类的实例化,在java中采用new
关键字,配合类名来实例化对象。
下面这段代码表示实例化2个学生对象:
class Student {//属性public String name;//姓名public int age; //年龄//行为public void eat() {System.out.println(name+"吃饭!");}public void sleep() {System.out.println(name+"睡觉!");}public void coding() {System.out.println(name+"敲代码!");}
}public class Test {public static void main(String[] args) {//实例化一个学生对象-student1Student student1=new Student();student1.name="张三";student1.age=20;student1.coding();//实例化一个学生对象-student2Student student2=new Student();student2.name="李四";student2.age=22;student2.coding();}
}
通过观察上面实例化的例子,我们可以得出这些结论:
new
关键字用于创建一个对象的实例.- 使用
.
来访问对象中的属性和方法.- 同一个类可以创建
多个
实例.
如果想了解一下底层的储存原理,我们可以简单画一个内存图:
通过上面的一顿操作,相信你肯定对类和对象有了一定的认识,下面我们就再来简单的归纳一下:
- 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
- 类是一种自定义的类型,可以用来定义变量.
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量.
- 类和对象之间是抽象与具体的关系。类是一个模板,是对一类事物的抽象描述;对象用于表示现实中该事物的个体。类是在对象之上的抽象,对象则是类的具体化,是类的实例。
现在有这样一段代码:
public class Test2 {public int year;public int month;public int day;public void setDay(Test2 this,int y, int m, int d){year = y;month = m;day = d;}public void printDate(Test2 this){System.out.println(year + "/" + month + "/" + day);}public static void main(String[] args) {Test2 d1 = new Test2();d1.setDay(2020,9,15);d1.printDate();Test2 d2 = new Test2();d2.setDay(2022,11,11);d2.printDate();}
}
以上代码定义了一个日期类,然后main
方法中创建了2个对象d1
、d2
,不知道你有没有过这样的疑惑:
- 两个对象都在调用setDate和printDate函数,但是这两个函数中没有任何有关对象的说明,
setDate
和printDate
函数如何知道打印的是那个对象的数据呢?- 当形参名不小心与成员变量名相同:那函数体中到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量?成员变量参数?估计自己都搞不清楚了。
其实这些问题都与this引用息息相关,下面就让我们解开this引用的神秘面纱👇
其实类的每个成员方法的第一个参数默认是this
引用,this代表的是对当前对象的引用,谁调用了这个方法,谁就是这个引用。
为了能够直观的感受到这个参数的存在,我们可以通过调试进行观察。
注:通常this这个参数是不显示的也不用刻意添加,是默认存在的,这里添上是为了调试时更好的观察
- this的类型:对应
类类型引用
,即哪个对象调用就是哪个对象的引用类型- this只能在
"成员方法"
中使用(后面介绍)- 在"成员方法"中,this只能引用
当前对象
,不能再引用其他对象- this是“成员方法”
第一个隐藏的参数
,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收
正是由于this
这些特性的存在,使得我们可以精准的找到每个对象对应的成员方法。即便是成员方法的形参名与成员变量名相同时只要我们在变量前加上this.
即可。
//加上this表示给当前对象赋值
public void setDay(int year, int month, int day){this.year = year;this.month = month;this.day = day;
}
注:其实在每个成员方法中的变量前都添加上this.是一个很好的编程习惯,这样可以避免很多不必要的错误!熟练使用this,是一种好的编程习惯!
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,没有返回值,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
注:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。
- 名字必须与
类名
相同没有返回值
类型,设置为void也不行- 创建对象时由编译器自动调用,并且在对象的生命周期内
只调用一次
(相当于人的出生,每个人只能出生一次)- 如果你没有写任何构造方法,此时Java会帮我们提供一个
默认的不带参数
的方法体为空的构造方法。- 如果自己写了不管写了什么构造方法,Java都不会给你提供!
- 构造方法可以
重载
(用户根据自己的需求提供不同参数的构造方法)- 构造方法中,可以通过
this
调用其他构造方法来简化代码- 绝大多数情况下使用public来修饰,特殊场景下会被private修饰(后期讲)
下面着重介绍8、9特性👇
📝构造方法的重载
public class Test2 {
//成员变量,成员方法public int year;public int month;public int day;public void printDate(){System.out.println(this.year + "/" + this.month + "/" + this.day);}
//两个构造方法构成的重载:public Test2(int year, int month, int day){this.year = year;this.month = month;this.day = day;System.out.println("Test2(int,int,int)构造方法被调用了");}public Test2() {System.out.println("Test2()构造方法被调用了");}
//main函数public static void main(String[] args) {Test2 d1 = new Test2();d1.printDate();Test2 d2 = new Test2(2022,11,11);d2.printDate();}
}
📝通过this来调用其他构造方法
注:this(…)必须是构造方法中第一条语句。同时不能使用this
形成环。
public class Test2 {public int year;public int month;public int day;public void printDate(){System.out.println(this.year + "/" + this.month + "/" + this.day);}public Test2(int year, int month, int day){this.year = year;this.month = month;this.day = day;System.out.println("Test2(int,int,int)构造方法被调用了");}public Test2() {this(2008,10,1);System.out.println("Test2()构造方法被调用了");}public static void main(String[] args) {Test2 d1 = new Test2();d1.printDate();}
}
📝疑问1:对成员变量不进行任何初始化,不报错并且可输出值
📝疑问2:在构造方法中使用this
相要回答这两个问题就要好好看一下Test2 d1=new Test()
背后发生的故事了。在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
JVM
要保证给对象分配的空间不冲突数据类型 | 默认值 |
---|---|
byte | 0 |
char | ‘\u0000’ |
short | 0 |
int | 0 |
long | 0L |
boolean | false |
float | 0.0f |
double | 0.0 |
reference | null |
也许以上的几个环节我们还不能理解,不过我们从中应该可以看出实例化的大体过程。其实这也就很好地解决了我们以上的两个疑问:
1、即便没有赋值,在实例化对象的时候也会初始化分配的空间,所以不会报错并会输出初识值。
2、其实在调用构造方法前对象的基本信息就已经创建好了,所以使用this
也是没有什么问题的。
由于上述的初始化是在实例化过程中自动进行的,所以我们称为默认初始化。
在声明成员变量时,就直接给出了初始值。除非特殊的业务需求,否则一般我们不使用就地初始化。
public class Test2 {public int year=2020;public int month=10;public int day=1;public void printDate(){System.out.println(this.year + "/" + this.month + "/" + this.day);}public static void main(String[] args) {Test2 d1 = new Test2();d1.printDate();}
}
本章简单介绍了面向对象的概念,重点在于掌握Java中类的定义和使用,类的实例化,理解类和对象之间的关系,难点在于对this引用以及构造方法的理解。从本章开始Java语法部分的内容开始趋于抽象,对于类和对象的学习,需要慢慢的、逐步的才能理解。
------------------ (下期见!)------------------