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

文章目录

  • 一、如何理解根父类
  • 二、 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EasyPOI实现excel文件导出

EasyPOI真的是一款非常好用的文件导出工具&#xff0c;相较于传统的一行一列的数据导出&#xff0c;这种以实体类绑定生成的方式真的非常方便&#xff0c;也希望大家能够了解、掌握其使用方法&#xff0c;下面就用一个实例来简单介绍一下EasyPOI的使用。 1.导入依赖 <!-- e…

使用Python的requests库模拟爬取地图商铺信息

目录 引言 一、了解目标网站 二、安装requests库 三、发送GET请求 四、解析响应内容 五、处理异常和数据清洗 六、数据存储和分析 七、数据分析和可视化 八、注意事项和最佳实践 总结 引言 随着互联网的快速发展&#xff0c;网络爬虫技术已经成为获取数据的重要手段…

CSS特效009:音频波纹加载律动

总第 009 篇文章&#xff0c; 查看专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花…

Linux环境实现mysql所在服务器定时同步数据文件到备份服务器(异地容灾备份场景)

目录 概述 1、建立ssh连接 1.1、操作mysql所在服务器 1.2、操作备份文件服务器 2、创建脚本实现备份以及传输 3、配置定时任务 概述 应对异地容灾备份场景&#xff0c;mysql所在服务器和本分服务器需要建立ssh连接&#xff0c;每天mysql服务器通过定时任务执行脚本&…

OpenAI调查ChatGPT故障;向量搜索的优势与局限

&#x1f989; AI新闻 &#x1f680; OpenAI调查ChatGPT故障&#xff0c;发布新AI产品GPTs和GPT-4 Turbo 摘要&#xff1a;OpenAI的ChatGPT和其他服务出现故障&#xff0c;经过调查后发现是由于DDoS攻击导致的异常流量模式。OpenAI在首届开发者大会上发布了新的AI产品GPTs&am…

MATLAB | 官方举办的动图绘制大赛 | 第一周赛情回顾

嘿真的又是很久没见了&#xff0c;最近确实有点非常很特别小忙&#xff0c;今天带来一下MATHWORKS官方举办的迷你黑客大赛第三期(MATLAB Flipbook Mini Hack)的最新进展&#xff01;&#xff01;目前比赛已经刚好进行了一周&#xff0c;前两届都要求提交280个字符内的代码来生成…

老胡的周刊(第115期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 draw-a-ui[2] 利用 tldraw gpt-4-vision ap…

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

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

时序数据库 TDengine + 高级分析软件 Seeq,助力企业挖掘时序数据潜力

作为一款制造业和工业互联网&#xff08;IIOT&#xff09;高级分析软件&#xff0c;Seeq 支持在工艺制造组织中使用机器学习创新的新功能。这些功能使组织能够将自己或第三方机器学习算法部署到前线流程工程师和主题专家使用的高级分析应用程序&#xff0c;从而使单个数据科学家…

EasyDarwin开源流媒体服务器

文章目录 前言一、EasyDarwin 简介二、EasyDarwin 主要功能特点三、安装部署四、推拉流测试1、进入控制页面2、推流测试3、拉流测试 前言 本文介绍一个十分实用的高性能开源 RTSP 流媒体服务器&#xff1a;EasyDarwin。 一、EasyDarwin 简介 EasyDarwin 是基于 go 语言研发&a…

【广州华锐视点】海外制片人VR虚拟情景教学带来全新的学习体验

虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;是一种利用电脑模拟产生一个三维的虚拟世界&#xff0c;提供用户关于视觉、听觉、触觉等感官的模拟体验的技术。随着科技的进步&#xff0c;VR已经被广泛应用到许多领域&#xff0c;包括游戏、教育、医疗、房…

VuePress介绍及使用指南

VuePress是一个基于Vue.js的静态网站生成工具&#xff0c;它专注于以Markdown为中心的项目文档。VuePress具有简单易用的特性&#xff0c;同时提供了强大的自定义和扩展性。在本文中&#xff0c;我们将介绍VuePress的基本概念&#xff0c;并提供一个简单的使用指南。 什么是Vue…

Centos7安装mysql8.0.35(亲测)

今天在centos7上安装了mysql8&#xff0c;特此记录以作备忘。 说明&#xff1a; - 我安装的mysql版本&#xff1a;8.0.35 - centos版本&#xff1a;7 - 我的虚拟机没安装过mysql,如果之前安装过mysql记得卸载干净 - 卸载步骤&#xff1a; - rpm -qa|grep mysql (搜索mysql)比如…

自定义Graph Component:1.2-其它Tokenizer具体实现

本文主要介绍了Rasa中相关Tokenizer的具体实现&#xff0c;包括默认Tokenizer和第三方Tokenizer。前者包括JiebaTokenizer、MitieTokenizer、SpacyTokenizer和WhitespaceTokenizer&#xff0c;后者包括BertTokenizer和AnotherWhitespaceTokenizer。 一.JiebaTokenizer   Ji…

5 新的关键字

动态内存分配 回想C语言中&#xff0c;动态内存是怎么分配的&#xff1f;通过C库里面的malloc free去进行动态内存分配。 C通过new关键字进行动态内存申请&#xff0c;动态内存申请是基于类型进行的。 delete 关键字用于内存释放。 //变量申请 type* pointer new type; dele…

arcgis提取栅格有效边界

方法一&#xff1a;【3D Analyst工具】-【转换】-【由栅格转出】-【栅格范围】 打开一幅栅格数据&#xff0c;利用【栅格范围】工具提取其有效边界&#xff08;不包含NoData值&#xff09;&#xff1a; 方法二&#xff1a;先利用【栅格计算器】将有效值赋值为1&#xff0c;得到…

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline

模型简介 本基线模型共分为三个部分&#xff1a; 基于CNN的判断每张人脸是否是说话人的模型&#xff1b;基于Transformer-Encoder的判断同一段对话中不同轮次的说话人关系的模型&#xff1b;和使用上述两个预测结果求解二次型优化问题的说话人识别求解器。 基于CNN的判断每…

VSCode 好用的插件分享

文章目录 Introlistcode runner 【在文本编辑器中编辑好各类语言的源代码&#xff0c;然后一键运行】gitlens - 【git提交信息即时查看&#xff0c;类似IDEA中的 show annotation】还有更多&#xff0c;会日常补充。 Intro 大四毕业前&#xff0c;我只有一台dell latitude 455…

瑞萨e2studio(29)----SPI速率解析

瑞萨e2studio.29--SPI速率解析 概述视频教学时钟配置解析RA4M2的BRR值时钟速率7.5M下寄存器值3K下寄存器值 概述 在嵌入式系统的设计中&#xff0c;串行外设接口&#xff08;SPI&#xff09;的通信速率是一个关键参数&#xff0c;它直接影响到系统的性能和稳定性。瑞萨电子的…

No200.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…