Java常用类object详解
1.Object概述: 类Object是类层次结构的根类。每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。
2.构造方法详细信息:
Object只有一个无参构造方法,因为object中没有属性
public Object()
3.常用成员方法:
protected Object clone()
boolean equals(Object obj)
protected void finalize()
Class<?> getClass()
int hashCode()
String toString()
public final Class getClass():
从final看出子类不能被重写, 任何一个对象它的 getClass() 行为是一致。
返回值是 Object 的运行时类型。返回值类型是Class: 类类型
Class概述:Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注解是一种接口。
Class类中有一个public String getName():返回该对象的运行时类的全限定名(包名.类名)。可以在得到getClass的方法返回值Class类的时候通过getName获取当前正在运行的类名。
例如:
1 package com.cskaoyan.object; 2 public class ObjectDemo_02 { 3 public static void main(String[] args){ 4 Object obj=new Object(); 5 Class cl1=obj.getClass(); 6 String name1=cl1.getName(); 7 System.out.println("name1 = " + name1);//name1 = java.lang.Object 8 System.out.println("------------------------------------------" ); 9 Object obj2=new Student(); 10 Class cl2=obj2.getClass(); 11 String name2=cl2.getName(); 12 System.out.println("name2 = " + name2);//name2 = com.cskaoyan.object.Student 14 15 } 16 }
public int hashCode():
返回该对象的哈希码值。
默认实现:这一般是通过将该对象的 内部地址 转换 成一个整数来实现的
hashcode()的常规协定:
1) 一致性. 如果一个对象进行比较的信息没有发生修改,那么在一次程序运行期间,它们的hash值要一致。
2) 相等性. 如果两个对象通过 equals 比较是相等的,那么它们的 hashcode 也要相等。
3) 哈希碰撞概率低. 如果两个对象不相等,那么它们的 hashcode 最好不相等,这个可以提高哈希 表的性能。
哈希码值相关知识:
哈希方程:哈希函数可以把任意长度的输入数据映射成一个固定长度的输出结果,返回值就为哈希码值
*MD4是麻省理工学院教授Ronald Rivest于1990年设计的一种信息摘要算法。它是一种用来测试信息完整性的密码散列函数的实行。其摘要长度为128位。这个算法影响了后来的算法如MD5、SHA家族和RIPEMD等。
*MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。
*SHA家族:安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。
一些常用的哈希算法:
public String toString(): (建议所有子类都重写此方法。)
返回该对象的字符串表示。结果应是一个简明但易于读懂的信息表达式。
默认实现:return getClass().getName() + "@" + Integer.toHexString(hashCode());
例如:
1 public class ObjectDemo_04 { 2 public static void main(String[] args) { 3 Object obj=new Object(); 4 String s=obj.toString(); 5 System.out.println("s = " + s);//s = java.lang.Object@1540e19d 6 System.out.println(obj);//java.lang.Object@1540e19d 7 } 8 }
注意:直接打印对象,会默认调用toString()方法。
public boolean equals(Object obj):
指示其他某个对象是否与此对象"相等"。
默认实现: return (this == obj); 判断两个对象的地址值是否相等 (是否是同一个对象)
分两种情况判断是否需要重写equals()方法:
实体类:
一个对象对应一个实体。没有必要重写 Object 中的 equals();
值类:
例如:String, Point(成员变量为为横坐标和纵坐标),因为在现实生活中这种类型的类,当值都相同就可以看作同一个对象,所以需要重写 equals 方法。
值类重写方法需要将关键域进行比较:
例如:Rectangle(长方形类):
关键域:length, width
衍生域:area, perimeter
无关域:color
根据关键域进行比较
Point类重写equals()方法例如:
1 @Override 2 //注意,因为是重写Object类的equals方法,所以参数列表不能改变,还应该是Object object 3 public boolean equals(Object object){ 4 if(object instanceof Point){ 5 Point point=(Point) object; 6 return x==point.x&&y==point.y; 7 } 8 } 9 }
equals方法常规协定:
equals 方法在非空对象引用上实现相等关系:
自反性:对于任何非空引用值 x,x.equals(x) 都应返回true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回true时,x.equals(y)才应返回 true。
传递性:对于任何非空引 用值 x、y 和 z,如果x.equals(y)返回 true,并且y.equals(z)返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
非空性:对于任何非空引用值 x,x.equals(null) 都应返回 false。
注意事项:当此方法被重写时,通常有必要重写hashCode方法,并协定相等对象,都要有相同的哈希码。
用比较的元素作为根据来写hashCode方法。
使用idea生成的equals方法有一个缺陷,子类和父类进行比较的时候,返回值为false违反了里氏替换原则(凡是能够使用父类的地方都可以它的子类替换)。
protected void finalize() throws Throwable
概述:当垃圾回收器回收这个对象时,会自动调用此方法。子类重写 finalize 方法,以释放资源。
默认实现:什么都没做,空实现。
finalize:
1. 可以自己调用, 该对象没有被回收。
2. 当垃圾回收器回收这个对象时,会自动调用此方法。
3. 释放资源最好不要放在 finalize() 里面。为什么?
原因是:垃圾回收线程是一个优先级低的线程,当一个对象变成垃圾后,并不会马上被回 收,因此资源得不到立刻释放。
怎么释放资源呢?
try ... catch ... finally(异常处理)语句释放资源
protected Object clone() throws CloneNotSupportedException
概述:创建并返回此对象的一个"副本".
这个方法是protected修饰的,只有类在同一个包中才能使用,而Object在lang包下,所以我们想要调用这个方法就必须去重写这个方法。
但是如果重写得方法不实现Cloneable
接口则会报出异常:CloneNotSupportedException。
Cloneable(空接口, 标记接口):
此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出CloneNotSupportedException异常。
一个接口没有定义任何内容,叫做空接口,在Java中往往起标记作用。
浅拷贝和深拷贝:
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
深拷贝和浅拷贝的应用场景:
1.对于基本数据类型我们不需要考虑浅拷贝和深拷贝,使用等号便可复制值。
2.对于复合数据类型使用等号属于浅拷贝,仅复制该字段值,如数组则复制地址,这个时候需要考虑是否使用需要深拷贝。
Java的默认实现是浅拷贝和深拷贝?
浅拷贝
举例:
1 public class ObjectDemo7 { 2 public static void main(String[] args) throws CloneNotSupportedException { 3 // Object obj = new Object(); 4 // obj.clone(); 5 Student s1 = new Student("Henson_z", 18); 6 Student s2 = s1.clone(); 7 // System.out.println(s1.equals(s2)); 8 // System.out.println(s2); 9 // System.out.println(s1 == s2); 10 System.out.println(s1.getName().equals(s2.getName())); // true 11 System.out.println(s1.getName() == s2.getName()); // false 12 } 13 }
因为name 是String类型的是引用变量,从 System.out.println(s1.getName() == s2.getName()); // false中可以看出s1和s2的name是指向同一个变量的,所以java中的拷贝为浅拷贝
在java中怎么实现深拷贝?
对引用数据类型,创建一个新的对象,并复制其内容。
举例:(单层关系的深拷贝)
//在Student重写clone()方法时,name属于String类型的成员变量,如果直接调用super.clone()(即Object类的clone方法)方法进行复制,只进行了浅拷贝
//所以对于name成员变量要创建一个新的对象,并复制内容
protected Student clone() throws CloneNotSupportedException { Student s = (Student) super.clone(); s.name = new String(name); return s; }
举例:(多层关系的深拷贝)
1 package com.cskaoyan.object; 2 /* 3 对 FirstLevel 实现深拷贝。 5 分析: 6 1. 实现 cloneable 接口 7 2. 重写 clone 方法。 8 */ 9 public class FirstLevel implements Cloneable{ 10 int a; 11 SecondLevel secondLevel; 12 13 @Override 14 protected FirstLevel clone() throws CloneNotSupportedException { 15 // return super.clone(); 16 FirstLevel fl = (FirstLevel) super.clone(); 17 // 对 SecondLevel 进行深拷贝不是 FirstLevel 的职责。 18 /*SecondLevel sl = new SecondLevel(); 19 sl.b = fl.secondLevel.b; 20 sl.s = new String(fl.secondLevel.s);*/ 21 SecondLevel clone = secondLevel.clone(); 22 fl.secondLevel = clone; 23 return fl; 24 } 25 }
1 package com.cskaoyan.object; 2 3 public class SecondLevel implements Cloneable{ 4 int b; 5 String s; 6 7 @Override 8 protected SecondLevel clone() throws CloneNotSupportedException { 9 SecondLevel sl = (SecondLevel) super.clone(); 10 sl.s = new String(s); 11 return sl; 12 } 13 }