Object
在java中,Object是类层次中的根类,即Object是所有类的父类-任何类都是 object的子类。任何一个类的对象都可以使用object来声明。
类<?> getClass() 返回此object的运行
int hashCode() 返回对象的哈希码
protected Object clone() 创建并放回此对象的副本(拷贝)
String toString() 返回对象的字符串表示形式,当打印对象的时候,实际底层在调用这个对象的toString
boolean equals() 指示一些对象是否等于此
事实上还有notify(),notifyAll(),wait()这些都是多线程中使用到的方法,我在之前的博客中有提到。
下面演示getClass()和hashCode():
package com.itheima.math;
public class MathDemo03 {
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = "abc";
Object o3 = new int[]{1,2,3,4,5};
Object o4 = 10.3;
//getClass 获取对象的实际类型
System.out.println(o1.getClass());
System.out.println(o2.getClass());
System.out.println(o3.getClass());
System.out.println(o4.getClass());
//hashCode 获取对象的哈希码
//哈希码是根据哈希散列算法计算出来的,哈希散列算法不是一个算法而是一套算法
//哈希散列算法的结果一定是散列的-数据只要有一丁点的不同,那么计算的结果就差别很大
System.out.println(o1.hashCode());
System.out.println(o2.hashCode());
System.out.println(o3.hashCode());
System.out.println(o4.hashCode());
}
}
运行结果:
#补充:哈希码是根据哈希散列算法计算出来的,哈希散列算法不是一个算法而是一套算法。哈希散列算法的结果一定是散列的 - 数据只要有一丁点的不同,那么计算的结果就差别很大。同一个对象利用相同的哈希算法计算出来的结果肯定是相同。哈希算法算出来的结果称之为哈希码。哈希值不具有自反性:可以根据对象和哈希算法计算出来哈希码,但是根据哈希码和哈希算退出原始数据是不可能的。
下面演示clone()和toString():
package com.itheima.math;
public class MathDemo04 {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person("张三",19,"男");
Person p2 = p1.clone();
System.out.println(p1);
System.out.println(p2);
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
}
}
class Person implements Cloneable{
private String name;
private int age;
private String gender;
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
protected Person clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
}
运行结果:
#补充: clone(克隆),在Java中,一个对象想要克隆,那么这个对象的类必须实现Cloneable接口。这个方法中没有任何的方法,只是为了标识当前的类可不可以被克隆。使用clone()时,需要复写clone()。
在打印对象时,如果重写了toString方法,则执行最新的toString方法,如果没有重写,则执行object的toString方法。
就会打印这些:
下面演示equlas():
package com.itheima.math;
import java.util.Objects;
//null调用任何的属性或者方法都会出现空指针异常
//默认情况下:equals使用==来判断两个对象的,实际上是判断的是两个对象的地址是否相同
public class MathDemo05 {
public static void main(String[] args) {
Student s1 = new Student("小丽",18,"女");
Student s2 = new Student("小丽",18,"女");
System.out.println(s1.equals(s2));
}
}
class Student{
private String name;
private int age;
private String sex;
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
//重写equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name) &&
Objects.equals(sex, student.sex);
}
/*public boolean equals(Object o){
//判断地址是否相同
if(this == o)return true;
//判断参数是否为空
if(o == null)return false;
//判断类型是否一致
if(this.getClass() != o.getClass())return false;
//强转
Student s = (Student) o;
//判断属性
//判断年龄是否一致
if(this.age != s.age)return false;
//姓名是否一致
return true;
}*/
}
运行结果:
补充:默认情况下:equals使用==来判断两个对象的,实际上是判断的是两个对象的地址是否相同。null调用任何的属性或者方法都会出现空指针异常(存在参数设置为null的情况,不应该忽视)。仅使用默认情况下的equals是不够的,因为他只会判断地址,而不会判断内容,所以通常情况下,需要去重写equals。
如果我们去掉这个重写的equals,把s1的小丽改为小红,它的运行结果为:
我们再把小红改为小丽:
这玩意压根判断不了,我们把重写的equals给它加上去就可以判断了。
包括其它参数都是可以判断的。
#这个重写的equals(),可以快捷生成,也可以手写,在idea中可使用快捷键ALT+INSERT找到。
#拓展:
在上面提到的拷贝方法被称之为:浅拷贝
浅拷贝对于基本数据类型就是直接进行值传递,在内存的另一个空间内存放,修改这个值不会影响到拷贝源的值
基本数据类型:保存的是值本身;
引用类型:保存的是指向堆中数据的地址;
浅拷贝对于引用数据类型就是进行的是地址传递,并没有对该对象重新开辟一个内存空间进行存放,所以对于引用数据类型的浅拷贝就相当于两个引用指向了同一个内存地址,
那么就显而易见了修改拷贝后的值就会影响到拷贝源的值
我们来简单测试一下另外写的代码:
package com.itheima.object;
import java.util.Arrays;
public class Teacher implements Cloneable{
private String name;
private int age;
private int[] id;
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + Arrays.toString(id) +
'}';
}
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 int[] getId() {
return id;
}
public void setId(int[] id) {
this.id = id;
}
public Teacher(String name, int age, int[] id) {
this.name = name;
this.age = age;
this.id = id;
}
protected Teacher clone() throws CloneNotSupportedException {
return (Teacher)super.clone();
}
}
package com.itheima.object;
public class ObjectDemo01 {
public static void main(String[] args) throws CloneNotSupportedException {
int[] id1 = {1,2,3,4,5,6,7,8,9,10};
Teacher t1 = new Teacher("李章",47,id1);
Teacher t2 = t1.clone();
System.out.println(t1);
System.out.println(t2);
}
}
那么这段代码的运行结果是这样的:
此时,我们对代码进行一点小修改:
package com.itheima.object;
public class ObjectDemo01 {
public static void main(String[] args) throws CloneNotSupportedException {
int[] id1 = {1,2,3,4,5,6,7,8,9,10};
Teacher t1 = new Teacher("李章",47,id1);
Teacher t2 = t1.clone();
id1[9] = 0;
System.out.println(t1);
System.out.println(t2);
}
}
因为我们是拷贝过来的,当我们需要一个与源文件一样的副本,都是又希望这个副本是独立的,就不会希望出现这种情况:
会发现明明在拷贝完成后修改的数据,副本依旧出现了变化,这是因为对于引用数据类型,它保存的不是数据本身,而是数据在数据堆中的地址。也就是”浅拷贝“
下面介绍深拷贝:
深拷贝又成为深度拷贝,所拷贝的对象的内部的引用类型也需要实现clone()这个方法,其目的就是实现对引用数据也拷贝其本身。
由于手写深拷贝过于麻烦,遇到数据量大的代码直接无从下手,所以这里我们建议使用第三方工具:
将jar包导入到idea或者eclipse中即可。
像这样可以打开的,就说明导入成功了。
接下来展示用第三方工具实现深拷贝:
package com.itheima.object;
import com.google.gson.Gson;
public class ObjectDemo01 {
public static void main(String[] args) throws CloneNotSupportedException {
int[] id1 = {1,2,3,4,5,6,7,8,9,10};
Teacher t1 = new Teacher("李章",47,id1);
System.out.println(t1);
//编写代码
Gson gson = new Gson();
//把对象变成一个字符串
String s = gson.toJson(t1);
//再把字符串变会对象就可以了
Teacher t2 = gson.fromJson(s,Teacher.class);
//打印对象
System.out.println(t2);
}
}
这是还没进行操作的运行结果:
接下来我们对引用数据进行修改:
package com.itheima.object;
import com.google.gson.Gson;
public class ObjectDemo01 {
public static void main(String[] args) throws CloneNotSupportedException {
int[] id1 = {1,2,3,4,5,6,7,8,9,10};
Teacher t1 = new Teacher("李章",47,id1);
//编写代码
Gson gson = new Gson();
//把对象变成一个字符串
String s = gson.toJson(t1);
//再把字符串变会对象就可以了
Teacher t2 = gson.fromJson(s,Teacher.class);
//打印对象
int[] id2 = {9,8,7,6,5,4,3,2,1};
t2.setId(id2);
System.out.println(t1);
System.out.println(t2);
}
}
改动后运行结果:
我们发现引用数据并没有受到影响,那么这个时候就实现了深拷贝。