1.初始面向对象
1.1 什么是面向对象
Java是一门纯面向对象 的编程语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交换来完成一件事情
1.2 面向过程&面向对象的区别
这里以洗衣服为例:
1.手洗衣服过程
按照以上方式洗衣服,我们必须要亲自完成每一个阶段,其中每个阶段的处理方式也要我们自己来把握,比如:加水量,洗衣粉的量,搓衣服的力度等等。如果某个以后不洗衣服,改成洗鞋子,那么以上的流程就不一样了。按照这种方式来写代码,将来对代码进行扩展 和维护 就比较困难
2.现在洗衣服的过程
现在洗衣服会经常用到洗衣机来完成,那么使用洗衣机来洗衣服一般涉及四个对象:人,衣服,洗衣机,洗衣粉
洗衣服的过程如下:
人把衣服放进洗衣机,加入洗衣粉,启动洗衣机
以上整个过程中,主要是人,衣服,洗衣机,洗衣粉这四个对象在交互。人不需要关注洗衣机是怎么洗衣服的,人只需要把衣服放进去,加洗衣粉,然后启动开关就行了。
换言之,人只需要面向洗衣机这个对象,就能完成洗衣服,而不需要面向洗衣服的各个过程,这就是面向对象和面向过程的区别
2.类的定义和使用
面向对象编程关注的是对象,对象就相当于是生活中的实物,比如:洗衣机。但是计算机不知道什么是洗衣机,这需要我们开发人员来告诉计算机什么是洗衣机
上图左边的信息就是对洗衣机的描述,我们可以用这种描述信息来表示一个具体的实物,这个过程称为抽象。所谓抽象,指的是从具体事物中抽取共同的、本质的特征,忽略次要的、非本质的特征。但是这些简化的抽象结果(图片左侧的描述信息)也不能被计算机识别,开发人员就需要使用某种面向对象的编程语言来进行描述,比如:Java
2.1 简单认识类
**类是对一个实体(对象)来进行描述的。**主要描述该实体(对象)有哪些属性,有哪些功能,描述完成后计算机就可以识别了。以上述洗衣机为例,我们使用左边的描述信息来抽象一台洗衣机,但是计算机并不能识别这些描述信息,我们可以将这些信息放进一个类里面,然后计算机就可以识别了
2.2 类的定义格式
定义类的具体语法如下:
javafield; //属性或者成员变量 method; //行为或者成员方法 } ```
class
是定义类使用的关键字,ClassName是类的名字,{}中是类的主体,类的主体中定义了类有哪些属性,有哪些方法
下面我们来定义一个类来描述一台洗衣机:
java
public class WashingMachine {
//品牌
public String brand;
//型号
public String model;
//大小
public Double size;
//重量
public Double weight;
//价格
public Double price;
//洗衣服
public void wash() {
System.out.println("Washing clothes...");
}
//脱水
public void dehydrate() {
System.out.println("Dehydrating clothes...");
}
}
上述过程中,我们使用Java语言定义了一个洗衣机类,通过javac编译后转换为字节码文件,再由JVM翻译就可以被计算机识别了(Java文件如何被计算机识别,请看博文Java虚拟机------JVM(Java Virtual Machine)解析一)
注意1:
- 类名采用大驼峰形式。大驼峰:每个单词的首字母大写
- 类的成员变量/方法暂时使用public修饰。public是访问限定修饰符之一,后面讲到继承时再介绍
- 类的成员变量/方法暂时不使用static修饰
下面再来定义两个类来熟悉一下类的定义
(1)定义Dog类
java
class Dog{
public String name;
public int age;
public String color;
//
public void eat(){
System.out.println("eat food");
}
public void bark(){
System.out.println("汪汪汪...");
}
}
(2)定义学生类
java
class Student{
public String name;
public int age;
public int id;
public double score;
public String height;
public String weight;
//
public void exam(){
System.out.println("参加考试");
}
public void doHomework(){
System.out.println("写作业");
}
}
注意2:
- 一个Java文件建议定义一个类
- 使用public修饰的类在一个Java文件中只能存在一个
- 使用public修饰的类的类名 和所在文件的文件名相同
3.类的实例化
3.1 什么是实例化?
在上述代码中,我们定义了WashingMachine、Dog和Student类,就相当于在计算机中定义了这三个新的数据类型。和int、float等基本数据类型一样,只不过int和float是Java内置的2类型,而WashingMachine这些是用户自定义的类型,我们通过这些自定义类型就可以定义实例/对象 。而通过类 来定义实例/对象的过程,称之为实例化 ,在Java中需要借助new 关键字来完成实例化
3.2 如何访问对象中的成员变量/方法?
javapublic static void main(String[] args) { Dog dog = new Dog(); dog.name = "Dog"; System.out.println(dog.name); dog.age = 18; System.out.println(dog.age); dog.color = "blue"; System.out.println(dog.color); dog.eat(); dog.bark(); } } ```
运行结果如下:
注意:
- Java中使用
.
来访问对象中的成员变量/方法 - 同一个类可以实例化多个对象
3.3 类和对象的关系
类
是一种抽象的数据类型 ,它可以实例化一组具有相同属性(成员变量)和行为(成员方法)的对象。类可以看作是一个蓝图或者模板,用于创建对象
对象
是类的具体实现,每个对象都可以给自己的属性(成员变量)赋予独特的值
房屋和具体的房子
- 类(Class):房屋(House)
属性(Attributes):房间数量、面积、楼层数、地址
方法(Methods):建造、入住、出售- 对象(Object):具体的房子,如"张三的家"
实例化(Instantiation):张三的家是一个具体的房子,它有5个房间,面积是150平方米,3层楼,地址是"北京市朝阳区XX路"
行为(Behavior):张三的家可以被建造、入住或出售
4.this关键字
4.1 为什么要使用this?
这里举个例子
预期结果:2025-5-1
实际结果:null-null-null
原因分析:
java
public void setDate(String year, String month, String day) {
year = year;
month = month;
day = day;
}
这个方法中,形参的参数名和MyDate类的成员变量吗名一致,当给year赋值时,编译器无法区分year是成员变量还是方法的局部变量,在这种情况下会优先调用局部变量,相当于是自己给赋值
java
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
这个方法中没有形参,调用的参数(year/month/day)只能是MyDate类的成员变量,由于setDate方法没有给成员变量赋值,所以printDate打印的时候才会打印出null-null-null。分析到这里就明白了,问题在于当方法的形参名和类的成员变量名一致时,该如何进行区分呢?这就要借助this关键字
4.2 this是什么?
this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完 成
通过代码来解释一下:
当编译器去调用成员变量的时候都会通过this关键字来调用。this引用指向当前对象
,这句话又该怎么理解呢?以上面的代码为例
这里的当前引用指的就是myDate。换言之,this = myDate。
java
public void setDate(String year1, String month1, String day1) {
//this.year的含义是:myDate指向的对象中的year
//this.year = year1;这段代码的意思是:把 方法形参year1 赋值给 myDate指向的对象中的year
this.year = year1;
this.month = month1;
this.day = day1;
}
修改之后的代码如下:
java
public class MyDate {
public String year;
public String month;
public String day;
//
public void setDate(String year1, String month1, String day1) {
//使用this关键字来区分哪个是成员变量,哪个是方法形参
this.year = year1;
this.month = month1;
this.day = day1;
}
//
public void printDate(){
System.out.println(this.year + "-" + this.month + "-" + this.day);
}
//
public static void main(String[] args) {
MyDate myDate = new MyDate();
myDate.setDate("2025","5","1");
myDate.printDate();
}
}
注意:
在刚学习Java的使用就提醒过,使用一个变量之前需要给该变量赋初值,否则会报错
但是:
打印结果是null-null-null,并没有报错。这是怎么回事呢?
原因是,对于成员变量 来说,如果没有进行初始化,会有⼀个对应的默认值
String类型是引用类型,会赋予默认值null,所以不会报错
默认值遵循如下规则:
数据类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0 |
boolean | FALSE |
float | 0.0f |
double | 0 |
引用类型(reference) | null |
5.对象的构造及初始化
上文已经介绍到,成员变量在没有赋初值的时候会赋予默认值,这就是对象的默认初始化。说实话,我个人认为这是防止程序报错而出现的一个措施,不算正常的初始化操作,那么对象的初始化有哪些方式呢?
5.1 就地初始化
在声明 成员变量时,就直接给出了初始值
java
public class MyDate {
public String year = "2025";
public String month = "5";
public String day = "1";
//
public void setDate(String year1, String month1, String day1) {
this.year = year1;
this.month = month1;
this.day = day1;
}
//
public void printDate(){
System.out.println(this.year + "-" + this.month + "-" + this.day);
}
//
public static void main(String[] args) {
MyDate myDate = new MyDate();
myDate.printDate();
}
}
5.2 自定义方法初始化
用户自定义一个方法来进行成员变量的初始化操作
java
public class MyDate {
public String year;
public String month;
public String day;
//
public void setDate(String year1, String month1, String day1) {
this.year = year1;
this.month = month1;
this.day = day1;
}
//
public void printDate(){
System.out.println(this.year + "-" + this.month + "-" + this.day);
}
//
public static void main(String[] args) {
MyDate myDate = new MyDate();
myDate.setDate("2025","5","1");
myDate.printDate();
}
}
5.3 构造方法初始化
上面介绍的两种初始化方法,说实话都不是很常见。就地初始化灵活性太差;自定义方法初始化还需要创建并调用自定义的方法,不太方便
那么,有没有既灵活又方便的初始化方式呢?
那就是使用构造方法来初始化
5.3.1 什么是构造方法?
构造方法(也称为构造器)是一个特殊的成员方法,方法名必须和类型一致,在创建对象时由编译器自动调用 ,并且在整个对象的生命周期内构造方法只会调用一次
java
public class MyDate {
public String year;
public String month;
public String day;
//
public MyDate(String year, String month, String day) {
this.year = year;
this.month = month;
this.day = day;
}
//
public void printDate(){
System.out.println(this.year + "-" + this.month + "-" + this.day);
}
//
public static void main(String[] args) {
MyDate myDate = new MyDate("2025","5","1");
myDate.printDate();
}
}
在使用new关键字 实例化对象的时候,编译器会根据括号内的参数数量和类型 来判断调用哪个构造方法。这段代码中,new对象的时候一共传递了三个String类型的参数,编译器就会查找哪个构造方法的参数列表能与之对应
5.3.2 构造方法注意事项&使用规范
注意:
- 1.构造方法名必须和类名一致
- 2.没有返回值,设置void也不行
- 3.创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
- 4.构造方法可以重载(用户根据自己的需求创建不同参数列表的构造方法)
- 一般来说,构造方法使用public修饰
注意6:
当用户没有手动添加构造方法的时候,编译器会默认生成一份无参的 构造方法。当用户显式 地添加构造方法(不论有参还是无参)的时候,编译器将不再默认生成构造方法
左图中 ,用户没有显式地添加构造方法,编译器会默认生成 一个无参的构造方法,当用户需要实例化一个不赋初值地对象时,就能匹配到该无参构造方法;右图中 ,用户显式地添加一个构造方法,参数列表有三个形参,当用户需要实例化一个不赋初值地对象时,由于编译器没有 默认生成一个无参的构造方法,导致匹配失败 。所以,构造方法也有一个不成文的使用规范:当用户显式地添加构造方法后,不论无参的构造方法有没有用,都建议添加上
5.3.2 构造方法中使用this来简化代码
java
public class MyDate {
public String year;
public String month;
public String day;
//
public MyDate() {
this("2025","5","1");
}
public MyDate(String year, String month, String day) {
this.year = year;
this.month = month;
this.day = day;
}
//
public void printDate(){
System.out.println(this.year + "-" + this.month + "-" + this.day);
}
}
class Test{
public static void main(String[] args) {
MyDate myDate = new MyDate();
myDate.printDate();
}
}
在上述代码中,new对象的时候会默认调用无参的构造方法,无参的构造方法内使用了this()代码,编译器就会根据括号内的参数数量和类型 去查找参数列表与之匹配的构造方法
注意:
- this()必须是构造方法中的第一条语句
- this()不能形成环的调用