JavaImprove--Lesson02--Object类,Objects工具类,封装类
一.Object类
Java中的Object
类是所有类的超类,它是Java类层次结构的根类。这意味着所有的类都直接或间接地继承自Object
类
equals(Object obj)
: 用于比较两个对象是否相等。默认实现是比较对象的引用,但可以通过重写此方法来比较对象的内部状态。hashCode()
: 返回对象的哈希码值,通常用于散列数据结构,如哈希表。toString()
: 返回对象的字符串表示形式。默认实现可能不提供足够的信息,因此经常被重写。clone()
: 创建并返回此对象的一个副本。默认实现是浅复制,可以通过重写clone()
方法和Cloneable
接口来实现深复制。finalize()
: 当垃圾收集器准备回收对象的内存时,会调用此方法。可以用于释放资源,但不建议依赖此方法,因为它不是保证会运行。
Object自带的方法有很多,但是常使用的就是toString,equals,clone方法
这些方法都是主要使用的方法,但是Object类是被任何类所继承或者间接继承的,所以说任何类都可以使用到这些方法
但是,作为子类大多数情况下并不是为了使用父类的方法,而是重写父类的方法,从而使这些方法能够适配子类
举个例子,如果不重写object类的方法,clone()就会一直克隆object类,很显然,大多数情况下,我们不需要使用克隆object,而是克隆当前类,就需要重写clone方法
toString方法
toString方法,如果不重写父类的方法,那么就还是调用父类的方法,父类的方法就是打印一些关于当前对象的类名和对象的hashcode
public class toStringDemo { private String name; private String clasName; private double grade; public toStringDemo() { } public toStringDemo(String name, String clasName, double grade) { this.name = name; this.clasName = clasName; this.grade = grade; } }
如上代码,没有重写父类的方法,我们在主方法调用toString方法
输出如下
我们重写toString方法:
注意,重写需要清楚是自己重写还是让编译器帮我们重写
自己重写就根据自己想让此方法输出什么,就diy就好了
编译器帮我们重写的toString方法是用来打印当前对象的属性值的,我们可以使用快捷键 alt + insert ,或者手动输入tosting,编译器会提示此方法
但是一般重写都是让编译器帮我们重写,因为大多数人使用toString方法都是想看看对象的内部属性内容的
重写toString方法:
@Override public String toString() { return "toStringDemo{" + "name='" + name + '\'' + ", clasName='" + clasName + '\'' + ", grade=" + grade + '}'; }
使用有参构造,再来获取一个对象后,调用toString方法
输出如下:
总结:大多数情况下,我们都会让编译器重写object类的toString方法,使其能打印一些类对象的内部细节
equals
equals方法是用来比较两个对象是否相等的,使用方法:对象 . equals(对象)
对象之间的比较方式是确定equals方法执行的关键,object方法自带的比较方式是比较内存地址,但是再Java中,使用new关键字创建的对象都不是单例模式
也就是每次new关键字实例化出来的对象都是新建的,所以他们有自己的内存地址
所以使用object类的equals方法比较结果都是false
我们重写equals方法后,可以根据自定义的方式来判断两个对象是否相等,我们判断的标准可以变为对象的属性值是否一一对应相等,如果不是才返回false
重写equals方法:
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; toStringDemo that = (toStringDemo) o; return Double.compare(that.grade, grade) == 0 && Objects.equals(name, that.name) && Objects.equals(clasName, that.clasName); }
这是编译器自动生成的equals方法,我们可以来看看这个方法的执行逻辑
if (this == o) return true;
这是equals方法的重写第一句,this调用此方法的对象,而o代表传入的对象
== 符号是用来判断地址是否相等的,如果这两个对象地址相等,那么肯定是一个对象,则返回true
if (o == null || getClass() != o.getClass()) return false;
第二句话先判断传入的对象是否为空,不为空且传入对象的类和this类是否属于一个类
如果不是一个类,那么不管怎么创建对象,两个类new出来的对象就一定是不同的对象,所以直接返回false
toStringDemo that = (toStringDemo) o; return Double.compare(that.grade, grade) == 0 && Objects.equals(name, that.name) && Objects.equals(clasName, that.clasName);
最后一段代码就是将两个对象的属性值进行依次比较,只要有一个不相等,就返回false,反之,都相等,返回ture
clone方法
这不是 Java代码实现的方法,而是c++写的方法
它可以实现对象克隆,它是在内存中操作的方法,Java本身不提供指针操作,所以使用c++的方法会更加的高效,它们可以操作内存,这些非Java写的代码一般存放再Java的jvm虚拟机的本地方法栈中
这个方法就重写就只能靠编译器重写了
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
这种写法是浅克隆,可以克隆一个一摸一样的对象出来,hashcode是不一样的,内容是一样的
关于深克隆和浅克隆可以看我的博客:GOF23--23种设计模式(二)
查看设计模式的原型模式部分,有深克隆和浅克隆的详解
二.Objects工具类
Objects
是 Java 中的一个实用工具类,它包含了一系列用于处理对象的方法。由于 Object
是所有类的超类,Objects
类中的方法可以用于任何 Java 对象。以下是一些 Objects
类中的常用方法:
- equals(): 用于比较两个对象是否相等。这个方法首先检查两个对象是否为同一个对象(即它们的引用是否相同),如果是,则返回
true
。如果不是,它会调用对象的equals()
方法。如果对象没有重写equals()
方法,则默认实现会比较对象的内存地址,而不是它们的内部状态。 - hashCode(): 返回对象的哈希码值。哈希码是一个整数,通常用于在哈希表等数据结构中存储对象。默认情况下,
hashCode()
方法返回对象的内存地址的整数表示,但也可以通过重写该方法来提供更合适的哈希码计算方式。 - toString(): 返回对象的字符串表示形式。默认情况下,这个方法返回对象的类名和内存地址的字符串表示形式,但也可以通过重写该方法来提供更有意义的字符串表示。
- hash(): 计算对象的哈希码值,前提是该对象实现了
hashCode()
方法。 - toString(Object obj): 返回对象的字符串表示形式,前提是该对象实现了
toString()
方法。
Objects类中的方法都是静态的,所以说,我们可以直接通过Objects . 方法使用这个工具类重点的方法
Objects类中的工具方法有很多,详细了解请款JDK帮助文档
equals方法
object的equals方法和objects的equals方法使用是不一样的
调用方式:
object的equals方法:对象 . equals(对象)
ObjectsDemo obj1 = new ObjectsDemo(); ObjectsDemo obj2 = new ObjectsDemo(); obj1.equals(obj2);
objects的equals方法: Objects.equals(对象,对象)
ObjectsDemo obj1 = new ObjectsDemo(); ObjectsDemo obj2 = new ObjectsDemo(); //静态方法,直接点出来 Objects.equals(obj1,obj2);
object的equlas方法需要可以重写,但是objects的equals方法是静态方法,是架构师写好的,我们只能使用,不用重写
object
//object类的equals public boolean equals(Object obj) { return (this == obj); }
objects
//Objects类的equals public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); }
我们可以看到objects类的方法更加的专业
它有非空校验,但是object的方法没有
obj1=null; obj1.equals(obj2);
object的比较方式没有校验,如上比较后,会报错:
而使用objects的equals方法比较:
obj1=null; System.out.println(Objects.equals(obj1, obj2));
总结:
Objects工具类中的方法更加专业,所以如果不想自己重写object的方法,可以使用Objects工具类中的方法
三.封装类(包装类)
众所周知,Java 是一门面向对象的编程语言,所谓万物皆对象
但是Java中又必须有一些不是对象的基本类型
编程语言一共有八个基本数据类型,对于这些不是对象,且必须存在面向对象的编程语言的类型怎么办呢?
这时候Java就拥有了基本类型的包装类,每一个基本类型都有它的包装类,它们的包装类就是对象类型
Java中的包装类(Wrapper class)是对基本数据类型的封装,它们为每种基本数据类型提供了对应的包装类。这些包装类在Java标准库中定义,并且都是java.lang
包的一部分。
以下是Java中的8种基本数据类型及其对应的包装类:
- byte -> Byte
- short -> Short
- int -> Integer
- long -> Long
- float -> Float
- double -> Double
- char -> Character
- boolean -> Boolean
我们在泛型中讲到,泛型中不支持基本类型的,所以有了包装类,我们可以使用包装类
举个例子:ArrayList<>泛型就只接收对象类型
ArrayList<Integer> list = new ArrayList<>();
使用Interger对象,就可以毫无问题的传入int类型
但是有没有想过,为什么我们传入的是int类型,而ArrayList<>中又是Interger类型,但是任然可以装进去呢?
这就涉及到Java的另外一个领域了,自动拆箱和装箱
自动装箱指的是,我们可以直接将int型变量赋给Integer对象,有JVM帮我们调用相关方法
如下:
Integer a = 12;
Integer b = Integer.valueOf(12);
这两个命名方式是一样的,但是上一条语句就是自动装箱的结果,在ArrayList中,我们也是传入了一个int型的值
只不过它被自动装箱成了Integer对象罢了
自动拆箱指的是,可以将一个Integer对象直接赋值给基本类型
如下:
Integer a = 12; int b = a; int c = a.intValue();
自动拆箱也不需要调用相关的方法,可以使封装类直接转换为基本类型
详细的自动拆箱和装箱可以看:Java拓展-拆,装箱,线程,反射
Integer.parseInt()和String.valueOf()
这两个方法是包装类的重点方法
parse方法可以将字符串转换为int,float,double
valueOf可以将其它类型转换为string类型
尤其是在web开发的时候,前后端传递参数都是String类型的,就可以通过paseInt将本是int类型的数据转换为int
parse系列方法:
parseInt:
String a = "12"; int b = Integer.parseInt(a);
parseDouble:
String a = "12"; double b = Double.parseDouble(a);
parseFloat:
String a = "12"; float b = Float.parseFloat(a);
注意:
如果a = “12.5”这种一看就是浮点型是不能使用int去转换的,它转不了
而且如果a中包含字符,也是转换不了的
上面两种情况都是会报错的
valueOf()方法:
此方法是包含于String类型的,可以将其它类型转换为S听类型
String a = String.valueOf(12);
String b = String.valueOf(12.0);
但是这个在实际开发中用到的比较少,因为一般我们会选择使用字符拼接