说明

这是一个完善了但又不完善的笔记,或许以后会更新

可以参考但请务必超越

源文件


Tools


Typora
PicGo

Java 类和对象

类就是图纸,对象就是产物

虽然我很想通过这么一句话直接讲明白,但是这是完全不可以的。要彻底搞明白这个东西,最好的方式就是吃透干货!不管是硬生生吃还是有自己的办法,接下来的内容无论是搜索还是一点一点啃,最好务必搞搞清楚,对以后也有很大帮助。

注意,这一章很重要

关于类和对象,很多人都不是很明白

  1. 什么是类
  2. 什么是对象

这两个概念,非常的抽象!

难就难在,如何去抽象

1.类和对象的初步认知

这里,通过2个概念来帮助你理解:

  • 面向对象编程
  • 面向过程编程

面向过程,注重的是过程,在整个过程中所涉及的行为,就是功能

面向对象,注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来

要去抽象理解一个概念,最好的方法就是举例子

面向过程就好像是我们手动去做一件事,需要分很多个步骤一步一步来。面向对象就是直接用工具,工具会自动帮你完成所有步骤,你不需要去操心。

面向过程: 1.把冰箱打开 2. 把大象放入 3. 冰箱关起来

面向对象: 打开冰箱,储存,关闭都是对冰箱的操作,是冰箱的行为。冰箱就是一个对象,所以只要操作冰箱所具备的功能,都要定义在冰箱中。

以手机为例,现代人用手机太多了:

  1. 那么生产手机需要的图纸,就是类,使用这一个类,可以生产很多种手机,生产出来的手机就是实例化对象。你把图纸上的东西实例化了嘛。
  2. 生产手机,手工去一个一个造零件,造硬件,写系统,就是面向过程。直接用车床批量生产,就是面向对象

生活中有太多这样的例子,将现实世界和计算机世界映射对比,就可以较为容易的理解了

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

Java是基于面向对象的,关注的是对象

所以,我们后期主要就是学习使用对象

  1. 从类中找对象
  2. 创建对象
  3. 使用对象

就这3个点深入学习

接下来,可以通过实例化来加深理解

2.类和类的实例化

在Java开坑的时候有生成过.class文件,也就是字节码文件

一个类,对应一个字节码文件

接下来终于要探索类这个玩意了

类由字段和方法组成

那么首先我们肯定得有一个类吧,Java中有很多的类,我们新建项目不就也是直接创建了一个类吗

我们通过类来创建对象,就相当于根据图纸造物

class <class_name>{  
    field;//成员属性
    method;//成员方法
}

字段:属性->成员变量,定义在类的内部,方法的外部

成员方法:行为

一般我们定义的时候都是字段在前面,其他在后面

简单举个栗子,我们写一个人的类,接下来都会以这个类来讲述

class Person {
    //普通成员变量
    public String name;
    public int age;
    //每个人都有姓名和年龄
    //这些就是人这个类的字段,也就是属性,属于人这个类的成员变量
    //你可以直接在这里初始化值,不过在图纸里直接赋值,没什么意义
    
    //静态成员变量
    public static int count;
    //当然相对的也有静态方法
    
    public void eat() {
        System.out.println(name + "正在吃饭");
        //假设打印个谁在吃饭
    }
    //人得吃饭吧,所以吃饭这个方法,就是人这个类的行为
    //当然你也可以没有行为(人没有行为那不就寄了...)
    public void sleep() {
        System.out.println(name + "正在睡觉");
        //假设还要睡觉
    }
    
    //静态成员方法
    public static void staticFunc() {
        System.out.println("static::func()");
    }
}

玩过Minecraft我的世界的玩家肯定有共鸣。

kirito正在岩浆里游泳

这样我们就可以通过这个类,来实例化对象

类的命名规则

关于类名,一般都是首字母大写
这个其实没什么好说的
当然如果不大写也行,一般都推荐大写
如果因为没有大写而踩了坑,大概就会深深记住了吧...

实例化对象

<class_name> <对象名> = new <class_name>();

对象名存储对象地址,那就是一个引用

还记得我们之前使用的scanner

Scanner scanner = new scanner(System.in)

解读一下就是

Scanner类里面找scanner方法,创建scanner对象,从键盘输入使用

我们创建了人这个类,那么就可以实例化对象,创造一个人先(说法有点夸张...)

public class test {
    public static void main(String[] args) {
        Person person = new Person();
    }
}

注意,我们写的人Person这个类不能写在main函数所在的类test里。

访问使用成员变量

就很简单,使用类.成员变量即可

System.out.println(person.name);
System.out.println(person.age);

诶?这里可以看到,当前成员变量是没有赋值的,打印了null0。这是为什么呢?

成员变量默认值

如果我们没有给成员变量赋初值的话,他是会有默认值的

成员变量赋值

前面提到在类里面直接赋值,相当于在图纸里给值,没什么意义

那么成员变量的赋值,当然是在使用的时候再赋值

person.name = "kirito";
person.age = 18;

打印看看

null 和 引用指向同一个对象

这个就简单了

Person person = null;

person这个引用就不指向任何对象嘛

之前说过的嘛,一个引用指向一个对象。那么要是有person1person2多个引用,虽然只能指向一个对象,但是可以是一个对象

Person person = new Person();
Person person1 = person;
Person person2 = person;

person1person2这2个引用指向person这个引用所指向的对象。如果person指向一个new Person(),那么3个引用就都指向他,很容易理解吧。那么要是person指向null,笑死,全都没得指,指向了个寂寞。

访问使用成员方法

这个当然也就和前面一样了

我们前面给name赋值了名字,那么就看看吃饭的方法呗

当然啦,如果前面的成员变量name没有赋值,那就是默认值null正在吃饭

小结

  • new 关键字用于创建一个对象的实例
  • 使用.来访问对象中的属性和方法
  • 同一个类可以创建多个实例

3.实例化对象在内存的存储

现在有可以使用的类,也实例化了对象

那么接下来就应该研究研究类里面的这些成员了

3.1 普通成员变量

前面通过Person实例化对象的代码,是写在main函数里面的

那么也就是说对象名person是个引用且是局部变量

如果是局部变量,那肯定就是在栈上喽

在数组中提到过,引用指向一个对象,这就绕明白了

对象肯定就在堆上嘛

如果是个普通的成员变量,每个对象都会有一个普通的成员变量,不赋值就是默认值。

3.2 静态关键字static

前面我们使用的都是普通成员变量,比如age。那么相对的静态成员变量又是怎样的呢?

3.2.1 静态成员变量

static在类中定义的变量就是静态成员变量,叫做类变量。

这时我们可以使用我们创建的人person这个类中的静态成员变量count和普通成员变量age来进行对比,当然应该把前面age赋的值去掉

Person person1 = new Person();
person1.age++;
person1.count++;
System.out.println(person1.age);
System.out.println(person1.count);
System.out.println("----------");
Person person2 = new Person();
person2.age++;
person2.count++;
System.out.println(person2.age);
System.out.println(person2.count);

可以看一下,person1person2的这2个值都++了一下

可以看到age都是1,说明他们在2个对象里互不干扰。count是2说明静态成员变量不在对象里且只存在一个count所以2次++变成了2。

那么问题来了,静态成员变量存储在哪?

方法区

存放在方法区里,注意是属于类的,不是属于方法的。

方法区存储的内容:

  1. 存储一些代码片段
  2. 在Java开坑的时候生成的.class字节码文件
  3. 静态的成员变量

这样来想,就很清楚了,怪不得idea会标红色的波浪线提示,因为访问方法错了嘛,静态成员变量是属于类的,存放在方法区,压根就不需要对象。所以访问方式直接用类名就好了呀。

使用方式

类名.静态变量名(静态成员变量名、类变量名);

可以看到没有提示了,直接打印就行。

3.2.2 静态成员方法

那同样的

static在类中定义的方法就是静态成员方法,叫做类方法。

使用也就一样喽

类名.静态方法名(静态成员方法名、类方法名);

方法的调用,需要对象的引用来调用。但是如果可以使用static,类就可以调用。和前面的静态成员变量一样嘛,就不实例化对象了。

注意(很重要)

  • 静态的成员变量,是不可以在方法中定义的(前面讲到,存储位置都不一样,static定义的变量是属于类的。存储在方法区但和方法没关系。)。当然静态成员变量也不能在静态成员方法中定义。
  • 静态内部,不可以调用普通的方法。静态的方法不依赖于对象,非要用的话,就得新建一个对象(这样很怪...一般不这么做)。但是反过来可以,普通的方法可以调用静态的方法和静态的变量(直接通过类名调用)。
  • 当然,在任何方法上应用static关键字,方法就会变成静态方法
  • 即使是使用final修饰,虽然变成了常量,只要没有static就属于对象。只不过后续不能更改了。如果有static,就是静态的常量,属于类本身且只有一份。后续也不可更改。(一个对象存储到哪里和你是否被final修饰没关系)
  • 是否需要加static,要看情况。虽然加了可以不用new,但是后续或许会有一些其他的问题->“祖传代码”。被static修饰那就只有一个喽,这里改改哪里改改可能最后正常运行了,但是我草有bug!这就不能轻举妄动了...(很多游戏会出现这样的情况,比如某某游戏某某英雄出bug没办法直接动他,只能先禁用...)所以一般情况还是尽量少用static,能不用static解决就不用。

不过一般其实也不太会出问题,出问题编译器就会直接提示的。

这里再举个栗子解释下第二条

静态内部调用普通方法

main函数,是不是在我们写的class里面,那main函数也是被static修饰的,在我们写的类里面创建一个新的不用static修饰的普通方法,非要调用他的话不就得新建我们自己写的类吗?

public class test {

    public static void test1() {
        
    }

    public void test2() {
        
    }
    
    public static void main(String[] args) {
        test1();//main函数里直接用就好了嘛
        test test = new test();//好怪哦
        test.test2();
    }
}

所以根据这一点,以下有一个更蛋疼的面试题问法

面试题:main函数为什么是静态的

main函数是不是静态的都可以,取决于JVM。

JVM在设计的时候就规定了main函数是static修饰的,那要是规定不用修饰也是能运行的呀。

那假设main函数不写static...程序的入口就是main函数,怎么进去呢?在main函数里实例化对象然后类名.main?那不扯淡吗。

很有可能接着就讲JVM...所以后面一定要搞明白JVM

IEDA提供的快捷实现toString打印

这篇内容基本上都是干货,是在太硬了,这里可以中场休息,来点简单的。

我们在写类的时候可能会有很多的字段,那要是需要打印一下岂不是要写很多很多

这时,我们可以先打印看一下“引用”

想法

我们前面实例化的person不就是一个引用吗,打印一下看看

可以看到Person@1b6d3586Person是类名,后面@的东西叫做哈希值。因为Java设计的比较安全,不能直接拿到地址,所以我们拿到的相当于一个处理过的地址。关于哈希值可以直接去搜索,以后我或许也会讲吧...

注意,重点来了

编译器是怎么打印的呢?

我们打开println看一下。按住ctrl选择

这里的意思是拿到obiect(这里是地址嘛)转换成字符串,怎么转的呢?打开valueOf看一下

这里的意思是如果地址是null就返回打印null,如果不是就进入toString打印地址。那么我们打开toString看一下

这里的意思就是,返回这个类的类名,加上@加上后面的这个值

最后回到println

打印,换行

实现

通过上面的步骤可以知道,我们是不是可以直接使用toString来打印呢

public String toString() {
    return "姓名:" + name + " 年龄:" + age;
}

Person person = new Person();
System.out.println(person);

可以看到,行得通!

使用

于是,idea就为我们提供了自动实现toString()的快捷方法

在类里面,鼠标右键选择Generate,可以看到快捷键是alt+insert insert不常用不知道在哪,那就查,或者就用右键嘛,电脑基操

可以看到一个小窗口弹出,里面有很多idea提供的快捷实现功能,我们选择toString()

可以选择需要打印那些属性,多选就按住ctrlshift嘛,电脑基操

这次再打印就可以看到效果了

那么还有一个@Override,起一个检查的作用,后续还会讲到这其实是是一个重写的功能,字面意思就是重新写嘛。检查格式什么的,我们如果自己实现也要记得加上

可以看到idea真的很方便,前人走过的路使用过的感受不是没有道理的。

4.private封装

到这里,基本上对于类的学习可以说有了一定的认知

那么接下来问题就来了。

首先,在项目中编写了一个类的大佬,叫做类的实现者,那么我们使用类的人就是类的调用者

这时,如果这个类较为复杂,而类的实现者突然修改了其中的一些字段名或者方法名,那么类的调用者将会直接裂开...

试想一下类的调用者也要修改同步修改才能使用,而且如果有很多个类的调用者,那大家就都裂开了...

封装

《代码大全》开篇就在讨论一个问题:软件开发的本质就是对程序复杂程度的管理。如果一个软件代码复杂程度太高,那么就无法继续维护。如何管理复杂程度?封装就是最基本的方法。

在我们写代码的时候经常会涉及两种角色:类的实现者类的调用者

封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的,只要知道如何使用类就行了。

这样就降低了类使用者的学习和使用成本,从而降低了复杂程度。

这时,类的实现者可以使用private来进行封装,然后把gettersetter这2个方法告诉类的调用者就好了

这样类的实现者就可以随便改了,类的调用者可以使用固定给到的2个方法来使用

此时被private封装的字段名和方法名只能在此类中使用,所以说private封装的类也是很安全,别人拿到的也很安全

但是如果类的实现者连gettersetter这2个用来调用的方法名也改了,讲道理那太没意义了...

所以

4.1 命名约定

看过我写的文章的话,你可能会知道一点我的习惯,我习惯把较为重要的内容提前写到前面来。

那么,先不急着讲内容,先来讲关于起名字这个事情

这一点在阿里的Java开发手册或者其他公司的一些规定中,直接强制了起名规则,太具体就不详细说了

  • 总之,就算类的实现者怎么看都看不顺眼,看的不爽,gettersetter这样要给人用来调用的方法,名字起好最好就不要改。
  • 只要你使用了private封装,需要用到的时候,你就得提供gettersetter

4.2 private

我们在写代码的时候都会使用到public这个关键字

那么

privatepublic 这两个关键字就表示 ”访问权限控制“

  • public修饰的成员变量或者成员方法,可以直接被类的调用者使用。
  • private修饰的成员变量或者成员方法,不能被类的调用者使用。

其实也不难,很容易理解

private String name;
private int age;

这时我们想要修改肯定就会报错了

4.3 gettersetter

既然被private修饰了,那就无法直接使用

这时如果需要获取或者修改,就需要使用gettersetter

public void setName(String myName) {
    name = myName;
}
 
public String getName() {
    return name;
}

public void setAge(int myAge) {
    age = myAge;
}

public int getAge() {
    return age;
}

getter:就是上面的getName,返回name。类的调用者使用getName就可以获取了。

setter:就是上面的setName,类的实现者可以随便改myName,只要设定name = myName,类的使用者使用setName就可以修改了。

那类的调用者使用当然也很简单

Person person = new Person();
person.setName("kirito");
person.setAge(18);
System.out.println(person.getName());
System.out.println(person.getAge());

这时idea就又提供了快捷实现的功能

IEDA提供的快捷实现gettersetter打印

和前面的toString一样,我们使用看看

可以看到有单独分开的2个还有合在一起的,那么选择参数我们看一下

可以看到这是idea自动生成的,而且使用了this后面会讲

下面也正常的打印了出来

5.构造方法

到了这一节,较为难的点基本上攻克的差不多了,接下来的内容就较为容易一些(或许?)。但是,注意谨慎别大意

构造方法:就是一种特殊方法,用于完成初始化操作。方法名和类名相同,且没有返回值。

创建了类,也就是图纸,那你得使用吧。前面讲在类里先初始没什么意义,那要开始创造了,肯定先得赋予初始形态吧

5.1 基本语法

没有对象new一个,很常见了

前面讲到实例化对象,那么一个对象是如何产生的也就是对象如何实例化的呢?

new 执行过程(实例化对象过程)

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

这两步完成,对象才真正产生了。

这里注意使用了一个“合适”,也就是意味着构造方法,不止一个。

public Person() {
    System.out.println("Person()::不带参数的构造方法");
}

这里在我们的Person类写了一个最简单的构造方法

我们在main函数里仅仅实例化对象一下

Person person = new Person();

可以看到实例化了对象就直接打印了出来,之前都是没有打印的

也就是说这里new Person()就是调用了合适的构造方法

之前没有打印说明

当我们没有给类写任何构造方法的时候,编译器会默认给我们生成一个不带参数的构造方法

public Person() {
    
};

所以

注意

  • 如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数。一个类至少会有一个构造方法,所以写上更好。(此条后面还有注意)
  • 若类中定义了构造方法,则默认的无参构造将不再生成。
  • 构造方法支持重载。规则和普通方法的重载一致。
  • 构造方法不可以使用private。在类内可以实例化对象,但是在类外就不可以使用了。

带参数的构造方法

相对的带参数就简单了嘛

public Person(String name) {
    this.name = name;
    System.out.println("Person(String)::带一个String类型参数的构造方法");
}

Person person1 = new Person("test");

相当于在实例化person1的时候就给name赋了值,直接打印就可以看到

注意

现在有了不带参数和带参数2个构造方法

那么问题来了

注意重点,前面讲到

如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数。一个类至少会有一个构造方法,所以写上更好。

现在把不带参数的构造方法屏蔽掉

报错了,而且如果在大项目中,其实会集中体现于调用不带参数的构造方法

那,不是说编译器会默认帮我生成不带参数的构造方法吗

注意,现在的类里面是有其他的构造方法的(比如带参数的构造方法),那编译器就不会生成不带参数的构造方法

小结一下

  1. 如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数。一个类至少会有一个构造方法,所以写上更好。
  2. 如果当前类有其他的构造方法,那么编译器就不会帮我们生成不带参数的构造方法。
  3. 构造方法之间,可以构成重载

构造方法的重载

关于方法的重载,在方法那篇文章里讲过

那么这里的构造方法,不就是构成了重载吗

public Person() {
    System.out.println("Person()::不带参数的构造方法");
}

public Person(String name) {
    this.name = name;
    System.out.println("Person(String)::带一个String类型参数的构造方法");
}

可以看到方法名都是Person

构造方法支持重载,规则和普通方法的重载一样

5.2 this关键字

this就比较特殊了,不过从字面理解就是“这个”的意思嘛

this表示当前对象引用(注意不是当前对象,是他的引用)。可以借助this来访问对象的字段和方法

有些书里写的是this代表当前对象,这是错误的

前面讲到对象真正产生是要经过2个步骤的

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

很明显,前面this都放在构造方法里使用了,那只能说明this完成了第一步,并没有调用构造方法(调用完构造方法,对象才产生嘛)。所以this只表示当前对象的引用而不是当前对象。

举个栗子

前面setter写到年龄setAge,假设类的实现者突然发病了(玩笑),他把myAge改成了age

public void setAge(int age) {
    age = age;
}

注意:虽然可以运行,但是这时,这3个age是同一个age。我们叫做局部变量优先使用了。

那么类的调用者如果要修改

person.setAge(18);

就不会起作用

赋值赋了个寂寞

那么为了区别,就可以使用thisidea自动生成就是这样的

public void setAge(int age) {
    this.age = age;
}

意思就是类的调用者修改的age,赋值给实例化对象中的age

面试问题

关于this一般都会有这样一个面试问题:thissuper有什么区别

super以后再说,先看this

this一般有3种用法

  1. this.data,调用当前对象的属性
  2. this.func(),调用当前对象的方法
  3. this(),调用当前对象的其他构造方法

调用对象的属性,前面都是,gettersetter和构造方法都用到了。

调用当前对象的方法,也很简单,我们在Person类里写的方法,吃,睡,可以写成this.eat()this.sleep()

不过一般只是在调用对象属性的时候用以区分,方法一般能区分就不加了。

this()

这个没写过,不过也很好理解。就是直接调用当前对象的构造方法嘛。我们用前面写好的来看

public Person() {
    this();//err
    System.out.println("Person()::不带参数的构造方法");
}

当然不能这么写,这不就直接递归起来了嘛。编译器也直接报错了。

但是如果给里面写一个参数

public Person() {
    this("test");
    System.out.println("Person()::不带参数的构造方法");
}

public Person(String name) {
    this.name = name;
    System.out.println("Person(String)::带一个String类型参数的构造方法");
}

可以看到this("test")就变成了:调用带有1个参数的构造方法

就会执行下面的带参数的构造方法,最后再打印剩下的一句话

注意

  • 如果要使用this(),就要放在第一行,作为第一条语句,假如写了2个this()那都要第一行肯定不行。
  • this()只能存放在构造方法当中!
  • 还有注意一点this不可以在静态里用。

6.代码块

我们前面看到字段的初始化方式有

  1. 直接就地初始化
  2. 使用构造方法初始化

那么还有一种初始化,是使用代码块初始化

6.1 什么是代码块

写代码都写在{}里,这个就很容易理解吧

基本上所有的编程语言应该都一样...吧,使用{}定义的一段代码就是代码块

在Java中根据代码块定义的位置以及关键字,可分为以下四种:

  • 普通代码块(本地代码块)
  • 实例代码块(构造代码块)
  • 静态代码块
  • 同步代码块(等到多线程时候再讲)

重点是实例代码块和静态代码块。本地代码块就很简单,了解一下就行

6.2 普通代码块

定义在方法中的代码块

直接在main函数里单独写一个{}

没啥意义也很少见

public static void main(String[] args) {
    {
        //谁写代码这样写...
    }
}

6.3 实例代码块

定义在类中的代码块(不加修饰符)。也叫:构造代码块。构造代码块一般用于初始化实例成员变量

就很简单,普通代码块直接在main函数里单独写,构造代码块就直接在类里面单独写一个{}

class test {
    public int test;
    {
        this.test = 10;
        //实例代码块
    }
}

不过要注意:实例代码块优先于构造函数执行

6.4 静态代码块

和静态有关那就是static

使用static定义的代码块。一般用于初始化静态成员属性

class test {
    public static int test;
    static {
        test = 10;
        //静态代码块
    }
}

既然是静态的,那么也需要注意:

  • 静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
  • 静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。

6.5 调用代码块

那么我们就来看看代码块的调用,在类里面随便找地方写都可以

{
    System.out.println("实例代码块!");
}
 
static {
    System.out.println("静态代码块");
}

我们实例化多个对象看看

可以看到,我这里实例化的2个对象,只在第一次打印了静态代码块,而且顺序是:静态代码块-实例代码块-构造方法

那么我们不实例化对象,再打印下别的字段看看

这就很说明问题了

  • 静态代码块,只存在一份且只执行一次,不需要实例化对象也可以使用
  • 不管写在哪里,实例化对象都会按顺序调用代码块和构造方法

静态代码块对于静态成员属性的顺序

根据前面知道静态代码块最先调用

那么问题又来了

现在定义了一个静态成员变量,在静态代码块里外都赋值一次,会先打印那个呢?

回到我们的Person

静态代码块在后

class Person {
    public static int count = 10;
    
    static {
        count = 20;
        System.out.println("静态代码块");
    }
}

可以看到,静态代码块这5个字先打印且打印一次没问题,count的值为20,说明静态代码块是已经改变了count的值。

那么相对的,如果public static int count = 10;定义在后面呢?

静态代码块在前

class Person {
    static {
        count = 20;
        System.out.println("静态代码块");
    }
    
    public static int count = 10;
}

emm,也就是说

静态成员变量的值,如果都是静态的,那么和定义的先后顺序有关系

诶,等等,这里可没说绝对取决于定义的顺序

所以还有最后一个情况

只在静态代码块中赋初值

如果单看前面2个情况,理论上来说如果定义静态成员变量不赋值,那静态代码块在前面的话,这个静态成员变量应该还是0才对

class Person {
    //public static int count;
    
    static {
        count = 20;
        System.out.println("静态代码块");
    }
    
    public static int count;
}

这次,不管静态成员变量定义在前还是后,因为没有初始化,所以在静态代码块里都会赋予初始值。

注意

虽然前面有这么多实现情况

但是我们其实真的没必要特意去记...

一般情况下我们定义都是字段在前面,其他在后面...

7.匿名对象

顾名思义,就是这个对象没名字。既然没名字,那就只能用一次喽

我们前面写的Person

//Person person = new Person();//不创建有名字的对象了
new Person().eat();//new了个对象调用eat,只不过没名字,那就只能使用一次
new Person().sleep();//同理
System.out.printl(new Person());

匿名只是表示没有名字的对象。

  • 没有引用的对象称为匿名对象。
  • 匿名对象只能在创建对象时使用。
  • 如果一个对象只是用一次,后面不需要用了,可以考虑使用匿名对象。

匿名对象有很大的缺点

我实例化一个有名字的对象我随便用

我用匿名对象,这里用一下哪里用一下,如果就真的用一次那还好,用的多了那岂不是很麻烦,只要用第二次就得重新new

小头图版权:《ご注文はオトナココアですか?72》by KS 2021年10月29日下午5点04分 pid:93757282

广告位招租
最后修改:2021 年 11 月 11 日 03 : 26 AM
如果觉得我的文章对你有用,请喂饱我!(理直气壮)