目录
1.目标:理解类和对象之间的关系
2. 面向对象的初步认知
2.1 什么是面向对象
2.2 面向对象与面向过程
3.类的定义和使用
3.1 类的定义格式
4.类的实例化
4.1 什么是实例化
5.this引用
5.1 为什么要有this引用
5.2 什么是this引用
6. 对象的构造及初始化
6.1 如何初始化对象
6.2 构造方法
6.2.1 概念
6.2.2 特性
6.3 默认初始化
6.4 就地初始化
Java中一切皆为对象,比如描述一个人,会从他的长相和他所能做的事情来进行。
而对象的属性和对象的行为就构成了类。
Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。
我们所学的c语言就是一种面向过程的编程语言。就一个洗衣服的例子来说。传统的洗衣服过程是要分很多很多步来执行。
而面向过程则是只关心对象,不关心过程。整个洗衣服的过程:人将衣服倒进洗衣机,倒入洗衣粉,洗衣机启动,最后甩干衣服。这个过程包含了:人,洗衣机,洗衣粉,衣服四个对象。人们不需要去了解洗衣机具体是怎么工作的。只要了解对象之间是如何交互的即可。
类是用来对一个实体(对象)来进行描述的,比如:洗衣机,它是一个品牌,在Java中可以将其看成是一个类别。
属性:产品品牌,型号,产品重量,外观尺寸,颜色...
功能:洗衣,烘干、定时...
// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method; // 行为 或者 成员方法
}
class为定义类的关键字,ClassName(注意类名最好采用大坨峰的形式)为类的名字,{}中为类的主体。
例如:定义一个洗衣机类
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("定时功能");
}
}
一个类对应一个字节码文件,一般情况下,一个Java文件对应一个类。
那怎么样在IDEA中打开java文件呢?
定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的洗衣机类(一种新定义的类型)有了自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。
这样就实例化出了三个对象。
new对象的过程中,其实Java也进行了内存分配。我们的对象是在堆区上,只是将对象的地址给了引用变量,washMachine1就是一个引用变量,上面代码代表,我通过类定义了一个引用变量。这个引用变量指向了那个对象,也叫做引用指向对象。
这里就只画了两个对象作为实例。
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("定时功能");
}
}
public class Test {
public static void main(String[] args) {
WashMachine washMachine1 = new WashMachine();
washMachine1.dryClothes();
washMachine1.setTime();
washMachine1.washClothes();
}
}
由此我们可以看出:
new 关键字用于创建一个对象的实例.
使用 . 来访问对象中的属性和方法.
同一个类可以创建多个实例.
先看一个日期类的例子:
public class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d){
year = y;
month = m;
day = d;
}
public void printDate(){
System.out.println(year + "/" + month + "/" + day);
}
public static void main(String[] args) {
// 构造三个日期类型的对象 d1 d2 d3
Date d1 = new Date();
Date d2 = new Date();
Date d3 = new Date();
// 对d1,d2,d3的日期设置
d1.setDay(2020,9,15);
d2.setDay(2020,9,16);
d3.setDay(2020,9,17);
// 打印日期中的内容
d1.printDate();
d2.printDate();
d3.printDate();
}
}
以上代码定义了一个日期类,然后main方法中创建了三个对象,并通过Date类中的成员方法对对象进行设置和打印,代码整体逻辑非常简单,没有任何问题。
但是仔细来看
1. 形参名不小心与成员变量名相同:
此时,编译器输出的结果是
这是因为
2.三个对象都在调用setDate和printDate方法,但是这两个方法中没有任何有关对象的说明,setDate和printDate方法如何知道打印的是那个对象的数据呢?
这一切就要用this来解释了。
this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
public 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(this.year + "/" + this.month + "/" + this.day);
}
}
注意:this引用代表的是当前对象的引用, this只能在"成员方法"中使用
public static void main(String[] args) {
Date d = new Date();
d.setDay(2020,9,15);
d.printDate();
}
有的人可能说this引加不加上都不影响结果,我的建议是最好加上,加上有不会错,还能让代码更加具有可读性。
通过前面知识点的学习知道,在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();
}
// 代码可以正常通过编译
需要调用之前写的SetDate方法才可以将具体的日期设置到对象中。通过上述例子发现两个问题:
1. 每次对象创建好后调用SetDate方法设置具体日期,比较麻烦,那对象该如何初始化?
2. 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
public class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d){
year = y;
month = m;
day = d;
}
public void printDate(){
System.out.println(year + "/" + month + "/" + day);
}
public Date() {
System.out.println("abcdef");
}
public static void main(String[] args) {
// 构造三个日期类型的对象 d1 d2 d3
Date d = new Date();
d.printDate();
}
}
public class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d){
year = y;
month = m;
day = d;
}
public void printDate(){
System.out.println(year + "/" + month + "/" + day);
}
public Date(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("调用三个参数的构造方法!");
}
public Date() {
System.out.println("abcdef");
}
public static void main(String[] args) {
Date d = new Date(2023,6,23);
d.printDate();
}
}
这样,我们就能够得出构造方法的一些特点
1. 名字必须与类名相同
2. 没有返回值类型,设置为void也不行
3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
5.构造方法中,可以通过this调用其他构造方法来简化代码
public class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d){
year = y;
month = m;
day = d;
}
public void printDate(){
System.out.println(year + "/" + month + "/" + day);
}
public Date() {
this(2023,1,23);
System.out.println("不带参数的构造方法!");
}
public Date(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("调用三个参数的构造方法!");
}
public static void main(String[] args) {
Date d = new Date();
d.printDate();
}
}
注意:this(...)必须是构造方法中第一条语句
this(...)不能形成环
public Date(){
this(1900,1,1);
}
public Date(int year, int month, int day) {
this();
}
/*
无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用
编译报错:Error:(19, 12) java: 递归构造器调用
*/
总结一下:this()调用:1. 这个写法只能写在构造方法中
2. 构造方法中,不能自己调用自己
3. 它只能够放在构造方法的第一行
在上文中提出的第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?
这个留在后续的章节中讲解,我们只要知道默认的值是多少就行了
很简单,在声明成员变量时,就直接给出了初始值
public class Date {
public int year = 1900;
public int month = 1;
public int day = 1;
public Date(){
}
public Date(int year, int month, int day) {
}
public static void main(String[] args) {
Date d1 = new Date(2021,6,9);
Date d2 = new Date();
}
}