2.4.5 Object类
clone(): “克隆”对象的方法
public class OsExec2{//每个类默认继承Object父类
//调用的OS类clone有异常,需要抛异常
public static void main(String[] args)throws CloneNotSupportedException{
OS win=new OS("windows操作系统");
OS linux=win.clone();
System.out.println(win==linux);//两个对象地址不一样false
//更改克隆出来的对象名字对被克隆对象没有影响
linux.name="Linux操作系统";
System.out.println(win.name);
System.out.println(linux.name);
}
}
//给类赋予克隆能力,即让类是实现可克隆的接口implements Cloneable
class OS implements Cloneable{
String name;
public OS(String name){
this.name=name;
}
//覆盖父类Object中clone方法,更改其权限protected->public,具体实现方法直接super.clone()调用
@Override
public OS clone()throws CloneNotSupportedException{
Object obj=super.clone();
return (OS)obj;//返回类型需要强转为本类类型
}
}
finalize(): 对象的“遗言”方法(当一个对象要被gc回收的时候,会主动执行的一个方法,主要是释放资源)/gc垃圾回收器
toString(): 制定一个对象打印显示的内容
当我们想要将一个引用数据类型的对象放进打印
语句里面的时候 这个对象会自动的调用toString()
toString()在没有覆盖的时候 和Object类保持一直
Object -> toString() -> 类型@XXX
Student stu=new Student(“zml”,20);
System.out.println(stu);//姓名:zml,年龄:20
@Override
//重写父类的toString方法
public String toString(){
return "姓名:"+name+",年龄:"+age;
}
例子:球色
public class ExecToString{
public static void main(String[] args){
Ball b1=new Ball(5);
Ball b2=new Ball(2);
Ball b3=new Ball(12);
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
}
}
class Ball{
int number;
public Ball(int number){
this.number=number;}
@Override
public String toString(){
/*String[] color={"黄","蓝","粉","紫","绿","白","黑","灰","红"};
for(int i=0;i<color.length;i++){
if(number==i+1) return number+"号球"+color[i]+"色";
}
return "无此球颜色";*/
String color="黄蓝粉紫绿白黑灰红";
if(number>=1&&number<=color.length()){
return number+"号球"+color.charAt(number-1)+"色";
}
return "无此球";
}
}
equals(): 制定一个类型的比较规则
当我们想要将内存里面不同的两个对象 视为相等对象的时侯需要拿着equals作比较
equals方法在没有覆盖的时候 和Object类型保持一致
在Object类里面 equals() -> 比较地址
如果不想要比较地址的话 需要覆盖equals()
@Override
public boolean equals(Object obj){
if(obj == null)return false;
if(!(obj instanceof 当前类型))return false;
if(obj == this)return true;
制定比较规则
}
基本数据类型==比较;引用数据类型equals比较
public class EqualsExec{
public static void main(String[] args){
Student s1=new Student("小明");
Student s2=new Student("小红");
System.out.println(s1==s2);//连等号比地址
System.out.println(s1.equals(s2));//equals比内容
}}
class Student{
String name;
public Student(String name){
this.name=name;
}
@Override
public boolean equals(Object obj){//覆盖父类的equals方法
return this.name.equals(((Student)obj).name);
// Student x=this;
// Student y=(Student)obj;
// return x.name.equals(y.name);
}
}
equals健壮的写法
if(obj==null) return false;//排除空指针异常
if(!(obj instanceof Student)) return false;//判断obj是否属于Student类
if(obj==this) return true;//obj与当前调用equals对象this相等的话直接返回true,让代码高效运行
public class EqualsExec3{
public static void main(String[] args){
Cat cc=new Cat("小猫咪");
Student s1=new Student("小明");
Student s2=new Student("小红");
System.out.println(s1.equals(s2));
System.out.println(s1.equals(cc));
System.out.println(cc.equals(cc));
}}
class Cat {
String name;
public Cat(String name){
this.name=name;
}
}
class Student{
String name;
public Student(String name){
this.name=name;
}
@Override
public boolean equals(Object obj){
//由于参数是Object类型 导致所有的引用数据类型都可以传递进来
//所有的引用数据类型默认值都是null 为了防止出现空指针异常
//所以进行排空判断 如果参数是null 那么直接返回false
//保证代码的健壮性
if(obj==null) return false;
//由于参数是Object类型 所以导致所有的引用数据类型都可以传递进来
//但是学生类的equals方法应该和学生做比较
//所以只要参数不是学生类型的话 统一返回false
//保证代码的健壮性
if(!(obj instanceof Student)) return false;
//保证代码高效
if(obj==this) return true;
return this.name.equals(((Student)obj).name);
// Student x=this;
// Student y=(Student)obj;
// return x.name.equals(y.name);
}
}
面试题: ==与equals区别?
不同点 | == | equals |
---|---|---|
含义 | 运算符 | Object类里面一个方法 |
比较 | 如果比较基本数据类型 比较数值是否一样 如果比较引用数据类型 比较地址是否一样 | 程序员可以按照自己的意愿 将内存里面 不同的两个对象视为相等对象【逻辑相等】 比如:String类型 Sun公司通过覆盖equals() 让两个字符串只要内容一样就视为相等对象 |
hashCode(): 用于返回字符串的哈希码
hashcode代表对象的地址说的是对象在hash表中的位置,物理地址说的对象存放在内存中的地址
例:hash表中有 hashcode为1、hashcode为2、(…)3、4、5、6、7、8这样八个位置,有一个对象A,A的物理地址转换为一个整数17(这是假如),就通过直接取余算法,17%8=1,那么A的hashcode就为1,且A就在hash表中1的位置。
作用:
HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的(后半句说的用hashcode来代表对象就是在hash表中的位置)
hashcode和equals的关系
1、如果两个对象equals相等,那么这两个对象的HashCode一定也相同
2、如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置
public class TestHashcode {
public static void main(String args[]) {
String Str = new String("www.Oracle.com");
System.out.println("字符串的哈希码为 :" + Str.hashCode() );//字符串的哈希码为 :706482664
}
}
为什么equals方法重写的话,建议也一起重写hashcode方法?
比如:有个A类重写了equals方法,但是没有重写hashCode方法,看输出结果,对象a1和对象a2使用equals方法相等,按照上面的hashcode的用法,那么他们两个的hashcode肯定相等,但是这里由于没重写hashcode方法,他们两个hashcode并不一样,所以,我们在重写了equals方法后,尽量也重写了hashcode方法,通过一定的算法,使他们在equals相等时,也会有相同的hashcode值。
注意:当此方法[equals]被重写时,通常有必要重写 hashCode 方法,
以维护 hashCode 方法的常规协定,
该协定声明相等对象必须具有相等的哈希码。
x.equals(y) == true
x.hashCode() == y.hashCode()
public class TestStrinBuffer{
public static void main(String[] args){
Computer lenovo=new Computer("联想",14.0,'灰',6099,false);
Computer lenovo2=new Computer("联想",14.0,'灰',6099,true);
System.out.println(lenovo);
System.out.println(lenovo2);
System.out.println(lenovo.equals(lenovo2));
System.out.println(lenovo.hashCode());
}
}
class Computer{
String name;
double size;
char color;
int price;
boolean isShangshi;
public Computer(String name,double size,char color,int price, boolean isShangshi){
this.name=name;
this.size=size;
this.color=color;
this.price=price;
this.isShangshi=isShangshi;
}
@Override
public boolean equals(Object obj){
if(obj==null||!(obj instanceof Computer)) return false;
if(obj==this) return true;
return this.name.equals(((Computer)obj).name)&&this.size==((Computer)obj).size&&this.color==((Computer)obj).color&&this.price==((Computer)obj).price&this.isShangshi==((Computer)obj).isShangshi;
}
@Override
public int hashCode(){
return name.hashCode()+(int)size*10+color+price+(isShangshi? 1:0);
}
@Override
public String toString(){
StringBuffer buffer=new StringBuffer();
buffer.append(name);
buffer.append("的电脑新出来是一款");
buffer.append(color);
buffer.append("颜色,尺寸是");
buffer.append(size);
buffer.append(",售价是:");
buffer.append(price);
buffer.append(isShangshi ? "已经上市" : "至今还没有上市");
return String.valueOf(buffer);//valueOf()输出String中buffer的值
//return buffer.toString();//buffer再次调用toString()方法返回字符串
}
}
public class TestHashCode1{
public static void main(String[] args){
String x = new String("OK");//79 * 31(1) + 75 =
String y = new String("OK");
System.out.println(x == y);//地址:false
System.out.println(x.equals(y));//内容:true
//String extends Object => hashCode()
System.out.println(x.hashCode());
System.out.println(y.hashCode());
Student s1 = new Student("张三");
Student s2 = new Student("张三");
System.out.println(s1 == s2);//地址:false
System.out.println(s1.equals(s2));//true
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());//'张' * 31 + '三'
}
}
class Student{//extends Object => hashCode()
String name;
public Student(String name){
this.name = name;
}
@Override
public boolean equals(Object obj){
//if if if
return this.name.equals(((Student)obj).name);
}
@Override
public int hashCode(){
return name.hashCode();
}
}
/**
Object
toString():打印对象 -》 类型@XXX
equals():比较对象 -》地址
hashCode():生成哈希码值 -》 通过地址
String Student
继承得到: 继承得到:
toString():String@XXX toString():Student@XX
equals():地址 equals():地址
hashCode():地址 hashCode():地址
方法覆盖: 方法覆盖:
toString():内容
equals():内容 equals():name
hashCode():内容
*/