0


Java——类和对象

前言

Java与C语言最大的区别就在于一个是面向过程,一个是面向对象的,今天我们就走进Java当中的类和对象。

一. 面向对象的初步认知

1.1 什么是面向对象

Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。

1.2 面向对象与面向过程

对于这个的理解,我们具一个例子大家就能很好的理解:

  1. 传统洗衣服过程

传统的方式:注重的是洗衣服的过程,少了一个环节可能都不行。而且不同衣服洗的方式,时间长度,拧干方式都不同,处理起来就比较麻烦。如果将来要洗鞋子,那就是另一种放方式。按照该种方式来写代码,将来扩展或者维护起来会比较麻烦。

  1. 现代洗衣服过程

如今洗衣服的对象共有四个:人,衣服,洗衣粉,洗衣机。

整个的过程只需要,四个对象交互完成即可,并不需要人去关心洗衣机是如何去洗衣服的。

以面向对象方式来进行处理,就不关注洗衣服的过程,具体洗衣机是怎么来洗衣服,如何来甩干的,用户不用去关心,只需要将衣服放进洗衣机,倒入洗衣粉,启动开关即可,通过对象之间的交互来完成的。

注意:面向过程和面相对象并不是一门语言,而是解决问题的方法,没有那个好坏之分,都有其专门的应用场景。

二. 类的定义和使用

面向对象程序设计关注的是对象,而对象指代就是生活中的各种实体,就例如洗衣机,但是我们的计算机并不认识洗衣机,这个时候就需要去给这个对象定义,告诉计算机什么是洗衣机

2.1 简单认识类

类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干啥),描述完成后计算机就可以识别了。

比如:洗衣机,它是一个品牌,在Java中可以将其看成是一个类别。

属性:产品品牌,型号,产品重量,外观尺寸,颜色...

功能:洗衣,烘干、定时....

2.2 类的定义格式

在java中定义类时需要用到class关键字,具体语法如下:

  1. // 创建类
  2. class ClassName{
  3. field; // 字段(属性) 或者 成员变量
  4. method; // 行为 或者 成员方法
  5. }

class为定义类的关键字,ClassName为类的名字,{}中为类的主体。

类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法。

  1. class WashMachine{
  2. public String brand; // 品牌
  3. public String type; // 型号
  4. public double weight; // 重量
  5. public double length; // 长
  6. public double width; // 宽
  7. public double height; // 高
  8. public String color; // 颜色
  9. public void washClothes(){ // 洗衣服
  10. System.out.println("洗衣功能");
  11. }
  12. public void dryClothes(){ // 脱水
  13. System.out.println("脱水功能");
  14. }
  15. public void setTime(){ // 定时
  16. System.out.println("定时功能");
  17. }
  18. }

采用Java语言将洗衣机类在计算机中定义完成,经过javac编译之后形成.class文件,在JVM的基础上计算机就可以识别了。

注意事项

1.类名注意采用大驼峰定义

2.成员前写法统一为public,后面会详细解释

3.此处写的方法不带 static 关键字. 后面会详细解释

三. 类的实例化

3.1 什么是实例化

定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:PetDog类和Student类。它们都是类(一种新定义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。例如:

  1. class PetDog {
  2. public String name;//名字
  3. public String color;//颜色
  4. // 狗的属性
  5. public void barks() {
  6. System.out.println(name + ": 旺旺旺~~~");
  7. }
  8. // 狗的行为
  9. public void wag() {
  10. System.out.println(name + ": 摇尾巴~~~");
  11. }
  12. }
  13. public class Test {
  14. public static void main(String[] args) {
  15. PetDog dogh = new PetDog(); //通过new实例化对象
  16. dogh.name = "阿黄";
  17. dogh.color = "黑黄";
  18. dogh.barks();
  19. dogh.wag();
  20. PetDog dogs = new PetDog();
  21. dogs.name = "阿黄";
  22. dogs.color = "黑黄";
  23. dogs.barks();
  24. dogs.wag();
  25. }
  26. }

注意事项

1.new 关键字用于创建一个对象的实例

2.使用 . 来访问对象中的属性和方法

3.同一个类可以创建多个实例

3.2 类和对象的说明

  1. 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.

  2. 类是一种自定义的类型,可以用来定义变量.

  3. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量

  4. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间

四. this引用

4.1 为什么要有this引用

先看这样一个例子:

  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. public void setDay(int y, int m, int d){
  6. year = y;
  7. month = m;
  8. day = d;
  9. }
  10. public void printDate(){
  11. System.out.println(year + "/" + month + "/" + day);
  12. }
  13. public static void main(String[] args) {
  14. // 构造三个日期类型的对象 d1 d2 d3
  15. Date d1 = new Date();
  16. Date d2 = new Date();
  17. Date d3 = new Date();
  18. // 对d1,d2,d3的日期设置
  19. d1.setDay(2020,9,15);
  20. d2.setDay(2020,9,16);
  21. d3.setDay(2020,9,17);
  22. // 打印日期中的内容
  23. d1.printDate();
  24. d2.printDate();
  25. d3.printDate();
  26. }
  27. }

以上代码定义了一个日期类,然后main方法中创建了三个对象,并通过Date类中的成员方法对对象进行设置和打印,代码整体逻辑非常简单,没有任何问题。

但是细思之下有以下两个疑问:

  1. 形参名不小心与成员变量名相同:
  1. public void setDay(int year, int month, int day){
  2. year = year;
  3. month = month;
  4. day = day;
  5. }

那函数体中到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量?成员变量参数?估计自己都搞不清楚了。

  1. 三个对象都在调用setDate和printDate函数,但是这两个函数中没有任何有关对象的说明,setDate和printDate函数如何知道打印的是那个对象的数据呢?就像上面d1,d2,d3,我们知道是谁调用了这个函数,但是计算机并不知道是谁调用。

4.2 什么是this引用

this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. public void setDay(int year, int month, int day){
  6. this.year = year;
  7. this.month = month;
  8. this.day = day;
  9. }
  10. public void printDate(){
  11. System.out.println(this.year + "/" + this.month + "/" + this.day);
  12. }
  13. }

注意:this引用的是调用成员方法的对象。

  1. public static void main(String[] args) {
  2. Date d = new Date();
  3. d.setDay(2020,9,15);
  4. d.printDate();
  5. }

这样我们就能明确知道是d使用了这个这个方法,这个this所指向的就是d。

4.3 this引用的特性

  1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型

  2. this只能在"成员方法"中使用

  3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象

  4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收

在代码层面来简单演示--->注意:下图右侧中的Date类也是可以通过编译的

五. 对象的构造及初始化

5.1 如何初始化对象

通过前面知识点的学习知道,在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败。

  1. public static void main(String[] args) {
  2. int a;
  3. System.out.println(a);
  4. }
  5. // Error:(26, 28) java: 可能尚未初始化变量a

要让上述代码通过编译,非常简单,只需在正式使用a之前,给a设置一个初始值即可。如果是对象:

  1. public static void main(String[] args) {
  2. Date d = new Date();
  3. d.printDate();
  4. d.setDate(2021,6,9);
  5. d.printDate();
  6. }
  7. // 代码可以正常通过编译

需要调用之前写的SetDate方法才可以将具体的日期设置到对象中。通过上述例子发现两个问题:

  1. 每次对象创建好后调用SetDate方法设置具体日期,比较麻烦,那对象该如何初始化?
  2. 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?

5.2 构造方法

5.2.1 概念

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. // 构造方法:
  6. // 名字与类名相同,没有返回值类型,设置为void也不行
  7. // 一般情况下使用public修饰
  8. // 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
  9. public Date(int year, int month, int day){
  10. this.year = year;
  11. this.month = month;
  12. this.day = day;
  13. System.out.println("Date(int,int,int)方法被调用了");
  14. }
  15. public void printDate(){
  16. System.out.println(year + "-" + month + "-" + day);
  17. }
  18. public static void main(String[] args) {
  19. // 此处创建了一个Date类型的对象,并没有显式调用构造方法
  20. Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
  21. d.printDate(); // 2021-6-9
  22. }
  23. }

注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。

5.2.2 特性

  1. 名字必须与类名相同

  2. 没有返回值类型,设置为void也不行

  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)

  4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)

  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. // 无参构造方法
  6. public Date(){
  7. this.year = 1900;
  8. this.month = 1;
  9. this.day = 1;
  10. }
  11. // 带有三个参数的构造方法
  12. public Date(int year, int month, int day) {
  13. this.year = year;
  14. this.month = month;
  15. this.day = day;
  16. }
  17. public void printDate(){
  18. System.out.println(year + "-" + month + "-" + day);
  19. }
  20. public static void main(String[] args) {
  21. Date d = new Date();
  22. d.printDate();
  23. }
  24. }

上述两个构造方法:名字相同,参数列表不同,因此构成了方法重载。

  1. 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. public void printDate(){
  6. System.out.println(year + "-" + month + "-" + day);
  7. }
  8. public static void main(String[] args) {
  9. Date d = new Date();
  10. d.printDate();
  11. }
  12. }

上述Date类中,没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法。

注意:一旦用户定义,编译器则不再生成。

  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. public Date(int year, int month, int day) {
  6. this.year = year;
  7. this.month = month;
  8. this.day = day;
  9. }
  10. public void printDate(){
  11. System.out.println(year + "-" + month + "-" + day);
  12. }
  13. public static void main(String[] args) {
  14. // 如果编译器会生成,则生成的构造方法一定是无参的
  15. // 则此处创建对象是可以通过编译的
  16. // 但实际情况是:编译期报错
  17. Date d = new Date();
  18. d.printDate();
  19. }
  20. }
  21. /*
  22. Error:(26, 18) java: 无法将类 extend01.Date中的构造器 Date应用到给定类型;
  23. 需要: int,int,int
  24. 找到: 没有参数
  25. 原因: 实际参数列表和形式参数列表长度不同
  26. */
  1. 构造方法中,可以通过this调用其他构造方法来简化代码
  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. // 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复
  6. // 此处可以在无参构造方法中通过this调用带有三个参数的构造方法
  7. // 但是this(1900,1,1);必须是构造方法中第一条语句
  8. public Date(){
  9. //System.out.println(year); 注释取消掉,编译会失败
  10. this(1900, 1, 1);
  11. //this.year = 1900;
  12. //this.month = 1;
  13. //this.day = 1;
  14. }
  15. // 带有三个参数的构造方法
  16. public Date(int year, int month, int day) {
  17. this.year = year;
  18. this.month = month;
  19. this.day = day;
  20. }
  21. }

注意:

  1. this(...)必须是构造方法中第一条语句
  2. 不能形成环
  1. public Date(){
  2. this(1900,1,1);
  3. }
  4. public Date(int year, int month, int day) {
  5. this();
  6. }
  7. /*
  8. 无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用
  9. 编译报错:Error:(19, 12) java: 递归构造器调用
  10. */
  1. 绝大多数情况下使用public来修饰,特殊场景下会被private修饰(后序讲单例模式时会遇到)

5.3 默认初始化

在上文中提出的第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?

  1. public class Date {
  2. public int year;
  3. public int month;
  4. public int day;
  5. public Date(int year, int month, int day) {
  6. // 成员变量在定义时,并没有给初始值, 为什么就可以使用呢?
  7. System.out.println(this.year);
  8. System.out.println(this.month);
  9. System.out.println(this.day);
  10. }
  11. public static void main(String[] args) {
  12. // 此处a没有初始化,编译时报错:
  13. // Error:(24, 28) java: 可能尚未初始化变量a
  14. // int a;
  15. // System.out.println(a);
  16. Date d = new Date(2021,6,9);
  17. }
  18. }

要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:

  1. Date d = new Date(2021,6,9);

在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:

  1. 检测对象对应的类是否加载了,如果没有加载则加载

  2. 为对象分配内存空间

  3. 处理并发安全问题

比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

  1. 初始化所分配的空间

即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:

数据类型

默认值

byte

0

char

‘\u0000’

short

0

int

0

long

0L

boolean

false

float

0.0f

double

0.0

reference

null

  1. 设置对象头信息(关于对象内存模型后面会介绍)

  2. 调用构造方法,给对象中各个成员赋值

5.4 就地初始化

在声明成员变量时,就直接给出了初始值。

  1. public class Date {
  2. public int year = 1900;
  3. public int month = 1;
  4. public int day = 1;
  5. public Date(){
  6. }
  7. public Date(int year, int month, int day) {
  8. }
  9. public static void main(String[] args) {
  10. Date d1 = new Date(2021,6,9);
  11. Date d2 = new Date();
  12. }
  13. }

注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中


以上就是今天的全部内容,下期再见。

标签: java 开发语言 jvm

本文转载自: https://blog.csdn.net/m0_67910848/article/details/129723141
版权归原作者 Vex小摆子 所有, 如有侵权,请联系我们删除。

“Java——类和对象”的评论:

还没有评论