Java面向对象(进阶)-- Object类的详细概述

news2024/11/17 5:43:08

文章目录

  • 一、如何理解根父类
  • 二、 Object类的方法
    • (1)引子
    • (2)Object类的说明
  • 三、了解的方法
    • (1)clone( )
      • 1、介绍
      • 2、举例
    • (2)finalize( )
      • 1、介绍
      • 2、举例
    • (3)getClass()
    • (4)hashCode()
  • 四、native关键字的理解
  • 五、重点的方法
    • (1)equals( )
      • 1、适用性
      • 2、java.lang.Object类中equals()的定义
      • 3、子类使用说明
      • 4、重写equals()方法
        • 手动实现
        • IDEA自动实现
      • 5、开发中使用说明
      • 6、区分==和equals()
    • (2)toString( )
      • 1、Object类中toString()的定义
      • 2、子类使用说明
      • 3、开发中的使用场景和说明
      • 4、实现toString()方法
        • 手动实现
        • IDEA自动实现
      • 5、总结
  • 六、练习题
    • (1)equals()练习题
      • 1、题一
      • 2、题二
      • 3、题三
    • (2)toString()练习题
      • 1、题一

一、如何理解根父类

类 java.lang.Object是类层次结构的根类,即所有其它类的父类。每个类都使用 Object 作为超类。

类的继承树关系:
image.png

  • Object类型的变量与除Object以外的任意引用数据类型的对象都存在多态引用
method(Object obj){} //可以接收任何类作为其参数

Person o = new Person();  
method(o);
  • 所有对象(包括数组)都实现这个类的方法。
  • 如果一个类没有特别指定父类,那么默认则继承自Object类。例如:
public class Person {
    ...
}
//等价于:
public class Person extends Object {
    ...
}

二、 Object类的方法

(1)引子

之前说继承性的时候就已经提到Object:

默认的父类:
Java中声明的类,如果没有显式的声明其父类时,则默认继承于java.lang.Object

若一个类没有显示声明,那么它的父类就是Object;若显示声明了,比如B是它的父类,但是B的父类没有显示写,那么也会继承于Object。

所以,任何一个类都直接或间接继承于Object类。Object类中的结构具有通用性,因为子类都能拿到。

(2)Object类的说明

  • 明确:java.lang.Object

我们自己也可以定义一个类,类名叫Object。(当然不建议这样做)

  • 任何一个Java类(除Object类)都直接或间接的继承于Object类
  • Object类称为java类的根父类
  • Object类中声明的结构(属性、方法等)就具有通用性
    • Object类中没有声明属性
    • Object类提供了一个空参的构造器
    • 之前说过子类对象实例化的全过程,造一个子类对象的时候,会直接或间接地调用到父类的构造器,父类又会调用父类的构造器,最终调用到Object类的构造器,Object就会留一个空参的构造器方便我们调用。
    • 重点关注:Object类中声明的方法
    • Object类的方法通过继承性都能被子类拿到,在权限允许的情况下,子类可以直接调用这些方法。那么任何一个类,在条件允许的情况下都可以调用这个方法,所以Object类的方法具备通用性。

看一下API文档:

image.png

三、了解的方法

image.png

  • 重点方法:equals() \ toString()
  • 了解方法:clone() \ finalize()
  • 目前不需要关注:getClass() – 反射 \ hashCode() – 集合 \ notify() \ notifyAll() \ wait() \ wait(xx) \ wait(xx,yy) – 多线程

(1)clone( )

1、介绍

clone():创建并返回当前类的复制品。调用这个方法的对象是this object。

若用x来调用clone()方法,得到一个复制品,把这个复制品与x用==来判断,结果是false。若是true那就麻烦了,因为是true就说明赋值的是地址。

这里复制的不是地址,而是真实得在堆空间中又造了一个对象。它们俩的地址一定不一样!内容(属性)是一样的。

image.png

2、举例

这里还涉及到接口的问题,简单看一下即可。

package com.atguigu07.object;
//Object类的clone()的使用
public class CloneTest {
    public static void main(String[] args) {
        Animal a1 = new Animal("小花");
        try {
            Animal a2 = (Animal) a1.clone();
            a2.setName("毛毛");

            System.out.println("原始对象:" + a1);
            System.out.println("a1[name = " + a1.getName() + "]");
            System.out.println("clone之后的对象:" + a2);
            System.out.println("a2[name = " + a2.getName() + "]");
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

class Animal implements Cloneable{
    private String name;

    public Animal() {
        super();
    }

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

Animal默认Object为父类:

image.png

这里重写了父类的方法,其实也没有干啥:

image.png

分别打印原来的和clone()之后的对象的地址和name,如下:

image.png

最终输出结果:

image.png

目前来看,创建对象就有两种方式了。第一种new一下构造器来造对象,第二种就是调用clone()。以后还会有其他的方式。

(2)finalize( )

1、介绍

  • 对象被回收时,系统自动调用该对象的 finalize() 方法。(不是垃圾回收器调用的,是本类对象调用的)
    • 永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。
  • 什么时候被回收:当某个对象没有任何引用时,JVM就认为这个对象是垃圾对象,就会在之后不确定的时间使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize()方法。
  • 子类可以重写该方法,目的是在对象被清理之前执行必要的清理操作。比如,在方法内断开相关连接资源。
    • 如果重写该方法,让一个新的引用变量重新引用该对象,则会重新激活对象。
  • 在JDK 9中此方法已经被标记为过时的。

image.png

2、举例

package com.atguigu07.object;

public class FinalizeTest {
    public static void main(String[] args) {
        Person p = new Person("Peter", 12);
        System.out.println(p);
        p = null;//此时对象实体就是垃圾对象,等待被回收。但时间不确定。
        System.gc();//强制性释放空间

        // try {
        //     Thread.sleep(1000);
        // } catch (InterruptedException e) {
        //     throw new RuntimeException(e);
        // }

    }
}

class Person{
    private String name;
    private int age;

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    //此方法调用的时机:当GC(垃圾回收器)要回收此对象时,调用如下的方法:
    //子类重写此方法,可在释放对象前进行某些操作
    //finalize()可能导致内部出现循环引用,导致此对象不能被回收。
    @Override
    protected void finalize() throws Throwable {
        System.out.println("对象被释放--->" + this);	//这里只是方便看一下是不是调用了它而已
    }
}

可以在编译器中看到这根线,其实在JDK9及以后就有这根线了:

image.png

这里重写了,可以看一下Object父类中的finalize()方法:

image.png

若将“项目依赖”改为1.8.0版本:

image.png

并且“语言标准”也改为1.8:

image.png

这个时候finalize上面的横线就没有了,因为它从9才开始过时。

换成17之后,并不是不能用,只是过时了而已。

💀那什么时候会调用finalize方法呢?回收的时候。那怎么才能让它回收呢?

public class FinalizeTest {
    public static void main(String[] args) {
        Person p = new Person("Peter", 12);
        System.out.println(p);
        p = null;//此时对象实体就是垃圾对象,等待被回收。但时间不确定。
        System.gc();//强制性释放空间
    }
}
class Person{
	//...
    
    //此方法调用的时机:当GC(垃圾回收器)要回收此对象时,调用如下的方法:
    //子类重写此方法,可在释放对象前进行某些操作
    //finalize()可能导致内部出现循环引用,导致此对象不能被回收。
    @Override
    protected void finalize() throws Throwable {
        System.out.println("对象被释放--->" + this);	//这里只是方便看一下是不是调用了它而已
    }
}

p指向堆空间的一个对象,将这根连接线抹除,此时堆空间的这个对象就是一个垃圾了。垃圾回收器GC若是此时回收的话,就会调用finalize方法。

image.png

但是不是随时都可以回收的,需要到一定程度才行,比如内存不够用了。

所以这里调用了一个方法:System.gc();强制调用gc。

但是尽管加上了这个方法,也不一定会调用到finalize()方法。

看一下输出结果,并没有显示finalize()方法中的输出语句,说明此时并没有调用它,也就是没有回收:

image.png

虽然System.gc();强制调用gc,但是垃圾回收器要我们等会儿,虽然我们着急要调用,垃圾回收器有个性,它不干,让我们再等会儿,等着等着程序就结束了,所以咱们就没有看到。

我们可以让程序先睡(sleep)上一秒钟等等咱,然后就可以看到GC执行它啦,如下:

package com.atguigu07.object;

public class FinalizeTest {
    public static void main(String[] args) {
        Person p = new Person("Peter", 12);
        System.out.println(p);
        p = null;//此时对象实体就是垃圾对象,等待被回收。但时间不确定。
        System.gc();//强制性释放空间

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }
}

class Person{
	//...
    
    //此方法调用的时机:当GC(垃圾回收器)要回收此对象时,调用如下的方法:
    //子类重写此方法,可在释放对象前进行某些操作
    //finalize()可能导致内部出现循环引用,导致此对象不能被回收。
    @Override
    protected void finalize() throws Throwable {
        System.out.println("对象被释放--->" + this);	//这里只是方便看一下是不是调用了它而已
    }
}

运行一下看看:
image.png

finalize有啥用呢?简单来说,就是这个对象临死之前还有什么遗言。

在最后当前对象要回收了,有没有拿着某些资源没有释放呐?你需要释放一下,要不然还回收不了嘞。

有点像之前学过的Scanner(),最后要close()释放一下,防止泄露。

finalize还有一个作用,就是当前对象临死之前要回收了,遗言是将一些数据保存下来,下一次再次创建新的对象的时候,这些数据可以重新拿来使用。

⚡注意

①finalize执行的时机是“临死之前”。

②那么究竟是谁调用的finalize()方法呢?

GC调用的吗?不准确。

自己调用的,自己的方法当然自己调用。当GC要回收的时候,我自己说还想再做点事。

所以是自己调用的,只不过是GC触发的而已。

③怎么给过时了呢?

之所以会过时,是因为它可能会导致一个问题。

finalize()可能导致内部出现循环引用,导致此对象不能被回收。
image.png

面试题:final(关键字) 、 finally(关键字) 、 finalize (方法名)的区别

根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。这里我们主要关注其中的6个。

(3)getClass()

public final Class<?> getClass():获取对象的运行时类型

image.png

因为Java有多态现象,所以一个引用数据类型的变量的编译时类型与运行时类型可能不一致,因此如果需要查看这个变量实际指向的对象的类型,需要用getClass()方法

public static void main(String[] args) {
	Object obj = new Person();
	System.out.println(obj.getClass());//运行时类型
}

结果:

class com.atguigu.java.Person

(4)hashCode()

public int hashCode():返回每个对象的hash值。(后续在集合框架章节重点讲解)
image.png

public static void main(String[] args) {
	System.out.println("AA".hashCode());//2080
    System.out.println("BB".hashCode());//2112
}

四、native关键字的理解

使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++等非Java语言实现的,并且被编译成了DLL,由Java去调用。

  • 本地方法是有方法体的,用c语言编写。由于本地方法的方法体源码没有对我们开源,所以我们看不到方法体
  • 在Java中定义一个native方法时,并不提供实现体。

1. 为什么要用native方法

Java使用起来非常方便,然而有些层次的任务用java实现起来不容易,或者我们对程序的效率很在意时,例如:Java需要与一些底层操作系统或某些硬件交换信息时的情况。native方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解Java应用之外的繁琐的细节。

2. native声明的方法,对于调用者,可以当做和其他Java方法一样使用

native method的存在并不会对其他类调用这些本地方法产生任何影响,实际上调用这些方法的其他类甚至不知道它所调用的是一个本地方法。JVM将控制调用本地方法的所有细节。

五、重点的方法

(1)equals( )

image.png

1、适用性

任何引用数据类型都可以使用。(基本数据类型不可以用,它和Object连继承关系都没有)

数组可以用:(包括后面要学习的接口)
image.png

2、java.lang.Object类中equals()的定义

举例

【UserTest.java】

package yuyi12;

/**
 * ClassName: UserTest
 * Package: yuyi12
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/12 0012 21:45
 */
public class UserTest {
    public static void main(String[] args) {
        //两个对象的属性值一样
        User u1=new User("Tom",12);
        User u2=new User("Tom",12);

        //u1调用equals()方法,将u2放入,结果是?
        System.out.println(u1.equals(u2));  //false
        //当前User并没有重写equals()这个方法,现在可以调用一定是来自于父类,此时User并没有写父类是谁,那么默认是Object
    }
}

class User{
    //属性
    String name;
    int age;

    //构造器
    public User(){

    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

输出结果:

image.png

当前User并没有重写equals()这个方法,现在可以调用一定是来自于父类,此时User并没有写父类是谁,那么默认是Object。

按住Ctrl键点击equals()方法,就会跳转到Object中equals()方法的声明,如下:

image.png

所以,

java.lang.Object类中equals()的定义:

public boolean equals(Object obj) {
    return (this == obj);
}

可以看到,java.lang.Object类中equals()中用到了==,所以这里就是判断一下u1与u2的地址值是否相同,如下:(很显然u1与u2是两个对象,地址值不同,所以输出false)

System.out.println(u1.equals(u2));  //false

3、子类使用说明

  • 自定义的类在没有重写Object中equals()方法的情况下,调用的就是Object类中声明的equals(),比较两个

对象的引用地址是否相同。(或比较两个对象是否指向了堆空间中的同一个对象实体)
平时开发中要是自定义类的话,要是调用equals(),一般也得重写。
比如刚才的例子,若是直接使用Object类中的equals()方法,就和==结果一致了,那还不如直接使用==

System.out.println(u1.equals(u2));  //false
System.out.println(u1==u2);

若平时想调用equals()方法,肯定也是想比较内容的,所以也得重写。

  • 对于像String(字符串的字符数组是否一样)、File(对应文件是不是同一个)、Date(对象是不是指的是同一个时间)和包装类等,它们都重写了Object类中的equals()方法,用于比较两个对象的实体内容是否相等。

【举例】

String

String除了可以正常声明之外,还可以new,比如:

public class UserTest {
    public static void main(String[] args) {
        String str1=new String("hello");
        String str2=new String("hello");
        System.out.println(str1==str2); //false
        System.out.println(str1.equals(str2));  //true
    }
}

输出结果:
image.png

很明显,这里String类调用的并不是Object类中的equals()方法(因为Object类中的equals()方法与==结果一致)。

按住Ctrl键点击equals()方法,就会跳转到String类中对equals()方法的重写,如下:

image.png

随着JDK版本的迭代,这个代码写的越发看不懂了,我们可以看一下JDK8版本的。如下:

public boolean equals(Object anObject){ //形参anObject,这个方法是Object中定义的,Object中定义的形参是Object,所以String重写的时候,名和形参都要与父类一样,所以这里的形参也是Object

    //若两个对象的地址一样,直接返回true
    if(this==anObject){ 
        return true;
    }
    
    //若两个对象的地址不一样,就是两个对象
    if(anObject instanceof String){ //判断一下参数是不是String类型,若是则进入if,否则不执行if直接输出下一条语句,返回false
        String anotherString=(String)anObject;  //强转
        int n=value.length; //字符串(String)在底层存储的是很多字符(char)构成的数组,这个数组叫value
    
        //想要看看两个字符串内容是否相等,就是比较两个数组是不是每一个字符都一样
        if(n == anotherString.value.length){    //先判断两个数组长度是否一致,若不一致直接结束,不用再比较
            char v1[]=value;    //将调用equals()方法的数组拿过来
            char v2[]=anotherString.value;  //将形参anObject的数组拿过来
            int i=0;
            while(n-- !=0){
                if(v1[i] != v2[i]){ //两个数组一个一个比较,只要有一个位置不一样,就false
                    return false;
                }
                i++;
            }
            return true;
        }
    }
}

File

类似String这种场景还是很多的,比如File

public class UserTest {
    public static void main(String[] args) {
        File file1=new File("d:\\abc.txt"); //d盘下这个文件可能不存在,现在只是内存层面来说
        File file2=new File("d:\\abc.txt");
        System.out.println(file1.equals(file2));
    }
}

对于File来说,equals()方法也重写了,比较的就是它们地址值是不是一样,指向的是不是同一个文件。所以此时输出结果是true,如下:
image.png

4、重写equals()方法

平时使用equals()方法时,需要重写一下,否则就和==一致了,并没有调用的必要。

怎么重写呢?

父类Object中的equals()方法如下:

public boolean equals(Object obj) {
	return (this == obj);
}
手动实现

【重写equals()方法】

方式一:

//重写equals()方法

@Override
public boolean equals(Object obj) {
    //若两个对象的地址一样,直接返回true
    if(this==obj){
        return true;
    }
    //若两个对象的地址不一样,就是两个对象
    if(obj instanceof User){    //判断一下参数obj是不是User类型,若是则进入if,否则不执行if直接输出下一条语句,返回false
        User user=(User) obj;//若是User,则强转
        if(this.age==user.age && this.name.equals(user.name)){  //若name与age都相等,则返回true
            return true;
        }else{  //若是name与age有一个不相等,则返回false
            return false;
        }
    }else{
        return false;
    }
}

注意一下这里的写法:(有个地方不小心把user的u写成大写了,不好意思~)

image.png

方式二:

//重写equals()方法

    @Override
    public boolean equals(Object obj) {
        //若两个对象的地址一样,直接返回true
        if(this==obj){
            return true;
        }
        //若两个对象的地址不一样,就是两个对象
        if(obj instanceof User){    //判断一下参数obj是不是User类型,若是则进入if,否则不执行if直接输出下一条语句,返回false
            User user=(User) obj;//若是User,则强转
            
            //方式1:
            /*if(this.age==user.age && this.name.equals(user.name)){  //若name与age都相等,则返回true
                return true;
            }else{  //若是name与age有一个不相等,则返回false
                return false;
            }*/
            
            //方式2:
            return this.age==user.age && this.name.equals(user.name);
        }else{
            return false;
        }
    }

现在再来看一下整体的代码:

package yuyi12;

public class UserTest {
    public static void main(String[] args) {
        //两个对象的属性值一样
        User u1=new User("Tom",12);
        User u2=new User("Tom",12);

        //u1调用equals()方法,将u2放入,结果是?
        System.out.println(u1.equals(u2));  //false--->true
        System.out.println(u1==u2);
        
    }
}

class User{
    //属性
    String name;
    int age;

    //构造器
    public User(){

    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //重写equals()方法
    @Override
    public boolean equals(Object obj) {
        //若两个对象的地址一样,直接返回true
        if(this==obj){
            return true;
        }
        
        //若两个对象的地址不一样,就是两个对象
        if(obj instanceof User){    //判断一下参数obj是不是User类型,若是则进入if,否则不执行if直接输出下一条语句,返回false
            User user=(User) obj;//若是User,则强转

            //方式1:
            /*if(this.age==user.age && this.name.equals(user.name)){  //若name与age都相等,则返回true
                return true;
            }else{  //若是name与age有一个不相等,则返回false
                return false;
            }*/

            //方式2:
            return this.age==user.age && this.name.equals(user.name);
        }else{
            return false;
        }
    }
}

再次输出结果,是true,如下:
image.png


IDEA自动实现

由于equals()方法在开发中比较常用,所以可以不用自己手写啦,可以用编译器自动生成。

按快捷键“Alt+Insert”,跳出一个框,点击“equals()”:

image.png

直接“下一步”:

image.png

这里我们就当只有两个属性都相同才算“equals()”,可以根据需要选择:

image.png

一直“下一步”,然后“创建”即可:(hashCode()暂时不用管)

image.png

然后就可以自动生成啦,如下:(和我们刚才手写的有点区别,但是功能是一样的)

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return age == user.age && Objects.equals(name, user.name);
}

5、开发中使用说明

  • 实际开发中,针对于自定义的类,常常会判断两个对象是否equals(),而此时主要是判断两个对象的属性值是否相等。

所以:我们要重写Object类的equals()方法。

  • 如何重写:
    • 手动自己实现
    • 调用IDEA自动实现(推荐)

以后开发中,可以自动生成它。

建议大家还是练一练,第一锻炼逻辑,第二以后有个需求是判断两个对象谁大谁小,也需要写类似这里的逻辑。

6、区分==和equals()

= =

==:运算符

使用范围:基本数据类型、引用数据类型

<1>基本数据类型:判断数据值是否相等

举例

int i1 = 10;
int i2 = 10;
sout(i1 == i2);//true

char c1 = 'A';
int i3 = 65;
sout(c1 == i3);//true  char自动类型提升为int

float f1 = 12.0F;
int i4 = 12;
sout(f1 == i4);//true	int类型自动提升为float

用“==”进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错。

基本类型比较值,只要两个变量的值相等,即为true。

<2>引用数据类型变量:比较两个引用变量的地址值是否相等。(或比较两个引用是否指向同一个对象实体)

举例

Person p1=new Person();  	    
Person p2=new Person();
if (p1==p2){}

引用类型比较引用(是否指向同一个对象),只有指向同一个对象时,==才返回true。

equals()

equals():方法

  • 使用范围:只能使用在引用数据类型上。(包括数组)
  • 具体使用:对于类来说,重写equals()和不重写equals()的区别。

【数组应用举例】

package yuyi12;

public class UserTest {
    public static void main(String[] args) {
        //数组上使用equals()
        int[] arr=new int[10];
        System.out.println(arr.equals(new int[20]));    //这里没有重写之说,用的就是Object中的==,输出false
        System.out.println(arr.equals(new int[10]));
    }
}

输出结果:
image.png


**equals():**所有类都继承了Object,也就获得了equals()方法。还可以重写。

  • 只能比较引用类型,Object类源码中equals()的作用与“==”相同:比较是否指向同一个对象。

image.png

  • 格式:obj1.equals(obj2)
  • 特例:当用equals()方法进行比较时,对类File、String、Date及包装类(Wrapper Class)来说,是比较类型及内容而不考虑引用的是否是同一个对象;
    • 原因:在这些类中重写了Object类的equals()方法。
  • 当自定义使用equals()时,可以重写。用于比较两个对象的“内容”是否都相等
  • 重写equals()方法的原则
    • 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
    • 自反性:x.equals(x)必须返回是“true”。
    • 传递性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
    • 一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
    • 任何情况下,x.equals(null),永远返回是“false”;
      x.equals(和x不同类型的对象)永远返回是“false”。

高频面试题:==equals的区别

从面试的反馈,85%的求职者“理直气壮”的回答错误…

  • == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址
  • equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。
  • 具体要看自定义类里有没有重写Object的equals方法来判断。
  • 通常情况下,重写equals方法,会比较类中的相应属性是否都相等。

(2)toString( )

image.png

1、Object类中toString()的定义

举例

【ToStringTest.java】

package yuyi16;

/**
 * ClassName: ToStringTest
 * Package: yuyi16
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 16:16
 */
public class ToStringTest {
    public static void main(String[] args) {
        User u1=new User("Tom",12);
        System.out.println(u1.toString());
    }
}


class User{
    String name;
    int age;

    //构造器
    public User() {

    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //方法
}

输出结果:
image.png

u1在User(继承于Object)没有重写ToString的时候,它调用的就是Object里面的ToString方法。如下:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

解释一下:

image.png

我们可以看到输出结果与直接输出u1的结果一致,如下:

public class ToStringTest {
    public static void main(String[] args) {
        User u1=new User("Tom",12);
        System.out.println(u1.toString());  //yuyi16.User@4eec7777
        System.out.println(u1); //yuyi16.User@4eec7777
    }
}

这是为啥呢?其实可以看一下println内部源码:(虽然这里写的是u1,但是实际上最终调用的也是toString)

问题4.gif

2、子类使用说明

  • 自定义的类,在没有重写Object类的toString()的情况下,默认返回的是当前对象的地址值
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
  • 像String、File、Date或包装类等Object的子类,它们都重写了Object类的toString(),在调用toString()时,返回当前对象的实体内容

举例1

public class ToStringTest {
    public static void main(String[] args) {
        String s1=new String("hello");
        System.out.println(s1.toString());
    }
}

输出结果:
image.png

可以看到,输出的不是地址值,而是实体内容。为啥呢?很简单,重写了呗。

举例2

package yuyi16;
import java.io.File;

public class ToStringTest {
    public static void main(String[] args) {
        File file =new File("d:\\abc.txt");
        System.out.println(file);
    }
}

输出结果:
image.png
可以看到打印的是文件的路径而不是地址值。

举例3

package yuyi16;

import java.util.Date;

public class ToStringTest {
    public static void main(String[] args) {
        Date date=new Date();
        System.out.println(date);
    }
}

输出结果:
image.png

可以看到,打印的也不是地址值,而是当前生成该对象的时间。

3、开发中的使用场景和说明

  • 平时我们在调用System.out.println()打印对象引用变量时,其实就调用了对象的toString()
  • 习惯上,开发中对于自定义的类在调用toString()时,也希望显示其对象的实体内容,而非地址值。这时候,就需要重写Object类中的toString()。

4、实现toString()方法

手动实现
//手动实现toString方法
    @Override
    public String toString() {
        //习惯上先会留一个类型
        return "User{ name = " + name + ",age = " + age + "}";
    }

整体代码:

package yuyi16;

public class ToStringTest {
    public static void main(String[] args) {
        User u1=new User("Tom",12);
        System.out.println(u1.toString());  //yuyi16.User@4eec7777 --> User{ name = Tom,age = 12}
        System.out.println(u1); //yuyi16.User@4eec7777 --> User{ name = Tom,age = 12}
    }
}

class User{
    String name;
    int age;

    //构造器
    public User() {

    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //手动实现toString方法
    @Override
    public String toString() {
        //习惯上先会留一个类型
        return "User{ name = " + name + ",age = " + age + "}";
    }
}

输出结果:
image.png

现在一看就知道里面的内容是啥了,一般以后就是这样来做。

IDEA自动实现

按快捷键“Alt+Insert”,跳出一个框,点击“toString()”:

image.png

选择想要显示的即可,点击“确定”:

image.png

然后就会自动生成啦:

//自动生成

@Override
public String toString() {
    return "User{" +
    "name='" + name + '\'' +
    ", age=" + age +
    '}';
}

整体代码:

package yuyi16;

public class ToStringTest {
    public static void main(String[] args) {
        User u1=new User("Tom",12);
        System.out.println(u1.toString());  //yuyi16.User@4eec7777 --> User{ name = Tom,age = 12}
        System.out.println(u1); //yuyi16.User@4eec7777 --> User{ name = Tom,age = 12}
    }
}

class User{
    String name;
    int age;

    //手动实现toString方法
    /*@Override
    public String toString() {
        //习惯上先会留一个类型
        return "User{ name = " + name + ",age = " + age + "}";
    }*/


    //自动生成
    @Override
    public String toString() {
        return "User{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
    }
}

输出结果:
image.png

5、总结

方法签名:public String toString()

① 默认情况下,toString()返回的是“对象的运行时类型 @ 对象的hashCode值的十六进制形式"

② 在进行String与其它类型数据的连接操作时,自动调用toString()方法

Date now=new Date();
System.out.println(“now=+now);  //相当于
System.out.println(“now=+now.toString());

③ 如果我们直接System.out.println(对象),默认会自动调用这个对象的toString()

因为Java的引用数据类型的变量中存储的实际上时对象的内存地址,但是Java对程序员隐藏内存地址信息,所以不能直接将内存地址显示出来,所以当你打印对象时,JVM帮你调用了对象的toString()。

④ 可以根据需要在用户自定义类型中重写toString()方法

如String 类重写了toString()方法,返回字符串的值。

s1="hello";
System.out.println(s1);//相当于System.out.println(s1.toString());

例如自定义的Person类:

public class Person {  
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

六、练习题

(1)equals()练习题

1、题一

【Account.java】

package yuyi13;

/**
 * ClassName: Account
 * Package: yuyi13
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 10:04
 */
public class Account {
    //属性
    private double balance; //余额

    //方法
    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    //构造器
    public Account() {
    }

    public Account(double balance) {
        this.balance = balance;
    }
}

【Customer.java】

package yuyi13;

/**
 * ClassName: Customer
 * Package: yuyi13
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 10:17
 */
public class Customer {
    //属性
    private String name;
    private int age;
    private Account acct;

    //方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public Account getAcct() {
        return acct;
    }

    public void setAcct(Account acct) {
        this.acct = acct;
    }

    //构造器
    public Customer() {
    }

    public Customer(String name, int age, Account acct) {
        this.name = name;
        this.age = age;
        this.acct = acct;
    }
}

【CustomerTest.java】

package yuyi13;

/**
 * ClassName: CustomerTest
 * Package: yuyi13
 * Description:
 *说明:判断两个Customer对象是否equals(),除了Customer类需要重写equals()之外,其内部的类类型的属性
 *     所在的类,也需要重写equals()
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 10:18
 */
public class CustomerTest {
    public static void main(String[] args) {
        Customer c1=new Customer("Tom",12,new Account(2000));
        Customer c2=new Customer("Tom",12,new Account(2000));

        System.out.println(c1.equals(c2));
        System.out.println(c1 == c2);
    }
}

输出结果:
image.png

现在我想比较一下c1与c2的属性是否相同,就需要重写equals()方法。

在【Customer.java】中自动生成:

package yuyi13;

import java.util.Objects;

public class Customer {
    //属性
    private String name;
    private int age;
    private Account acct;

    //重写equals()方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Customer customer = (Customer) o;
        return age == customer.age && Objects.equals(name, customer.name) && Objects.equals(acct, customer.acct);
    }
    //...
}

现在返回【Customer.java】中再次执行,发现结果还是false

image.png

此时equals()方法已经重写过了,为啥结果还是false呢?

Account是我们自定义的类,在equals()中需要调Account中的equals()方法,而现在Account类没有重写equals()方法,所以c1与c2的Account类的属性比较的是地址,地址显然不一样,所以结果是false。

image.png

如果在自定义类里面使用了自定义类的属性,而且想重写equals()方法并且用到它了,那么这个属性也得重写。

所以在【Account.java】中也要对equals()方法重写:

package yuyi13;

public class Account {
    //属性
    private double balance; //余额

    //重写equals()方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Account account = (Account) o;
        return Double.compare(account.balance, balance) == 0;
    }
	//...
}

现在返回【Customer.java】中再次执行,发现结果是true

image.png

判断两个Customer对象是否equals(),除了Customer类需要重写equals()之外,其内部的类类型的属性所在的类,也需要重写equals()。

此例中String本身就已经重写过了,所以我们没有感受到,但我们自定义一个类Account的属性,就需要重写equals()方法。

2、题二

🌋题目描述

编写Order类,有int型的orderId,String型的orderName,相应的getter()和setter()方法,两个参数的构造器,

重写父类的equals()方法:public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等。

💨代码

【Order.java】

package yuyi14;

/**
 * ClassName: Order
 * Package: yuyi14
 * Description:
 *  编写Order类,有int型的orderId,String型的orderName,相应的getter()和setter()方法,两个参数的构造器,
 *  重写父类的equals()方法:public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等。
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 14:26
 */
public class Order {
    //属性
    private int orderId;
    private String orderName;

    //构造器
    public Order() {
    }

    public Order(int orderId, String orderName) {
        this.orderId = orderId;
        this.orderName = orderName;
    }

    //方法
    public int getOrderId() {
        return orderId;
    }

    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    //手写equals()方法
    @Override
    public boolean equals(Object obj) { //equals形参之所以是Object类,是因为无法确定后续main中调用时,equals到底和谁进行比较,所以才有Object这个顶层父类比较
        if(this==obj){  //判断当前对象和形参是不是同一个对象,若地址一样,直接返回true即可
            return true;
        }
        if(obj instanceof Order){
            //判断obj是不是Order类型,若是,则强转 (因为obj的引用形式是Object,得强转成引用形式是Order的,才能调用引用形式的方法,否则调用的就是父类Object的方法)
            Order order=(Order)obj; //强转

            //两个属性都相同才算一致
            return this.orderId==order.orderId && this.orderName.equals(order.orderName);   //orderId是基本数据类型,用==即可比较;orderName是String类型,String类型里面的equals方法重写了,比较的是字符串里面每个字符的内容
            //通过orderName属性调用equals()方法时,有可能这个属性的值是null,
            // 若是null调用equals就是空指针了,那么要不要加一个非空的判断?在该属性是非空的情况下去调用equals(使得程序健壮性更好)
        }else{
            return false;
        }

    }
}

【OrderTest.java】

package yuyi14;

/**
 * ClassName: OrderTest
 * Package: yuyi14
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 15:04
 */
public class OrderTest {
    public static void main(String[] args) {
        //直接赋值
        Order order1=new Order(1001,"Jack");
        Order order2=new Order(1001,"Jack");    //String用直接赋值的方式(字面量的方式)
        System.out.println(order1.equals(order2));  //true

        //new两个不同字符串对象
        Order order3=new Order(1002,new String("Luis"));
        Order order4=new Order(1002,new String("Luis"));
        System.out.println(order3.equals(order4));  //true
    }
}

👻运行结果
image.png

⚡注意

这段代码希望大家可以看懂:

package yuyi14;

public class Order {
    //属性
    private int orderId;
    private String orderName;

    //...
    //手写equals()方法
    @Override
    public boolean equals(Object obj) { //equals形参之所以是Object类,是因为无法确定后续main中调用时,equals到底和谁进行比较,所以才有Object这个顶层父类比较
        if(this==obj){  //判断当前对象和形参是不是同一个对象,若地址一样,直接返回true即可
            return true;
        }
        if(obj instanceof Order){
            //判断obj是不是Order类型,若是,则强转 (因为obj的引用形式是Object,得强转成引用形式是Order的,才能调用引用形式的方法,否则调用的就是父类Object的方法)
            Order order=(Order)obj; //强转

            //两个属性都相同才算一致
            return this.orderId==order.orderId && this.orderName.equals(order.orderName);   //orderId是基本数据类型,用==即可比较;orderName是String类型,String类型里面的equals方法重写了,比较的是字符串里面每个字符的内容
            //通过orderName属性调用equals()方法时,有可能这个属性的值是null,
            // 若是null调用equals就是空指针了,那么要不要加一个非空的判断?在该属性是非空的情况下去调用equals(使得程序健壮性更好)
        }else{
            return false;
        }

    }
}

若这个地方改为了==

image.png

则运行结果是不一样的,因为两个对象的地址值不一样:(第一个输出还是true,因为地址值一样)

image.png

//补充
String str1="AA";
String str2="AA";
System.out.println(str1==str2); //true

字符串常量池,它们使用的是池子中的同一个,所以地址是相同的。输出为true,如下:

image.png

3、题三

🌋题目描述

请根据以下代码自行定义能满足需要的MyDate类,在MyDate类中覆盖equals方法,

使其判断当两个MyDate类型对象的年月日都相同时,结果为true,否则为false。

public boolean equals(Object o)

【EqualsTest.java】

public class EqualsTest {
    public static void main(String[] args) {
        MyDate m1 = new MyDate(14, 3, 1976);
        MyDate m2 = new MyDate(14, 3, 1976);
        if (m1 == m2) {
            System.out.println("m1==m2");
        } else {
            System.out.println("m1!=m2"); // m1 != m2
        }

        if (m1.equals(m2)) {
            System.out.println("m1 is equal to m2");// m1 is equal to m2
        } else {
            System.out.println("m1 is not equal to m2");
        }
    }
}

💨代码

①没有重写equals方法

【MyDate.java】

package yuyi15;

/**
 * ClassName: MyDate
 * Package: yuyi15
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 15:31
 */
public class MyDate {
    //属性
    private int day;
    private int month;
    private int year;

    //构造器
    public MyDate(){

    }
    public MyDate(int day, int month, int year) {
        this.day = day;
        this.month = month;
        this.year = year;
    }

    //方法
    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }
}

运行结果:
image.png

因为m1与m2的地址不同,而且此时equals没有重写(相当于==),所以输出的是else中的内容。

②重写equals方法

【MyDate.java】

package yuyi15;

public class MyDate {
    //属性
    private int day;
    private int month;
    private int year;

    //手写equals()
    @Override
    public boolean equals(Object obj) {
        if(this==obj){
            return true;
        }
        if(obj instanceof MyDate){
            MyDate mydate=(MyDate) obj;
            return this.getDay()==mydate.day &&this.getMonth()==mydate.month &&this.getYear()==mydate.year;
        }
        return false;
    }
}

运行结果:
image.png

(2)toString()练习题

1、题一

🌋题目描述

定义两个类,父类GeometricObject代表几何形状,子类Circle代表圆形。

写一个测试类,创建两个Circle对象,判断其颜色是否相等;利用equals方法判断其半径是否相等;

利用toString()方法输出其半径。

类关系图:
image.png

💨代码

【GeometricObject.java】

package yuyi17;

/**
 * ClassName: GeometricObject
 * Package: yuyi17
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 17:28
 */
public class GeometricObject {
    //属性
    protected String color;
    protected double weight;

    //构造器
    public GeometricObject() {
        color="white";
        weight=1.0;
    }

    public GeometricObject(String color, double weight) {
        this.color = color;
        this.weight = weight;
    }

    //方法
    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }
}

【Circle.java】

package yuyi17;

/**
 * ClassName: Circle
 * Package: yuyi17
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 17:28
 */
public class Circle extends GeometricObject{
    //属性
    private double radius;


    //构造器
    public Circle() {
        color="white";
        weight=1.0;
        radius=1.0;
    }

    public Circle(double radius) {
        color="white";
        weight=1.0;
        this.radius = radius;
    }

    public Circle(String color, double weight, double radius) {
        super(color, weight);
        this.radius = radius;
    }


    //方法
    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    //计算圆的面积
    public double findArea(){
        return 3.14*radius*radius;
    }

    //重写equals方法,比较两个圆的半径是否相等,若相等则返回true
    //手写
    public boolean equals(Object obj){
        if(this==obj){
            return true;
        }
        if(obj instanceof Circle){
            Circle c=(Circle) obj;  //强转
            return this.radius == c.radius;
        }
        return false;
    }

    //重写toString方法,输出圆的半径
    //手写
    public String toString(){
        return "Circle [radius = "+ radius + "]";
    }

}

【CircleTest.java】

package yuyi17;

/**
 * ClassName: CircleTest
 * Package: yuyi17
 * Description:
 *  写一个测试类,创建两个Circle对象,判断其颜色是否相等;利用equals方法判断其半径是否相等;
 *  利用toString()方法输出其半径。
 * @Author 雨翼轻尘
 * @Create 2023/11/13 0013 22:28
 */
public class CircleTest {
    public static void main(String[] args) {
        Circle c1=new Circle(2.3);
        Circle c2=new Circle("red",2.0,3.4);

        System.out.println("颜色是否相等? " + c1.getColor().equals(c2.getColor()));    //getColor返回的是String类型,String类型是重写过的equals,所以可以直接调用

        System.out.println("半径是否相等? "+ c1.equals(c2));

        System.out.println(c1);
        System.out.println(c1.toString());

    }
}

👻输出结果
image.png

⚡注意

当写好父类【GeometricObject.java】之后,在子类【Circle.java】中用IDEA自动写入构造器时,首先要选择是哪个父类构造器:(因为此时父类有两个构造器)

image.png

此时若要写子类空参构造器,就直接选择第一个父类空参的构造器GeometricObject(),然后要的是空参的,选择最上面那个,点击“确定”,如下:

image.png

就可以自动生成一个子类空参构造器:

public class Circle extends GeometricObject{
    //属性
    private double radius;

    //构造器
    public Circle() {
        
    }
}

重写方法:

//重写equals方法,比较两个圆的半径是否相等,若相等则返回true
//手写
public boolean equals(Object obj){
    if(this==obj){
        return true;
    }
    if(obj instanceof Circle){
        Circle c=(Circle) obj;  //强转
        return this.radius == c.radius;
    }
    return false;
}

//重写toString方法,输出圆的半径
//手写
public String toString(){
    return "Circle [radius = "+ radius + "]";
}

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1205458.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows系统用于 SDN 的软件负载均衡器 (SLB)

适用于&#xff1a;Azure Stack HCI 版本 22H2 和 21H2&#xff1b;Windows Server 2022、Windows Server 2019、Windows Server 2016 软件负载均衡器包括哪些内容&#xff1f; 软件负载均衡器提供以下功能&#xff1a; 适用于北/南和东/西 TCP/UDP 流量的第 4 层 (L4) 负载均…

什么是会话固定以及如何在 Node.js 中防止它

什么是会话固定以及如何在 Node.js 中防止它 在深入讨论之前&#xff0c;我们需要了解会话是什么以及会话身份验证如何工作。 什么是会话&#xff1f; 正如我们所知&#xff0c;HTTP 请求是无状态的&#xff0c;这意味着当我们发送登录请求时&#xff0c;并且我们有有效的用…

@CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思

@CacheInvalidate 注解是 JetCache 框架提供的注解,它是由阿里巴巴开源的组织 Alibaba Group 开发和维护的。JetCache 是一款基于注解的缓存框架,提供了丰富的缓存功能和灵活的配置选项,可用于增强应用程序的性能和可扩展性。JetCache 支持多种缓存后端,包括内存缓存、Redi…

2023亚太杯数学建模C题思路分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

二十、泛型(6)

本章概要 问题 任何基本类型都不能作为类型参数实现参数化接口转型和警告重载基类劫持接口 自限定的类型 古怪的循环泛型自限定参数协变 问题 本节将阐述在使用 Java 泛型时会出现的各类问题。 任何基本类型都不能作为类型参数 正如本章早先提到的&#xff0c;Java 泛型的…

OpenCV 笔记(6):像素间的基本关系——邻域、邻接、通路、连通、距离

像素是图像的基本元素&#xff0c;像素与像素之间存在着某些联系&#xff0c;理解像素间的基本关系是数字图像处理的基础。常见的像素间的基本关系包括&#xff1a;邻域、邻接、通路、连通、距离。 Part11. 邻域 邻域表示了像素之间的连接关系。 像素(x,y)的邻域&#xff0c;是…

Linux技能篇-软链接和硬链接

文章目录 前言一、硬链接是什么&#xff1f;二、软链接是什么&#xff1f;三、硬链接和软链接的区别和共性1.区别2.共同点 总结 前言 在Linux系统中&#xff0c;有两个容易混淆的概念&#xff0c;就是软链接&#xff08;Soft Link&#xff09;和硬链接&#xff08;Hard Link&a…

android studio新版本gradle Tasks找不到assemble

最近需要打包arr&#xff0c;但android studio新版本为了加快编译速度&#xff0c;取消了gradle下的assemble任务&#xff0c;网上还没有博主更新解决方案&#xff0c;因此一直找不到解决方案&#xff0c;后来尝试如下操作才解决&#xff0c;方便后来者解决。 先将这里勾选上&…

vscode远程linux安装codelldb

在windows上使用vscode通过ssh远程连接linux进行c调试时&#xff0c;在线安装codelldb-x86_64-linux.vsix扩展插件失败&#xff0c;原因是linux服务器上的网络问题&#xff0c;所以需要进行手动安装。 首先在windows上下载&#xff1a; codelldb-x86_64-linux.vsix&#xff1b;…

GoldWave v6.78 绿色免费便携版功能介绍及使用说明

GoldWave v6.78 绿色免费便携版是一款集声音编辑、播放、录制与转换为一体的音频编辑工具&#xff0c;还可以对音频内容进行转换格式等处理。该软件支持许多格式的音频文件&#xff0c;包括WAV, OGG, VOC, IFF, AIF, AFC, AU, SND, MP3,MAT, DWD, SMP, VOX, SDS, AVI, MOV等音频…

vue v-model

一、为什么使用v-model&#xff1f; v-model指令可以在表单input、textarea以及select元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。本质上是语法糖&#xff0c;负责监听用户的输入事件来更新数据。 二、什么场景下会使用v-model&#xff1f; ①…

7.外部存储器,Cache,虚拟存储器

目录 一. 外部存储器 &#xff08;1&#xff09;磁盘存储器 1.磁盘的组成 2.磁盘的性能指标 3.磁盘地址 4.硬盘的工作过程 5.磁盘阵列 &#xff08;2&#xff09;固态硬盘&#xff08;SSD&#xff09; 二. Cache基本概念与原理 三. Cache和主存的映射方式 &#xff…

RabbitMQ-基础篇-黑马程序员

代码&#xff1a; 链接&#xff1a; https://pan.baidu.com/s/1nQBIgB_SbzoKu_XMWZ3JoA?pwdaeoe 提取码&#xff1a;aeoe 微服务一旦拆分&#xff0c;必然涉及到服务之间的相互调用&#xff0c;目前我们服务之间调用采用的都是基于OpenFeign的调用。这种调用中&#xff0c;调…

OCR转换技巧:如何避免图片转Word时出现多余的换行?

在将图片中的文字识别转换为Word文档时&#xff0c;我们很多时候时会遇到识别内容的一个自然段还没结束就换行的问题&#xff0c;这些就是我们常说的多余换行的问题。为什么会产生这个问题呢&#xff1f;主要是由于OCR返回的识别结果是按图片上的文字换行而换行&#xff0c;而不…

解决Mac配置maven环境后,关闭终端后环境失效的问题(适用于所有终端关闭后环境失效的问题)

目录 问题的原因 解决方式一、每次打开终端时输入&#xff1a;"source ~/.bash_profile"&#xff0c;这个方式比较繁琐 解决方式二、我们终端输入"vim ~/.zshrc"打开".zshrc"文件 1、我们输入以下代码&#xff1a; 2、首先需要按 " i…

【java:牛客每日三十题总结-7】

java:牛客每日三十题总结 总结如下 总结如下 执行流程如下&#xff1a;创建HttpServlet时需要覆盖doGet()和doPost请求 2. request相关知识 request.getParameter()方法传递的数据&#xff0c;会从Web客户端传到Web服务器端&#xff0c;代表HTTP请求数据&#xff1b;request.…

保姆级使用vuedraggable三方组件

第一步 引入vuedraggable npm i vuedraggable -S 第二步 直接使用&#xff0c;源码如下 <template><draggableclass"list-group"tag"ul"v-model"list"v-bind"{animation: 1000,group: description,disabled: false,ghostClass:…

软路由R4S+iStoreOS实现公网远程桌面局域网内电脑

软路由R4SiStoreOS实现公网远程桌面局域网内电脑 文章目录 软路由R4SiStoreOS实现公网远程桌面局域网内电脑简介 一、配置远程桌面公网地址配置隧道 二、家中使用永久固定地址 访问公司电脑具体操作方法是&#xff1a;2.1 登录页面2.2 再次配置隧道2.3 查看访问效果 简介 上篇…

Load-balanced-online-OJ-system 负载均衡的OJ系统项目

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 本项目Github地址 - Load-balanced-o…

pdf增强插件 Enfocus PitStop Pro 2022 mac中文版功能介绍

Enfocus PitStop Pro mac是一款 Acrobat 插件&#xff0c;主要用于 PDF 预检和编辑。这个软件可以帮助用户检查和修复 PDF 文件中的错误&#xff0c;例如字体问题、颜色设置、图像分辨率等。同时&#xff0c;Enfocus PitStop Pro 还提供了丰富的编辑工具&#xff0c;可以让用户…