Java常用类(Object类及它的常用方法)

常见对象(API概述以及Object类的概述)

API(Application Programming Interface)
应用程序编程接口

Java API
就是Java提供给我们使用的类,这些类将底层的实现封装了起来,
我们不需要关心这些类是如何实现的,只需要学习这些类如何使用。

Object类概述
类层次结构的根类,即所有类的顶层父类
所有类都直接或者间接的继承自该类

构造方法
public Object(){
}
回想面向对象中为什么说:
子类的构造方法默认访问的是父类的无参构造方法

常见对象(Object类的hashCode()方法)

代码示例:

package org.westos.demo2;

/**
 * @Author: Administrator
 * @CreateTime: 2019-04-20 09:21
 */
public class MyTest {
    public static void main(String[] args) {  
        Object obj = new Object();           //创建Object类对象
        //看下Object中的成员方法,长按ctrl后鼠标点击Object类便可查看
        //int hashCode () 返回该对象的哈希码值。不同对象的哈希码值,是不一样的。
        //System.out.println(obj); 如果执行这条语句,打印的是局部变量obj里存放的地址值
        int i = obj.hashCode();
        System.out.println(i);
        Object obj2 = new Object();
        int i1 = obj2.hashCode();
        System.out.println(i1);
    }
}

Object类在 java.lang 包下, java.lang包下的类,使用时可以不用导包

查看到Object类中的hashCode()方法为:

public native int hashCode();

方法特点:

  • 返回该对象的哈希码值。默认情况下,该方法会根据对象的地址来计算。

  • 不同对象的,hashCode()一般来说不会相同。但是,同一个对象的hashCode()值肯定相同。

  • 不是对象的实际地址值,可以理解为逻辑地址值。

上述代码执行结果为:

356573597
1735600054

常见对象(Object类的getClass()方法)

package org.westos.demo2;

/**
 * @Author: Administrator
 * @CreateTime: 2019-04-20 09:28
 */
public class MyTest2 {
    public static void main(String[] args) {
       // Class getClass () 返回该类的字节码文件对象
        //万物皆对象
        //Object.class 字节码文件加载进内存-----JVM就会为Object.class文件创建一个对象。
        Object obj = new Object();
        Class clazz = obj.getClass(); //Object.class---->字节码文件对象。
        Object obj2 = new Object();
        Class aClass = obj2.getClass();
        Object obj3 = new Object();
        Class aClass1 = obj3.getClass();

        System.out.println(obj==obj2); //false   //局部变量中存放的是地址值,对象不一样,所以地址值肯定不一样
        System.out.println(clazz==aClass); //true
        System.out.println(aClass==aClass1);//true 因为类只有一个字节码文件,

    }
}

在Java语言中遵循万物皆对象的特点,所以在类的字节码文件被加载进内存后,JVM也会为该文件创建一个对象

查看到的Object类中的getClass方法为:

public final native Class getClass();

方法特点:

  • 返回此 Object 的运行时类,即类的字节码文件对象。

  • 可以通过Class类中的一个方法,获取对象的真实类的全名称。

上述代码运行结果为:

false
true
true

原因不再详述。

常见对象(Object类的toString()方法)

代码示例1:

package org.westos.demo3;

/**
 * @Author: Administrator
 * @CreateTime: 2019-04-20 09:36
 */
public class MyTest {
    public static void main(String[] args) {
        Object obj = new Object();
        String s = obj.toString(); //获取该对象的地址值的字符串表现形式
        System.out.println(s);
        Object o = new Object();
        System.out.println(o.toString());
        System.out.println(o);
     }
    }
}

在上述代码中调用了Object类的toString方法,该方法的具体实现如下

public String toString () {
            return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());

该方法可以返回对象的地址值的字符串表现形式,所以上述代码的运行结果为:

java.lang.Object@1540e19d
java.lang.Object@677327b6
java.lang.Object@677327b6

需要说明的一点,在我们之前的程序中为了区分两个对象是否一样,通常会采用System.out.println(o);语句来直接打印对象的地址来进行判断,实际上系统会默认在我们打印的对象后面加上.toString()来调用toString()方法获取对象的地址值的字符串表现形式。
但是也会存在下面的某种情况,当我打印对象时是想获得该对象的成员变量,那么我就可以在自定义类中对toString()进行重写。可以查看以下代码。

代码示例2:

package org.westos.demo3;

import java.net.SocketTimeoutException;

public class MyTest2 {
    public static void main(String[] args) {
        Student student = new Student();
        int i = student.hashCode();
        System.out.println(i);
        Class aClass = student.getClass();
        System.out.println(aClass.getName());
        System.out.println(student.toString());
        Student student1 = new Student("张三", 23);
        //System.out.println(student1.getName());
        //System.out.println(student1.getAge());
        student1.show();
        //一般情况下,我们自定义的类,都喜欢重写父类toString()方法,让他打印成员变量的值,当你根据你实际情况,可以打印其他任何内容
        System.out.println(student1.toString());
        //子类如果对父类的方法实现不满意,子类可以重写
    }
}

class Student {
    
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
        public void show(){
            System.out.println(name+"==="+age);
        }
    
        @Override
        public String toString() {
            return "姓名:"+this.name+"==="+"年龄"+this.age;
        }
    }

在上述代码中我定义了一个测试类和自定义类Student,在自定义类中对toString()方法进行了重写,之后再测试类中就可以通过直接打印对象名来获得对象的成员变量,所以上述代码最终运行结果为:

356573597
org.westos.test.Student
姓名:null===年龄0
张三===23
姓名:张三===年龄23

在该代码中还调用了获取到的类的字节码文件对象的方法,这个方法可以返回该对象的名字

源代码:

public String toString() {
       return getClass().getName() + "@" + Integer.toHexString(this.hashCode());
				}

它的值等于:

getClass().getName() + '@' + Integer.toHexString(对象名.hashCode()) 

由于默认情况下的数据对我们来说没有意义,一般建议重写该方法。 怎么重写?一般是将该类的所有的成员变量组成返回即可,也可以使用软件的快捷键来快速重写

利用软件重写toString()方法 alt+insert 选toStirng()方法,就会重写

常见对象(Object类的equals()方法)

A:案例演示
	a:指示其他某个对象是否与此对象“相等”。 
		源代码: 	
				public boolean equals(Object obj) {
    					return (this == obj);
				}
	b:默认情况下比较的是对象的引用是否相同。
	c:由于比较对象的引用没有意义,一般建议重写该方法。一般用于比较成员变量的值是否相等
	d:==和equals()的区别。(面试题)

常见对象(Object类的equals()方法代码优化)

equals()方法在Object类的定义中源码为:

public boolean equals(Object obj) {
        return (this == obj);
}

从代码中可以看出该方法比较的是两的对象的地址值,通过下面的代码引入equals()方法

代码示例:

package org.westos.demo5;

/**
 * @Author: Administrator
 * @CreateTime: 2019-04-20 10:03
 */
public class MyTest {
    public static void main(String[] args) {
        Object obj = new Object();
        Object obj2 = new Object();
        // boolean equals (Object obj) 判断两个对象的地址值是否相同
        System.out.println(obj == obj2);
        boolean b = obj.equals(obj2);
        System.out.println(b);
        System.out.println("---------------------");
        Student s1 = new Student("张三", 23);
        Student s2 = new Student("张三", 23);
        System.out.println(s1 == s2);//false
        //System.out.println(s1.equals(s2)); //true
       
        /*我觉得,s1.equals(s2) 比较两个对象的地址值,是否相同,对我来说意义不大,
        我认为的是,只要两个对象的成员变量的值一样,我就认为这两个对象一样。
        那么我就得重写父类的equals()方法,让他去比较两个对象的成员变量的值是否相同 */

         boolean b1 = s1.equals(new Teacher());//ClassCastException 类型转换异常
         System.out.println(b1);

         System.out.println("---------------");
         boolean b2 = s1.equals(s1);
         System.out.println(b2);
     }
}


class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
    this.name = name;
    this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    
    if (!(obj instanceof Student)) {
        return false;
    }
    
    //向下转型
    Student stu = (Student) obj;
    //字符串类,也认为父类的equals方法不满意,字符串这个类想要比较,两个字符串的内容是否相同
    // 所以字符串也重写了父类的equals方法 去比较两个字符串的内容是否相同
    return this.name.equals(stu.name) && this.age == stu.age;
    }
}

class Teacher {

}

在该代码中,可以看到equals()方法在Studnet类中被重写,重写需要实现比较成员变量的值的逻辑,实现描述如下:

  1. 如果是对象自己跟自己比,直接返回true
  2. 若不满足上述条件,则需要比较两个对象的成员变量的值,但在比较值前需要判断要和我比较的对象和我本身是不是同一类,如果不是,两个对象的成员变量的值肯定不相等,直接返回false,而在执行刚刚提到的判断时使用了一个关系运算符instanceof,作用是判断一个对象,是否是,该类型的一个对象,具体代码实现如下:

if (!(obj instanceof Student)) {
return false;
}

  1. 在判断完成后,如果是同一类或者有继承关系,就会执行下一阶段:判断成员变量的值,但是由于Object类是所以类的直接或间接父类,所以要想比较obj对象和student对象的成员变量值就必须让obj对象向下转型,转型完成后进行判断并且返回true或者false

通过重写equal()方法可以实现:

  1. 提高效率

  2. 提高健壮性(instanceof)

常见对象(Object类的clone() 方法)

​ clone()的权限修饰符是受保护的,在用的时候,让该类重写该方法,并把该方法的权限修饰符改为public

对象的克隆有两种:浅克隆深克隆
​使用clone()方法采用的是浅克隆的方式

对象浅克隆要注意的细节:

  1. 如果一个对象需要调用clone的方法克隆,那么该对象所属的类必须要实现Cloneable接口。

  2. Cloneable接口只不过是一个标识接口而已,没有任何方法。

  3. 对象的浅克隆就是克隆一个对象的时候,如果被克隆的对象中维护了另外一个类的对象,这时候只是克隆另外一个对象的地址,而没有把另外一个对象也克隆一份。

  4. 对象的浅克隆也不会调用到构造方法的。

对象的深克隆(后面讲):采用IO流来实现 使用 ObjectOutputStream 将对象写入文件中,然后再用ObjectInputStream读取回来

代码示例

public class MyTest {
	 public static void main(String[] args) throws CloneNotSupportedException {
		 Person p1 = new Person("狗娃", 23);
		 Person p2 = (Person) p1.clone();
		        p2.name="张三";
		        p2.age=30;
			System.out.println(p1);
			System.out.println(p2);
	    System.out.println("---------------------------");
		 Address address = new Address("北京");
		Person p3 = new Person("王五", 25, address);
		Person p4 = (Person) p3.clone();
		p4.name="赵六";
		p4.age=36;
		p4.address.city="上海";
		System.out.println(p3);
		System.out.println(p4);


}

}
class Person implements Cloneable{     //主方法中要对p1、p2对象进行浅克隆,所以person类必须要实现Cloneable接口
    public String name;
    public int age;
    public Address address;
    public Person(String name, int age) {     //有参构造
        this.name = name;
        this.age = age;
    }
    public Person(String name, int age, Address address) {    //有参构造的重载
        this.name = name;
        this.age = age;
        this.address = address;
}

    @Override
    public Object clone() throws CloneNotSupportedException {    //重写,要抛出异常,将权限修饰符修改为
    return super.clone();
}

    @Override
    public String toString() {     //重写Tostring方法
        return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", address=" + address +
            '}';
    }
}

class Address{
    public String city;
    public Address(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
             return "Address{" +
            "city='" + city + '\'' +
            '}';
    }
}
  1. 如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出
    CloneNotSupportedException 异常。所以在主方法后面会出现 throws CloneNotSupportedException
  2. 在重写clone方法时要将权限修饰符修改为public,而且方法内部还是使用clone方法在父类当中的逻辑

你可能感兴趣的:(新手求指教,求一起探讨)