Object类源码学习
来源:互联网 发布:在绿城工作怎么样知乎 编辑:程序博客网 时间:2024/04/30 12:54
众所周知,Java中所有的类都直接或间接继承自Object类,既然它如此重要,那么就有必要了解它的实现原理,这样也能够使得我们更加准确的使用。下面的一句话来自于J2SE 文档:
- Class
Object
is the root of the class hierarchy. Every class hasObject
as a superclass. All objects, including arrays, implement the methods of this class.
方法总结:
方法详解:
public boolean equals(Object obj) { return (this == obj); }
<pre name="code" class="java">public native int hashCode();equals方法中直接通过this == obj来判定两个对象是否相等,其中==表示的是this与obj引用指向同一个对象。hashCode中native表明这个是本地方法,即它是通过C语言实现的。但由于在实际的编码中可能并不强求两个引用指向同一个对象是equals才返回true,以String类为例:
public class Test {public static void main(String[] args) {String str1 = "abc";String str2 = new String("abc");System.out.println(str1.equals(str2));}}输出结果为:true
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String) anObject; 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; }可以看出,String类的equals方法首先比较两个引用是否指向同一个对象,若指向同一个对象则返回true;否则的话,比较两个引用所指向的字符串长度是否一致,若一致,则通过逐个比较字符来判断两个引用所指向的对象是否相等。
/** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0
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; }可以看出,得到一个字符串的哈希值是通过这个计算公式h = 31 * h + val[i]得到的,再回想一下String的equals方法的实现:如两个字符串对应位置字符相同则返回true。可以得出若两个字符串相等,那么它们的哈希值也是相同的。通过如下代码检验是否正确:
public class Test {public static void main(String[] args) {String str1 = "abc";String str2 = new String("abc");System.out.println("str1.hashCode() = " + str1.hashCode() + " str2.hashCode() = " + str2.hashCode());}}输出结果:str1.hashCode() = 96354 str2.hashCode() = 96354
import java.util.HashMap;import java.util.Map;public class Test {public static void main(String[] args) {Map<User, String> map = new HashMap<User, String>();User firstUser = new User("zcj", 25);map.put(firstUser, "firstUser");User targetUser = new User("zcj", 25);System.out.println(targetUser.equals(firstUser));String result = map.get(firstUser);System.out.println(result);result = map.get(targetUser);System.out.println(result);}}class User {private String name;private int age;public User(String name, int age) {super();this.name = name;this.age = age;}/*@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}*/@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;User other = (User) obj;if (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}输出结果是:
firstUser
null
firstUser
firstUser
firstUser
null
public class User {public static User gc_root = null;@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("finalize method executed!");gc_root = this;}public void isAlive() {System.out.println("yes, i am alive");}public static void main(String[] args) {gc_root = new User();gc_root = null;System.gc();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if(gc_root != null) {gc_root.isAlive();} else {System.out.println("no, i am dead");}gc_root = null;System.gc();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if(gc_root != null) {gc_root.isAlive();} else {System.out.println("no, i am dead");}}}输出结果是:
yes, i am alive
no, i am dead
在Java语言中,当clone方法被对象调用,就会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。那么在java语言中,有几种方式可以创建对象呢?
1.使用new操作符创建一个对象
2.使用clone方法复制一个对象
那么这两种方式有什么相同和不同呢?
new操作符的本意是分配内存。程序执行到new操作符时,首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。
clone在第一步是和new相似的,都需要分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用源对象中对应的各个域,填充新对象的域,填充完成之后,clone方法返回一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。
下面让我们来关注一下Cloneable接口,其与Object类中的clone方法是否存在联系呢?让我们看看API中的说明:
注意:Cloneable接口中并没有定义clone方法,但它决定了Object中受保护的clone方法实现的行为:如果一个类实现了Cloneable,Object的clone方法就返回该对象的逐域拷贝,否则就会抛出CloneNotSupportedException异常。
拷贝对象往往会导致创建它的类的一个新实例,但它同时也会要求拷贝内部的数据结构。这个过程中没有调用构造器。在这个类中声明的域将等同于被克隆对象中的域。如果每个域包含一个基本类型的值,或者包含一个指向不可变对象的引用,那么返回的对象则可能正是你所需要的对象,在这种情况下不需要再做进一步处理。
深拷贝 or 浅拷贝
public class User implements Cloneable {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "User [userName=" + userName + ", password=" + password + "]";
}
public static void main(String[] args) {
User user = new User();
user.setUserName("zcj");
user.setPassword("123456");
try {
User cloneUser = (User)user.clone();
System.out.println(user.userName == cloneUser.userName);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
- Object类源码学习
- java Object 类 源码学习
- JDK源码学习--java.lang.Object类
- Object源码学习
- Object类源码解析
- Object类源码分析
- 阅读Object类源码
- Object类源码解析
- Java源码学习-Object类的hashCode和equals方法
- JDK源码学习--System.identityHashCode(Object)
- Java Object类源码阅读
- Java Object 类源码分析
- java源码分析 ---- Object类
- Java-Object类源码解析
- 初识JDK源码object类
- Object 源码
- Object源码
- Object类学习总结
- 复习(数据结构):线性表 : C:动态分配内存
- android include使用
- hibernate——onetoone (单向)
- eclipse 全文搜索查找字符串
- SparkR安装部署及数据分析实例
- Object类源码学习
- 快速幂模板
- 百度的冬天:曾梦想成伟大公司 却为何陷入危机
- Struts2访问Servlet API的3种方式
- Can't create handler inside thread that has not called Looper.prepare()
- 自定义ToolBar
- IOS OPENGL ES 之EAGLContext上下文配置
- (七) spring_Bean的作用域
- acm之贪心算法题目6