object类在java中的作用,java里object是什么
目录
native method getClass method hashCode method equals method==和equals clone method浅拷贝和深拷贝的区别toString method thread method finalize method Java是一种天然的面向对象语言。而我们手动创建的所有类都继承自同一个类,即Object类。
看一下Object类的结构。
00-1010首先,超类有一个原生方法。
private static native void registerNatives();static { register natives();}在Java中,用native关键字修饰的函数表示该方法的实现不是在Java中完成的。而是由C/C完成,编译成. ddl文件,由Java调用。registerNatives()方法本身主要用于将C/C中的方法映射到Java中的原生方法,实现方法命名的解耦。同时定义了一个静态代码块,所以每当我们创建一个Java对象时,系统总是先调用静态代码块,也就是调用原生方法。这个方法用private修饰,表示这个方法是私有的,不会被外部调用。
native方法
通过这个方法,可以得到类的类实例,在Java反射机制中可以看到。
getClass方法
百度的定义如下:3360
HashCode,并不完全唯一,是一种算法,允许同一类的对象根据各自不同的特性,尽可能地拥有不同的hash码,但并不意味着不同的对象拥有完全不同的hash码。同样的情况,就看程序员怎么写哈希代码的算法了。
哈希表(也叫哈希表)是一种可以根据键值直接访问的数据结构。键值被映射到表中的一个位置来访问记录,从而加快搜索速度。
因此,通过Java的内部hash函数,可以为每个实例化的对象分配一个内存地址,并记录在哈希表中,方便更高效地在程序中查找、创建和比较对象。
写个例子印出来看看:
public class base { public static void main(String[]args){ Apple Apple=new Apple();system . out . println(apple . hashcode());System.out.println(苹果);system . out . println(integer . value of( 74a 14482 ,16));}}class Apple {}打印结果:
1956725890p2。Apple @ 74a144821956725890进程已经结束,退出码0显示对象的哈希地址是十进制数,对应打印的原生十六进制地址。
00-1010ObjectEquals()方法用于比较两个对象是否相等。
equals()方法比较两个对象,确定两个对象引用指向同一个对象,也就是比较两个对象的内存地址是否相等。
可以看出,equals在比较两个对象是否相等时,比较的是两个对象的hashcode是否相等。因此,如果要覆盖equals方法,通常必须覆盖hashcode方法。
比如字符串类型不是原生数据类型(比如int、char、double等。),而是Java重新包装的一个对象。字符串、整数等。都重写equals方法来比较值是否相等,而不是引用类型(hashcode)
例如,String重新打包equals方法:
public boolean equals(Object an Object){ if(this==an Object){ return true;} if(an object instance of String){ String another String=(String)an object;int n=value.length
if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }其中,instanceof
是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean
的数据类型。源码表示,会先匹配引用是否相同,相同则返回真,否则将String实例转化为字符数组,并逐个匹配是否相等,即匹配值是否相等。
String同时也重写了hashcode方法:
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
其中,hash
默认为0,所以重写hash计算公式为:hash=s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
==和equals的区别
== :当比较基本类型时,则比较两者的值是否相等;当比较引用类型时,则比较引用引用(hashcode)是否相等equals:由源码,比较引用是否相等,部分类型如String、Integer等重写了equals方法,比较值是否相等举几个例子:
public class base { public static void main(String[] args) { // new两个String对象,但内容相同 String a = new String("xxx"); String b = new String("xxx"); System.out.println(a == b); // 比较hash值,因为是两个不同的实例化对象,所以不同,返回false System.out.println(a.equals(b)); // 比较内容,均为“xxx”,返回true // 生成两个引用 String c = "xxx"; String d = "xxx"; System.out.println(c == d); // 比较hash值,因为指向同一个引用,所以相同,返回true System.out.println(c.equals(d)); // 比较内容,均为“xxx”,返回true }}
总结:equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较,所以一般情况下 可理解为equals 比较的是值是否相等。
clone方法
Object clone() 方法用于创建并返回一个对象的拷贝。
clone 方法是浅拷贝,对象内属性引用的对象只会拷贝引用地址,而不会将引用的对象重新分配内存,相对应的深拷贝则会连引用的对象也重新创建。
由源码文档,clone方法只能实现浅拷贝,且类需要重写clone方法,调用super.clone来获取返回的对象,因为不同包下,基类保护的实例方法子类无权访问。另外,object类本身没有实现Cloneable接口,但我们自己写的类需要继承Cloneable接口,否则会总会抛出CloneNotSupportedException异常。
写个例子:
public class base{ public static void main(String[] args) throws CloneNotSupportedException { // 实例化一个Student对象 Student student = new Student(18,"Tony"); // 打印内容 System.out.println(student); // 克隆student实例 Student anotherStudent = (Student) student.clone(); // 打印克隆内容 System.out.println(anotherStudent); }}class Student implements Cloneable { int age; String name; Student(int age, String name) { this.age = age; this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Student{" + "age=" + age + ", name=" + name + + }; }}
打印结果:
Student{age=18, name=Tony}Student{age=18, name=Tony}进程已结束,退出代码0
浅拷贝和深拷贝
浅拷贝例子
当拷贝的对象的成员有引用对象时,例如在Student类中包含了另一个Teacher对象时,被克隆的对象和克隆的对象指向同一个Teacher引用,所以当改变Teacher的数据时,克隆的对象也会随之改变
写个例子:
public class base { public static void main(String[] args) throws CloneNotSupportedException { // 实例化一个Teacher对象 Teacher teacher = new Teacher(25,"JayChou"); // 实例化一个Student对象 Student student = new Student(18, "Tony",teacher); // 打印内容 System.out.println(student); // 克隆student实例 Student anotherStudent = (Student) student.clone(); System.out.println(anotherStudent); System.out.println("---------------------------------------"); // 修改teacher数据,并更新student teacher.setAge(30); student.setTeacher(teacher); // 打印修改后的student实例和克隆对象实例 System.out.println(student); System.out.println(anotherStudent); }}class Student implements Cloneable { int age; String name; Teacher teacher; public void setTeacher(Teacher teacher) { this.teacher = teacher; } Student(int age, String name, Teacher teacher) { this.age = age; this.name = name; this.teacher = teacher; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Student{" + "age=" + age + ", name=" + name + + ", teacher=" + teacher + }; }}class Teacher implements Cloneable { int age; String name; Teacher(int age, String name) { this.age = age; this.name = name; } public void setAge(int age) { this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Teacher{" + "age=" + age + ", name=" + name + + }; }}
打印结果:
Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}---------------------------------------Student{age=18, name=fuck, teacher=Teacher{age=30, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=30, name=JayChou}}进程已结束,退出代码0
这就是浅拷贝的结果,因指向同一个引用,当其中一个实例发生更新时,会发生连锁变化
所以相反,实现深拷贝,使得不会发生连锁反应,让克隆与被克隆对象彻底分离!
实现深拷贝
大致有一下思路:
不采用clone方法,重新new一个对象,将需要复制的对象所有属性成员放进去
// 实例化一个Teacher对象 Teacher teacher = new Teacher(25,"JayChou"); // 实例化一个Student对象 Student student = new Student(18, "Tony",teacher); // 打印内容 System.out.println(student); // new一个一模一样的! Student anotherStudent = new Student(18,"Tony",new Teacher(25,"JayChou")); System.out.println(anotherStudent); System.out.println("---------------------------------------"); // 修改teacher数据,并更新student teacher.setAge(30); student.setTeacher(teacher); // 打印修改后的student实例和克隆对象实例 System.out.println(student); System.out.println(anotherStudent);
打印结果:
Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}---------------------------------------Student{age=18, name=Tony, teacher=Teacher{age=30, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}进程已结束,退出代码0
重写clone方法,将每个引用对象也实现克隆
@Override protected Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); student.setTeacher((Teacher) this.teacher.clone()); return student; }
打印结果:
Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}---------------------------------------Student{age=18, name=Tony, teacher=Teacher{age=30, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}进程已结束,退出代码0
序列化
序列化的方式有很多,主要是工具比较多...这里我使用Apache Commons Lang序列化
首先,相关类都需要继承序列化接口(接口并没有实质的实现内容,仅仅作为一个标志)
public class base { public static void main(String[] args) throws CloneNotSupportedException { // 实例化一个Teacher对象 Teacher teacher = new Teacher(25,"JayChou"); // 实例化一个Student对象 Student student = new Student(18, "Tony",teacher); // 打印内容 System.out.println(student); // 序列化深拷贝 Student anotherStudent = (Student) SerializationUtils.clone(student); System.out.println(anotherStudent); System.out.println("---------------------------------------"); // 打印序列化后内容 为字节流 byte[] res = SerializationUtils.serialize(student); System.out.println(SerializationUtils.serialize(student)); // 打印反序列化结果 System.out.println(SerializationUtils.deserialize(res)); System.out.println("---------------------------------------"); // 修改teacher数据,并更新student teacher.setAge(30); student.setTeacher(teacher); // 打印修改后的student实例和克隆对象实例 System.out.println(student); System.out.println(anotherStudent); }}class Student implements Serializable { int age; String name; Teacher teacher; public void setTeacher(Teacher teacher) { this.teacher = teacher; } Student(int age, String name, Teacher teacher) { this.age = age; this.name = name; this.teacher = teacher; } @Override public String toString() { return "Student{" + "age=" + age + ", name=" + name + + ", teacher=" + teacher + }; }}class Teacher implements Serializable { int age; String name; Teacher(int age, String name) { this.age = age; this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Teacher{" + "age=" + age + ", name=" + name + + }; }}
打印结果:
Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}---------------------------------------[B@50040f0cStudent{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}---------------------------------------Student{age=18, name=Tony, teacher=Teacher{age=30, name=JayChou}}Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}进程已结束,退出代码0
总结:第一种方式笨笨的哈哈,第二种方式需要手动重写clone方法,当对象复杂时,就不是一个明智的选择了。相比较之下,第三种当时显的十分方便帅气,可由于底层实现的复杂,存在一定的系统开销。
toString方法
当没有重写该方法时,当打印实例化对象时,则返回类名与hash地址的16进制拼接字符串。为便于人们阅读,建议所有子类重写该方法
例如我的Student类重写了该方法:
class Student implements Serializable { int age; String name; Teacher teacher; public void setTeacher(Teacher teacher) { this.teacher = teacher; } Student(int age, String name, Teacher teacher) { this.age = age; this.name = name; this.teacher = teacher; } @Override public String toString() { return "Student{" + "age=" + age + ", name=" + name + + ", teacher=" + teacher + }; }}
则打印该对象时会返回人们便于阅读的内容:
Student{age=18, name=Tony, teacher=Teacher{age=25, name=JayChou}}
线程方法
wait(),wait(long),wait(long,int),notify(),notifyAll()分别用于线程的休眠于唤醒,在多线程内容中再做详解
finalize方法
到此这篇关于一文带你了解Java万物之基之Object类的文章就介绍到这了,更多相关Java Object类内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。