【JavaSE系列】第七话 —— 类和对象(1)
前言
前面的几话基本上 已经把和C语言 类似的部分,里面的 不一样的部分都已经介绍完了;
接下来就开始进入 类和对象 的学习。
由于博客篇幅较长,因此会分成多个部分来介绍,希望大家看完以后会收获满满,赚的盆满钵满。
一、本节目标
二、 面向对象的初步认知
2.1 什么是面向对象
Java 是一门纯面向对象((Object Oriented Program,OOP)的语言,
但是不是说面向对象的语言只有 Java;
在面向对象的世界里,一切皆为对象;
面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。
2.2 面向对象 与 面向过程
2.2.1 面向对象
注重的是洗衣服的过程,少了一个环节可能都不行。 而且不同衣服洗的方式,时间长度,拧干方式都不同,处理起来就比较麻烦。 如果将来要洗鞋子,那就是另一种放方式。 如果按照这种 面向过程 的方式写代码,将来扩展或者维护起来会比较麻烦。
2.2.2 面向对象
以面向对象方式来进行处理,就不关注洗衣服的过程; 具体洗衣机是怎么来洗衣服,如何来甩干的,用户不用去关心,只需要将衣服放进洗衣机,导入洗 衣粉,启动开关即可, 通过对象之间的交互来完成的。
总之,面向过程 的意思 就是 所有的过程 都要一步一步的自己去实现;而 面向对象 的意思是 需要去 找对象、创建对象、使用对象,不注意其中的过程。
【注意】面向过程和面相对象并不是一门语言,而是解决问题的方法,没有那个好坏之分,都有其专门的应用场景。
2.2.3 对象从何而来
想要有一个对象,首先就需要有一个类;
认为某一个实物(人、衣服、洗衣机、动物等等)是一个对象,那么就得需要去创建一个类;
有了类以后,就可以有对象了。
3. 类的定义与使用
3.1 简单认识类
类,就相当于一个 理论上的东西;
而 对象,就是把这个理论化的东西 给 造出来到现实世界之中。
举个例子,想要建造一个房子;
那么,房子的图纸 就是一个 类;
而 造出来的房子 就是一个对象。
3.2 类的定义格式
在java中定义类时需要用到class关键字,具体定义语法如下:
其中,class为定义类的关键字,ClassName为类的名字,需要用大驼峰的形式命名,{}中为类的主体。
类中包含的内容称为类的成员。 属性主要是用来描述类的,称之为类的成员属性或者类成员变量。 方法主要说明类具有哪些功能,称为类的成员方法。 代码示例:
public class Person { //属性【成员变量】:定义在类当中,并且在方法的外边 public String name; public int age; //方法【成员方法】 public void sleep(){ System.out.println("睡觉!!!!!!"); } public void eat(){ System.out.println("吃饭!!!!!!"); } public void show(){ System.out.println("姓名:"+name+"年龄:"+age); }}
【说明】定义了一个 Person类,就相当于有了一个 模板 了;通过模板可以造出不同的 对象,比如说,小明有自己的 name,age,也会sleep,eat,show;小花也有自己的 name,age,也会sleep,eat,show......
从理论上来说,一个 .java文件 只有一个类;即:每一次重新创建一个 .java文件 的时候,它都自己会自动创建一个类:不过需要注意的是,一个 .java文件 只能有一个public类,如果有多个的话,那么就会报错:
【注意】
- 一般一个 .java文件 当中只定义一个类(这个不是硬性要求);
- main方法所在的类一般要使用public修饰(当然,如果不是bublic类也可以修饰main方法);
- public修饰的类必须要和文件名相同,否则就会报错;
- 不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改;
4. 类的实例化
4.1 什么是实例化
定义了一个类,就相当于在计算机中定义了一种新的类型;与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:Person类(一种新定义的类型);有了自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。 用类类型创建对象的过程,称为类的实例化,在java中采用new 关键字,配合 类名 来实例化对象。 代码示例: 首先创建一个Person类(用来找对象,相当于一个图纸):
public class Person { //属性:成员变量——>定义在 类的内部,方法的外部 public String name; public int age; public void sleep(){ System.out.println("睡觉!!!!!!"); } public void eat(){ System.out.println("吃饭!!!!!!"); } public void show(){ System.out.println("姓名:"+name+"年龄:"+age); }}
然后在另外一个类上面 通过new关键字 来实例化对象(用来创建对象,通过图纸来建造房子):
public class TestDemo_2 { public static void main(String[] args) { //通过new关键字来实例化对象 //可以实例化多个对象 //创建的对象都有类中的属性 Person person1 = new Person(); Person person2 = new Person(); Person person3 = new Person(); Person person4 = new Person(); }}
new关键字的语法格式:
类名 变量名 = new 类名();//调用方法的时候才会用小括号(),其实这个也是调用方法——>构造方法//至于什么是构造方法,以及构造方法的相关知识点,会在下面介绍
这个过程叫做 实例化对象,它是一个创建对象的过程,只要new 就会给这块对象分配一块内存。
不要说 成员变量就是对象!!!!!!
属性:又称作 成员变量(定义在类的内部,方法的外部的)。
new了一个对象以后,在对象里面 就会拥有 这些属性:
那么我们怎么才能调用这些对象呢(使用对象)?
这个时候就需要用到 点操作符 .
此时,如果运行以下代码,堆上的对象就会被赋予相应的初值:
当然,我们也可以通过 点操作符 . 来调用相应的方法:
//Person类public class Person { public String name; public int age; public void sleep(){ System.out.println("睡觉!!!!!!"); } public void eat(){ System.out.println("吃饭!!!!!!"); } public void show(){ System.out.println("姓名:"+name+" 年龄:"+age); }}
//测试类public class TestDemo { public static void main(String[] args) { Person person1 = new Person(); person1.name = "zhangsan"; person1.age = 19; person1.eat(); person1.sleep(); person1.show(); System.out.println("----------------------------------"); Person person2 = new Person(); person2.name = "lisi"; person2.age = 20; person2.eat(); person2.sleep(); person2.show(); }}
当然,如果成员变量在刚开始的时候没有赋予初值,那么就会默认为初始值是对应的0值;
如果是局部变量的话,在前面介绍过,如果局部变量没有初始化,那么肯定会报错。
4.2 总结出三个小问题
4.2.1 如何定义一个类
public class Student { //属性 public String name; public int age; public double score; public String sex; //方法 public void doClass(){ System.out.println("上课!!!!!!"); } public void doHomeWork(){ System.out.println("做作业!!!!!!"); }}
4.2.2 如何通过这个类 实例化对象
Student student1 = new Student(); Student student2 = new Student();
4.2.3 怎么去访问实例化出来的 对象的属性和方法
//通过对象的引用 student1.属性; student1.方法;
5. this引用
5.1 为什么要有this引用
现在我们先来看一个日期类的例子:
public class MyDate { public int year; public int month; public int day; /** * 设置日期 */ public void setDate(int myYear,int myMonth,int myDay){ year = myYear; month = myMonth; day = myDay; } /** * 打印日期 */ public void printDate(){ System.out.println("年:"+year+" 月:"+month+" 日:"+day); } public static void main(String[] args) { MyDate myDate1 = new MyDate(); myDate1.setDate(2022,3,27); myDate1.printDate(); MyDate myDate2 = new MyDate(); myDate2.setDate(2022,3,27); myDate2.printDate(); }}
以上代码结构非常简单,就是定义了一个日期类,然后并且对这个日期类进行打印。
看起来确实是没有什么问题,但是仔细琢磨琢磨还是有问题的:
第一个问题:站在setDate方法的角度来说,不知道 year是哪个对象的year,month是哪个对象的month,day是哪个对象的day(因为现在有两个对象);
第二个问题:当把setDate方法改成这个样子的时候,按理来说也是正确的,没有任何的逻辑错误;但是当真正运行的时候,就会发现运行结果出现偏差:
/** * 设置日期 */ public void setDate(int year,int month,int day){ year = year; month = month; day = day; }
其实是这样子出现偏差的:
上面的 year = year;month = monrh;day = day; 其实是一样的。
传的参数year、month、day它们是局部变量,其作用域在setDate方法内部;
即:在作用域范围内,其出现的所有year、month、day其实都是形参的year、month、day;
就相当于 是自己给自己赋值了,但是没有给 上面的 处于setDate方法之外的 局部范围之外的 当前对象的year、month、day赋值;
所以,存储在堆上面的 对象的 year、month、day并没有被赋值;
所以就会产生偏差,这个很好理解。
5.2 this的引用
那么,应该怎样去解决上面的问题呢?
这个就需要 this引用 来解决这个问题:
/** * 设置日期 */ public void setDate(int year,int month,int day){ this.year = year; this.month = month; this.day = day; }
通过使用 this引用,又正确的打印出来了。
5.3 this的引用特性
this:代表当前对象的引用,即 哪个对象调用就是哪个对象的引用类型。这个可以用打断点的方式来证明:
到目前为止,我们知道 关于this的:
- 代表当前对象的引用;
- 当参数和成员的名字冲突的时候,可以用以区别(当然,如果名字不冲突的时候,也可以用this.);
到底以后的程序是否要加上this,建议是:在当前类当中去访问 自己的成员变量和属性的时候,可以去把this加上(不是硬性要求),如:
/** * 设置日期 */ public void setDate(int year,int month,int day){ this.year = year; this.month = month; this.day = day; } /** * 打印日期 */ public void printDate(){ System.out.println("年:"+this.year+" 月:"+this.month+" 日:"+this.day); }
当然,this只能 在 "成员方法" 中使用,this不能再静态方法里面使用(这个在下面会介绍)。
在"成员方法"中,this只能引用当前对象,不能再引用其他对象,具有final属性。
6. 对象的构造及初始化
6.1 如何去初始化对象
通过前面知识点的学习知道,在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败。
如果想要去初始化对象,那么可以用 点操作符. 去一个一个初始化;
也可以去调用所创建的方法去初始化对象:
还有一种初始化的方式——就地初始化:即直接在所定义的 属性 进行赋值:
不过这种方式一点也不好,毕竟这个Student类是一个模板;
不可能以后所实例化的对象 都叫做 bit,年龄都是19岁......
那么如果有的学生 不叫做 bit,年龄不是19岁,......,那么在实例化过后 又需要重新进行赋值,就会把 就地初始化 所附的值给覆盖掉了;那么,在平常的情况下就显得没有必要了,除非业务需求希望是 默认就要那些属性值。
当然,初始化对象不可能只有这几种方式,还可以有我们下面所介绍的 构造方法:
6.2 构造方法
6.2.1 概念
构造方法(也称为构造器)是一个特殊的成员方法; 要求:
- 方法名必须和类名是一致的;
- 没有返回值。
【说明】在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
【注意】
当我们实例化一个对象的时候,必须会经过以下两个步骤(但不是一定只有这两个步骤):
- 为对象分配内存;
- 调用合适的构造方法。
下面我们来看一下例子来介绍:
实际上,在实例化对象的时候,它会默认调用 构造方法;
//一开始就在疑惑,一般 方法的后面才会有小括号,//为什么 实例化对象的时候 会有小括号()的出现呢?Student student = new Student();//原来这个小括号就是 在默认帮助调用构造方法
那么,现在 又有人会发出疑惑,一开始的时候不是没有写 构造方法吗,为什么程序却没有报错呢?
其实,当程序当中 没有构造方法的时候,编译器会帮助我们 默认提供一个不带参数的构造方法,
即:没有构造方法的时候,它会默认提供一个如下的默认构造方法:
如果写上了一个构造方法,那么编译器就不会再帮你默认生成一个不带参数的构造方法:
细心的铁汁们就会发现,构造方法是可以发生重载的;
在实例化对象的时候调用构造方法;
那么,用 构造方法 来干嘛呢?
——可以用来帮助初始化当前对象的属性:
这样就不需要一个一个的去赋值了,直接new对象的时候去赋值就可以了:
当然,可以用IDEA来 自动提供包含参数的构造方法(就是可以不用自己来写了):
6.2.2 特性
- 名字必须与类名相同 ;
- 没有返回值类型,设置为void也不行;
- 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次);
- 构造方法可以重载 (用户根据自己的需求提供不同参数的构造方法) 。
- 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
- this可以用来调用 本类中其他的构造方法。
浅浅的总结一下:
- 构造方法 是没有返回值的方法,方法名和类名是一样的;
- 构造方法 不止一个,可以有多个,多个构造方法之间,构成了重载;
- 当我们写了一个类之后,没有写构造方法的时候,编译器会帮助我们 默认生成一个不带参数的构造方法;
- 当我们写了任何一个构造方法之后,编译器不再为我们,提供不带参数的构造方法;
- 一个类 至少会有1个构造方法 就算你没有写;
- 构造方法 本质 就是来实例化对象的时候调用的,可用于初始化属性;
- this可以用来调用 本类中其他的构造方法【要在构造方法当中使用】(就是调用方法,不过有一个非常大的前提:必须要把this放到第一行,否则就会报错);所以,只能在构造方法当中,只能调用一个:
public class Student { public String name; public int age; public double score; public String sex; public void show(){ System.out.println("姓名:"+name+" 年龄:"+age+" 学分:"+score+" 性别:"+sex); } public Student(){ this("张三",19,100,"男"); System.out.println("这个是不带参数的构造方法!!!!!!"); } public Student(String name,int age,double score,String sex){ this.name = name; this.age = age; this.score = score; this.sex = sex; System.out.println("这个是带4个参数的构造方法!!!!!!"); } //测试 public static void main(String[] args) { Student student = new Student(); student.show(); }}
this可以访问属性,this可以访问构造方法,那么this还可以 在一个普通的成员方法当中,通过this来调用另一个成员方法(当然,不加上this也可以,加上this更可以,习惯上还是来加一下):
this的用法:①this.data; 访问属性 ②this.func(); 访问方法 ③this(); 调用本类中其他的构造方法
不能形成环:
6.3 就地初始化 和 默认初始化
6.3.1 就地初始化
就地初始化 就是:在声明成员变量时,就直接给出了初始值。
public class Student { public String name = "张三"; public int age = 19; public double score = 100; public String sex = "男";}
6.3.2 默认初始化
默认初始化 就是:在声明成员变量时,没有给出初始值(但默认给出的是各种类型所对应的0值)。
public class Student { public String name; public int age; public double score; public String sex;}
此话博客正在持续更新中......