Java中有一个比较特殊的类,就是 Object类,它是所有类的父类,如果一个类没有使用extends关键字明确标识继承另外一个类,那么这个类就默认继承 Object类。因此,Object 类是 Java 类层中的最高层类,是所有类的超类。换句话说,Java 中任何一个类都是它的子类。由于所有的类都是由 Object 类衍生出来的,所以 Object 类中的方法适用于所有类。
在Object类里面定义toString()方法的时候返回的对象的哈希code码(对象地址字符串);
可以通过重写toString()方法表示出对象的属性。
此方法是在打印对象时被调用的,下面有两个范例,一个是没复写toString()方法,另一个是复写了 toString()方法,读者可比较两者的区别。
package educoder;
public class TestToStringDemo1 {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p);
}
}
class Person extends Object {
String name = "张三";
int age = 18;
}
输出结果:
educoder.Person@7852e922
从上面的程序中可以发现,在打印对象p的时候实际上打印出的是一些无序的字符串,这样的字符串很少有人能看懂什么意思,之后可以再观察下面的范例,下面的范例复写了Object类中的 toString()方法。
package educoder;
public class TestToStringDemo2 {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p);
}
}
class Person extends Object {
String name = "张三";
int age = 18;
// 复写Object类中的toString()方法
public String toString() {
return "我是:" + this.name + ",今年:" + this.age + "岁";
}
}
输出结果:
我是:张三,今年:18岁
与 TestToStringDemo1.java 程序相比,程序TestToStringDemo2.java 在 Person
类中明确复写了 toString()方法,这样在打印对象p的时候,实际上是去调用了 toString()方法,只是并没有明显的指明调用 toString()方法而已,此时第 6 行相当于:
System.out.println(p.toString());
比较的是对象的引用是否指向同一块内存地址,一般情况下,比较两个对象时是比较它的值是否一致,那如何解决呢?思路也比较简单,重写equals()方法。
在不重写的情况下,我们先看下程序执行情况,创建两个相同类型的对象,并判断对象是否相等。
package educoder;
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "jack";
Dog dog1 = new Dog();
dog1.name = "jack";
System.out.println(dog);
System.out.println(dog1);
if (dog.equals(dog1)) {
System.out.println("两个对象是相同的");
} else {
System.out.println("两个对象是不相同的");
}
}
}
class Animal {
}
class Dog extends Animal {
int age = 20;
String name = "rose";
public String toString() {
return "Dog [age=" + age + ", name=" + name + "]";
}
}
输出结果:
Dog [age=20, name=jack]
Dog [age=20, name=jack]
两个对象是不相同的
分析下 : 两个对象分别new了一次,开辟了两个不同内存空间,内存地址不同。object提供的equals()是用来比较的是对象的引用是否指向同一块内存地址。很显然,内存地址不一样,所以是不相等的,跟属性值是否一样完全没有任何关系。
一般情况下,我们是需要判断对象的属性值相等的,那么如何重写 equals()方法呢?通过Eclipse(集成开发环境)提供的快捷键,Dog类中出现如下方法,方法的解释也放在代码中一并进行解释如下:
package educoder;
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "jack";
Dog dog1 = new Dog();
dog1.name = "jack";
System.out.println(dog);
System.out.println(dog1);
if (dog.equals(dog1)) {
System.out.println("两个对象是相同的");
} else {
System.out.println("两个对象是不相同的");
}
}
}
class Animal {
}
class Dog extends Animal {
int age = 20;
String name = "rose";
public String toString() {
return "Dog [age=" + age + ", name=" + name + "]";
}
/* getClass() 得到的是一个类对象 */
@Override
public boolean equals(Object obj) {
if (this == obj)// 两个对象的引用是否相同,如果相同,说明两个对象就是同一个
return true;
if (obj == null)// 如果比较对象为空,不需要比较,肯定不相等
return false;
if (getClass() != obj.getClass())// 比较两个对象的类型是否相同,如果不同,肯定不相同
return false;
Dog other = (Dog) obj;// 转化成相同类型后,判断属性值是否相同
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
输出结果:
Dog [age=20, name=jack]
Dog [age=20, name=jack]
两个对象是相同的
equals() 和 == 的区别:
首先,不能用于基本数据类型的变量之间的比较相等;
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类都对equals方法进行了重写,比较的是所指向的对象的内容。
对象克隆是一种创建对象的精确副本的方法。 Object类的clone()方法用于克隆对象。java.lang.Cloneable接口必须由我们要创建其对象克隆的类实现。如果我们不实现Cloneable接口,clone()方法将生成CloneNotSupportedException。
clone()方法在Object类中定义。 clone()方法的语法如下:
protected Object clone() throws CloneNotSupportedException
为什么要使用clone()方法?
clone()方法保存用于创建对象的精确副本的额外处理任务。 如果我们使用new关键字执行它,它将需要执行大量的处理,这就是为什么我们使用对象克隆。
对象克隆的优点:
少处理任务。
clone()方法示例(对象克隆)
package educoder;
public class Student implements Cloneable {
int rollno;
String name;
Student(int rollno, String name) {
this.rollno = rollno;
this.name = name;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String args[]) {
try {
Student s1 = new Student(101, "amit");
Student s2 = (Student) s1.clone();
System.out.println(s1.rollno + " " + s1.name);
System.out.println(s2.rollno + " " + s2.name);
} catch (CloneNotSupportedException c) {
}
}
}
输出结果:
101 amit
101 amit
从上面的例子可以看出,两个引用变量都有相同的值。 因此,clone()将对象的值复制到另一个对象。 因此,在实际应用中我们不需要编写显式代码将对象的值复制到另一个对象。如果通过new关键字创建另一个对象并将另一个对象的值赋给这个对象,则需要对该对象进行大量处理。 所以为了节省额外的处理任务,我们使用clone()方法。
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
Demo类和Person类已经写好,在测试类中创建Demo类对象d1,传入输入值num1, d1调用toString方法并打印输出该值;
创建Demo类对象d2,同样传入输入值num1,打印判断d1和d2是否相等(实际是比较地址);
创建Person类对象p,传入输入值num2,打印判断d1和p是否相等(实际是比较地址);
package case1;
import java.util.Scanner;
public class ObjectTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();
int num2 = sc.nextInt();
// 在测试类中创建Demo类对象d1,传入输入值num1, d1调用toString方法并打印输出该值
// 创建Demo类对象d2,同样传入输入值num1,打印判断d1和d2是否相等(实际是比较地址)
/********* Begin *********/
Demo d1 = new Demo(num1);
System.out.println(d1.toString());
Demo d2 = new Demo(num1);
if(d1.equals(d2)){
System.out.println("true");
}else{
System.out.println("false");
}
Person p = new Person(num2);
if(d1.equals(p)){
System.out.println("true");
}else{
System.out.println("false");
}
/********* End *********/
// 创建Person类对象p,传入输入值num2,打印判断d1和p是否相等(实际是比较地址)
/********* Begin *********/
/********* End *********/
}
}
class Demo {
private int num;
public Demo(int num) {
this.num = num;
}
public boolean equals(Object obj) // Object obj = new Demo()
{
if (!(obj instanceof Demo)) // 判断obj是否和Demo是同类
return false;
Demo d = (Demo) obj; // 将父类的引用(Object)向下转换为子类(Demo)
return this.num == d.num;
}
public String toString() {
return "Demo:" + num; // 返回对象的值(每一个对象都有自己的特定的字符串)
}
}
class Person {
private int num;
public Person(int num) {
this.num = num;
}
}