20250103-Object类

1. 定义

是java所有类的超类,所有的类从根本上都继承自Object类,是唯一没有父类的类。

如果一个类没有明确标识继承某一个类,那么它默认继承自Object类。比如下面两个类是等价的:

public class Person
{}

public class Person extends Object
{}

Object类的方法适用于所有类。

2. Object类的常用方法

2.1 构造方法Object()

2.2 clone()

如果想实现对象的克隆,那么在对象所在的类必须实现cloneable接口,即第11行,这个接口没有定义方法,属于标识接口

对象的克隆即另开辟一块内存空间,存放复制对象的内容。见下面示例,第3行和第20行需声明异常类型;

第22行继承父类的clone()方法;第6行向下转型;

public class TestDemo
{
    public static void main(String[] args) throws Exception
    {
        Robot r1=new Robot("大疆",12);
        Robot r2=(Robot) r1.clone();
        System.out.println(r2.name);
    }
}

class Robot implements Cloneable
{
    String name;
    int height;
    public Robot(String name,int height)
    {
        this.name=name;
        this.height=height;
    }
    public Object clone() throws CloneNotSupportedException
    {
        return super.clone();
    }
}
//输出结果:大疆

2.3 equals(object)

此方法必须被覆写。

2.3.1. 不覆写的情景

那么比较两个对象实际上是比较对象的内存地址是否相同。

2.3.2 覆写

覆写后比较的是对象的内容。

须注意第23行和第26行的代码。另外覆写的equals()还有更简便的实现代码,见注释。

第23行中的this表示调用该equals方法的对象;

第26行的向下转型是为了定义传入的对象,向下转型确实说得通,Object是所有类的父类,equals方法传入的对象是父类的对象,通过向下转型才能得到子类的对象,即欲比较的对象;另外就是,因为调用子类的成员属性需由子类的实例对象来完成,父类若不具有和子类相同的成员属性,则父类对象调用子类成员属性会报错。

为什么24行中的o instanceof Person会成立呢?是因为o是Person类对象的向上转型得到的,即Object o=new Person(),这行代码可能不能编译,但就按这么理解吧。

public class draft2
{
	public static void main(String[]args)
	{
		Person p1=new Person(12,"dia");
		Person p2=new Person(12,"dia");
		System.out.println((p1.equals(p2))?"相等":"不相等");
	}
}

class Person
{
	int age;
	String name;
	public Person(int age,String name)
	{
		this.age=age;
		this.name=name;
	}
	public boolean equals(Object o)
	{
		boolean temp=true;
		Person p1=this;
		if(o instanceof Person)
		{
			Person p2=(Person)o;
			if(!(p1.age==p2.age&&p1.name.equals(p2.name)))
			{
				temp=false;
			}
		}
		else{
			temp=false;
		}
		return temp;
	}
    // public boolean equals(Object o)
	// {
	// 	Person p2=(Person)o;
	// 	return (this.age==p2.age&&this.name.equals(p2.name));
	// }
}

2.4 finalize()

2.5 getClass()

2.6 hashCode()

HashTable,哈希表,是一种数据结构,其中的元素是键值对(key:value),具有快速查找、修改、删除的优点;其中用到了哈希算法,该算法的功能是将任意长度的输入转换成固定长度的输出,这就是hashcode,是整数值,默认情况下表示对象的存储地址。hashtable、hashmap、hashset均是基于此数据结构的具体实现。

hashcode是对象的哈希值,也可以称关键码,是上文说的key。

下面代码中,第27行的name.hashcode(),name是String类的实例对象,因此调用hashcode方法没毛病,调用的目的是得到name的哈希值,用于后续计算。

覆写equals()方法必须覆写hashcode()方法,那么覆写后两者的联系是什么呢?在于,覆写后的equals方法是比较age和name这俩成员变量,覆写后的hashcode方法也是用上了这两个成员变量-用它俩来计算对象的哈希值,如此将对象的哈希值与对象匹配了起来。

public class draft2
{
	public static void main(String[]args)
	{
		Person p1=new Person(12,"dia");
		Person p2=new Person(12,"dia");
		Person p3=new Person(14,"dao");
		System.out.println((p1.equals(p2))?"相等":"不相等");
		System.out.println((p1.equals(p3))?"相等":"不相等");
		System.out.println(p1.hashCode());
		System.out.println(p2.hashCode());
		System.out.println(p3.hashCode());
	}
}

class Person
{
	int age;
	String name;
	public Person(int age,String name)
	{
		this.age=age;
		this.name=name;
	}
	public int hashCode()
	{
		return age*(name.hashCode());
	}
	public boolean equals(Object o)
	{
		boolean temp=true;
		Person p1=this;
		if(o instanceof Person)
		{
			Person p2=(Person)o;
			if(!(p1.age==p2.age&&p1.name.equals(p2.name)))
			{
				temp=false;
			}
		}
		else{
			temp=false;
		}
		return temp;
	}
}
/*输出结果
相等
不相等
1193424
1193424
1389052*/

2.7 notify()

2.8 nitifyAll()

2.9 wait()

2.10 toString()

2.10.1 默认调用

为了适用于所有子类,在默认情况下该方法返回对象地址,见第7行;第6、7两行的输出结果相同,说明在输出对象时,会默认调用toString方法。

public class toString
{
	public static void main(String[]args)
	{
		Person p=new Person();
		System.out.println(p);
		System.out.println(p.toString());
	}
}

class Person
{

}
//输出结果
//Person@279f2327
//Person@279f2327

2.10.2 子类覆写

当然,子类(相比于object来说,任何类都是其子类)也可以自己修改该方法的输出。

public class toString
{
	public static void main(String[]args)
	{
		Person p=new Person();
		System.out.println(p);
		System.out.println(p.toString());
	}
}

class Person
{
	public String  toString()
	{
		return "该通知表示方法已覆写。";
	}
}

/*
输出结果
该通知表示方法已覆写。
该通知表示方法已覆写。
*/

2.11 wait(long)

2.12 wait(long,int)

2.13 Object接收任意引用数据类型对象

2.13.1 接收方法的传入参数

public class ObjectArrayTest
{
	public static void main(String[] args)
	{
		int[] arr={1,2,3,4,5};
		Person p=new Person();
		p.print(arr);
	}
}

class Person
{
	public void print(Object o)
	{
		if(o instanceof int[])
		{
			int[] x=(int[]) o;
			for(int i=0;i<x.length;i++)
			{
				System.out.println(i);
				System.out.println(x[i]);
			}
		}
	}
}

其实这里用Object来接收引用数据类型参数增加复杂度了,如下代码13行所示,更简单:

public class ObjectArrayTest
{
	public static void main(String[] args)
	{
		int[] arr={1,2,3,4,5};
		Person p=new Person();
		p.print(arr);
	}
}

class Person
{
	public void print(int[] x)
	{
		for(int i=0;i<x.length;i++)
		{
			System.out.println(i);
			System.out.println(x[i]);
		}
	}
}

 2.13.2 接收数组的元素

class MyStack<T>
{
	private static final int STACK_CAPACITY=3;
	private T[] myStack;
	int top;							//栈顶索引
	// int size;						

	@SuppressWarnings("unchecked")
	public MyStack()
	{
		myStack=(T[]) new Object[STACK_CAPACITY];
		// myStack[++top]=data;
		top=-1;

	}
}

见上面代码第11行,java不能直接创建泛型数组(因为 Java 的泛型是基于擦除机制实现的,在运行时泛型类型信息会被擦除,所以无法确定具体的数组类型。),不能直接这样:

myStack=new T[STACK_CAPACITY];

那么将T[]替换成Object[],即创建Object数组,然后再进行强制类型转换就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值