java中的祖先类_JAVA中所有类的祖先-Object类源码解读

Object类是Java中所有类的祖先,在Java中每个类都是由它拓展而来,我们都知道继承一个类的写法

class child extends father

但是继承Object类并不需要写

class child extends Object

因为如果你不明确指定继承的类,Object就被默认为是这个类的父类。

由于在Java中,每个类都是由Object类拓展而来的,所以熟悉这个类所提供的服务就有必要认真的去观摩观摩了。

1、Equals方法

在Objdect类中的equals方法用于检测一个对象是否等于另外的一个对象,如果两个对象具有相同的引用,则相等。下面用一个例子来解读。

class Employee

{

public Employee(String name,double salary,int year,int month,int day) {

this.name = name;

this.salary = salary;

GregorianCalendar calendar = new GregorianCalendar(year,month-1,day);

this.hireDay =calendar.getTime();

}

public String getName()

{

return this.name;

}

public double getSalary()

{

return this.salary;

}

public Date getHireDay()

{

return this.hireDay;

}

public void raiseSalary(double byPercent)

{

double raise = salary * byPercent / 100;

salary += raise;

}

public boolean equals(Object otherObject)

{

if(this==otherObject)return true;

if(otherObject==null)return false;

if(getClass()!=otherObject.getClass())return false;

Employee other = (Employee)otherObject;

return this.name.equals(other.name)&&this.salary==other.salary&&this.hireDay.equals(other.hireDay);

}

public int hashCode()

{

return 7*name.hashCode()+11*new Double(salary).hashCode()+13*hireDay.hashCode();

}

/*public String toString()

{

return getClass().getName()+"[name="+name+",salary="+salary+",hireDay"+hireDay+"]";

}*/

private String name;

private double salary;

private Date hireDay;

}

class Manage extends Employee

{

public Manage(String name,double salary,int year,int month,int day)

{

super(name,salary,year,month,day);

this.bonus = 0;

}

public double getSalary()

{

double baseSalary = super.getSalary();

return baseSalary+bonus;

}

public void setBonus(double b)

{

bonus = b;

}

public boolean equals(Object otherObject)

{

if(!super.equals(otherObject))return true;

Manage other = (Manage)otherObject;

return bonus == other.bonus;

}

public int hashCode()

{

return super.hashCode()+17*new Double(bonus).hashCode();

}

/*public String toString()

{

return super.toString()+"[bonus="+bonus+"]";

}*/

private double bonus;

}

这里定义了两个类,一个Employee类和一个子类Manage类,当我们创建两个对象的时候

Employee alice1 = new Employee("Alice Adams",75000,1987,12,15);

Employee Bob = new Employee("Bob",50000,1989,1,25);

System.out.println("alice1.equals(alice3):"+alice1.equals(alice3));

System.out.println("alice1.equals(Bob):"+alice1.equals(Bob));

...

alice1.equals(alice3):true

alice1.equals(Bob):false

1)可以看到输出的结果alice1和alice指向的是同一个引用,所以结果是对的,而alice1和Bob指向的不是同一个对象,所以不相等。

2)当遇到的参数不属于同一个类的时候equals应该怎么做呢?比如在Employee和Manage对象中都有相同的姓名、薪水和雇佣日期。我们可以这样定义equals

public boolean equals(Object otherObject)

{

if(this==otherObject)return true;//检测this和otherObeject引用的是否同一个对象

if(otherObject==null)return false;//检测otherObject是否为空

if(getClass()!=otherObject.getClass())return false;//比较this和otheObject是否是同一个类的

Employee other = (Employee)otherObject;//将otherObject转换成为响应的类的类型变量

return this.name.equals(other.name)&&this.salary==other.salary&&this.hireDay.equals(other.hireDay);//开始做字段的匹配

}

//如果在子类中重新定义equals,就要在其中包含调用super.equals(other)

public boolean equals(Object otherObject)

{

if(!super.equals(otherObject))return true;

Manage other = (Manage)otherObject;

return bonus == other.bonus;

}

equals和“==”的区别

==是判断两个变量或实例是不是指向同一个内存空间

equals是判断两个变量或实例所指向的内存空间的值是不是相同

当这两者除了在String类型和封装器上的比较有区别,其他并没有区别,因为String类型重写了equals。

String下的equals源码:

c504b6407918a763c135809dbf60f1f4.png所以在这里面,equals()指比较字符串或封装对象对应的原始值是否相等,"=="是比较两个对象是否为同一个对象。

StringBuilder sb1 = new StringBuilder("aaa");

StringBuilder sb2 = new StringBuilder("aaa");

System.out.println(sb1.equals(sb2)+" "+ (sb1==sb2));//输出false false,因为是对象的比较,equals和“==”都是比较引用

String sb1 = new String("aaa");

String sb2 = new String("aaa");

System.out.println(sb1.equals(sb2)+" "+ (sb1==sb2));//输出 true false.因为String重写了equals,equals比较的是值。

2、HashCode方法

HashCode是由对象导出的一个整型值,(散列码是由内容导出的)如果x和y 是不同的对象,则他们的散列值一般是不同的。

在Object类中的hashCode方法默认导出的是对象的存储地址。

另Equals和hashCode的定义必须一致,如果x.equals(y)返回true,那么x和y的hashCode应该具有相同的值。

比如:

StringBuilder sb1 = new StringBuilder(“aaa”);

StringBuilder sb2 = new StringBuilder(“aaa”);

System.out.println(sb1.equals(sb2)+" "+ (sb1==sb2));

System.out.println("alice1.hashCode():"+alice1.hashCode());

System.out.println("alice3.hashCode():"+alice3.hashCode());

public int hashCode()

{

return 7*name.hashCode()+11*new Double(salary).hashCode()+13*hireDay.hashCode();//与equals有同样的字段进行计算,计算规则自定义,但是应该让散列码更均匀

}

//输出结果

alice1.hashCode():377780067

alice3.hashCode():377780067

//如果我们将上面的方法给注释了,则返回的是存储地址的值

alice1.hashCode():1028566121

alice3.hashCode():1118140819

3、toString方法***

在Object中还有一个很重要的方法就是toString方法。它用于返回表示对象值得字符串。在Object中我们可以看到它是这样定义的

/**

* Returns a string representation of the object. In general, the

* {@code toString} method returns a string that

* "textually represents" this object. The result should

* be a concise but informative representation that is easy for a

* person to read.

* It is recommended that all subclasses override this method.

*

* The {@code toString} method for class {@code Object}

* returns a string consisting of the name of the class of which the

* object is an instance, the at-sign character `{@code @}', and

* the unsigned hexadecimal representation of the hash code of the

* object. In other words, this method returns a string equal to the

* value of:

** * getClass().getName() + '@' + Integer.toHexString(hashCode())

*

*

* @return a string representation of the object.

*/

public String toString() {

return getClass().getName() + "@" + Integer.toHexString(hashCode());

}

alice1=alice2:Employee@3d4eac69,Employee@3d4eac69

alice1=alice3:Employee@3d4eac69,Employee@42a57993

它返回的是一个类名和散列码,但是返回这个值有点太抽象,对我们的意义并不是很大,我们可以对这个方法进行重载,返回我们想要的字段

public String toString()

{

return getClass().getName()+"[name="+name+",salary="+salary+",hireDay"+hireDay+"]";

}/**/

//输出结果

alice1=alice2:Employee[name=Alice Adams,salary=75000.0,hireDayTue Dec 15 00:00:00 CST 1987],Employee[name=Alice Adams,salary=75000.0,hireDayTue Dec 15 00:00:00 CST 1987]

alice1=alice3:Employee[name=Alice Adams,salary=75000.0,hireDayTue Dec 15 00:00:00 CST 1987],Employee[name=Alice Adams,salary=75000.0,hireDayTue Dec 15 00:00:00 CST 1987]

对于数组类型的域,equals、hashcode和都可以应用静态的Arrays调用来检测。

4、class getClass()

返回包含对象信息的类的对象,

5、protected native Object clone()

拷贝与克隆的区别

c0332f184b9f74c05b021f4345340ebf.png拷贝:拷贝的变量与原变量指向同一个对象

Employee original = new Employee("John Public",50000);

Employee copy = original;

copy.raiseSalary(10);//则原始的original的Salary也会改变

克隆:创建一个对象的副本。Java运行时系统将为新实例分配存储控制,并不是只创建一个变量指向相同的空间哦,而是有开辟新的存储空间。

Employee copy = original.clone();

copy.raiseSalary(10);//original的salary并没有改变

但是事情并没有那么简单,clone是一个Proteced方法,也就是说用户编写的代码不能直接访问,如果对象中的所有数据域都属于基本数值或基本类型,则不会出现什么情况,但是如果对象中包含对子对象的引用,则克隆结果会使两个域引用同一个子对象,

f095370caa8fca740423a936d7714004.png

所以针对这种情况,我们要对clone进行重定义,将其定义为public类型。

class Employee implements Cloneable()

{

public Employee clone() throws CloneNotSupportedException

{

Employee cloned = (Employee)super.clone();

cloned.hireDay = (Date)hireDay.clone();//所有可变的域都应该克隆

return cloned;

}

}

6、void notify(),voide notifyall(),void wait(long timeout)

这三者一般应用在同步synchronized关键字声明的方法中,如果一个方法用synchronized关键字声明后,那么对象的锁将保护整个方法

public synchronized void method()

{

method body

}

而wait 和notify,notifyall用在这个方法中。

void wait(long timeout): 导致线程进入等待状态知道它被通知,该方法只能在一个同步方法中调用。如果当前线程不是对象锁的持有者,该方法抛出一个IllegalMonitorStatwException异常

voide notifyall():解除那些在该对象上调用wait方法的线程的阻塞状态,该方法只能在同步方法或同步块内部调用,如果当前线程不是对象锁的持有者,则抛出IllegalMonitorStatwException异常

voide notify():随机选择一个在该对象上调用wait 方法的线程,解除其阻塞状态,该方法只能在同步方法或同步块内部调用,如果当前线程不是对象锁的持有者,则抛出IllegalMonitorStatwException异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值