> 文档中心 > 【JavaSE系列】第七话 —— 类和对象(1)

【JavaSE系列】第七话 —— 类和对象(1)


前言

       前面的几话基本上 已经把和C语言 类似的部分,里面的 不一样的部分都已经介绍完了;

接下来就开始进入 类和对象 的学习。

       由于博客篇幅较长,因此会分成多个部分来介绍,希望大家看完以后会收获满满,赚的盆满钵满。


 

一、本节目标

  1. 掌握类的定义方式以及对象的实例化
  2. 掌握类中的成员变量和成员方法的使用
  3. 掌握对象的整个初始化过程
  4. 掌握封装特性
  5. 掌握代码块
  6. 掌握内部类

 


二、 面向对象的初步认知

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类,如果有多个的话,那么就会报错:

【注意】

  1. 一般一个 .java文件 当中只定义一个类(这个不是硬性要求);
  2. main方法所在的类一般要使用public修饰(当然,如果不是bublic类也可以修饰main方法);

      

  3. public修饰的类必须要和文件名相同,否则就会报错;

  4. 不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改;


4. 类的实例化

4.1 什么是实例化

定义了一个类,就相当于在计算机中定义了一种新的类型;intdouble类似,只不过intdoublejava语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的: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的:

  1. 代表当前对象的引用;
  2. 当参数和成员的名字冲突的时候,可以用以区别(当然,如果名字不冲突的时候,也可以用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 概念

构造方法(也称为构造器)是一个特殊的成员方法; 要求:

  1. 方法名必须和类名是一致的;
  2. 没有返回值。

【说明】在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次

【注意】

当我们实例化一个对象的时候,必须会经过以下两个步骤(但不是一定只有这两个步骤):

  1. 为对象分配内存;
  2. 调用合适的构造方法。

下面我们来看一下例子来介绍:

实际上,在实例化对象的时候,它会默认调用 构造方法;

//一开始就在疑惑,一般 方法的后面才会有小括号,//为什么 实例化对象的时候 会有小括号()的出现呢?Student student = new Student();//原来这个小括号就是 在默认帮助调用构造方法 

 那么,现在 又有人会发出疑惑,一开始的时候不是没有写 构造方法吗,为什么程序却没有报错呢?

其实,当程序当中 没有构造方法的时候,编译器会帮助我们 默认提供一个不带参数的构造方法,

即:没有构造方法的时候,它会默认提供一个如下的默认构造方法:

如果写上了一个构造方法,那么编译器就不会再帮你默认生成一个不带参数的构造方法:

 

 细心的铁汁们就会发现,构造方法是可以发生重载的;

在实例化对象的时候调用构造方法;

 

那么,用 构造方法 来干嘛呢?

——可以用来帮助初始化当前对象的属性:

这样就不需要一个一个的去赋值了,直接new对象的时候去赋值就可以了:

 当然,可以用IDEA来 自动提供包含参数的构造方法(就是可以不用自己来写了):

 

 6.2.2 特性

  1. 名字必须与类名相同
  2. 没有返回值类型,设置为void也不行;
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次);
  4. 构造方法可以重载 (用户根据自己的需求提供不同参数的构造方法) 。
  5. 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
  6. this可以用来调用 本类中其他的构造方法。

浅浅的总结一下:

  1. 构造方法 是没有返回值的方法,方法名和类名是一样的;
  2. 构造方法 不止一个,可以有多个,多个构造方法之间,构成了重载;
  3. 当我们写了一个类之后,没有写构造方法的时候,编译器会帮助我们 默认生成一个不带参数的构造方法;
  4. 当我们写了任何一个构造方法之后,编译器不再为我们,提供不带参数的构造方法;
  5. 一个类 至少会有1个构造方法 就算你没有写;
  6. 构造方法 本质 就是来实例化对象的时候调用的,可用于初始化属性;
  7. 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更可以,习惯上还是来加一下):

  8. this的用法:①this.data; 访问属性      ②this.func(); 访问方法      ③this(); 调用本类中其他的构造方法

  9. 不能形成环:

     

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;}

此话博客正在持续更新中......