天天看点

Java学习笔记一面向对象Object类

Object类

toString方法

Java对象都是Object类的实例,都可直接调用该类中定义的方法,这些方法提供了处理Java对象的通用方法。

class Person
{
  private String name;
  public Person(String name)
  {
    this.name = name;
  }
}
public class PrintObject
{
  public static void main(String[] args){
    Person p = new Person("hello");
    System.out.println(p);  // 输出:Person@15db9742
    System.out.println(p.toString());  // 输出:Person@15db9742
  }
}      

System.out.println(类对象的引用)实际上是调用该类对象继承的Object类的toString方法。并且Java对象和字符串连接时,系统自动调用toString方法和字符串进行连接运算。

String pStr = p + "";
String pStr = p.toString() + "";      

Object类的toString方法总是返回该对象实现类的“类名+@+hashCode”值,这个返回值并不能真正实现自我描述功能,如果用户需要自定义实现自我描述功能,就需要重写Object类的toString方法。

equals方法

equals方法是Object类提供的一个实例方法,所有引用变量都可以调用该方法来判断是否与其他引用变量相等。但使用这个方法判断两个对象相等的标准与使用==运算符没有区别,同样要求两个引用变量指向同一对象才会返回true。因此Object类提供的equals方法没有太大意义,一般需要重写该方法。比如String已经重写Object的equals方法,String的equals方法判断两个字符串相等的标准:只要两个字符串所包含的字符序列相同,通过equals比较将返回true,否则将返回false。

class Person
{
  private String name;
  private String idStr;
  public Person() {}
  public Person(String name, String idStr){
    this.name = name;
    this.idStr = idStr;
  }
  public boolean equals(Object obj){
    //如果两个对象为同一对象
    if(this == obj)
      return true;
    //只有当obj是Person对象
    if(obj!=null && obj.getClass() == Person.class)
    {
      Person personobj = (Person)obj;
      //并且当前对象的idStr与obj对象的idStr相等时才可判断两个对象相等
      if(this.getIdStr().equals(personobj.getIdStr()))
        return true;
    }
    return false;
  }
}
public class OverrideEqualsRight
{
  public static void main(String[] args)
  {
    Person p1 = new Person("孙悟空", "1234343433433");
    Person p2 = new Person("孙行者", "1234343433433");
    Person p2 = new Person("孙悟饭", "99933433");
    System.out.println("p1和p2是否相等:"+p1.equals(p2)); // true
    System.out.println("p2和p3是否相等:"+p2.equals(p3)); // false
  }
}      

判断obj是否为Person类的实例可以使用instanceof嘛?

对于instanceof运算符,前面对象是后面类的实例或其子类的实例都将返回true,所以重写equals方法判断两个对象是否为同一个类的实例时使用Instanceof是有问题的。比如Teacher类型变量t,如果t instanceof Person,这也将返回true。但对于重写equals方法而言,通常要求两个对象是同一个类的实例,因此使用instanceof运算符不太合适。

finalize方法

在垃圾回收机制回收某个对象所占用的内存之前,通常要求程序调用适当的方法来清理资源,在没有明确指定清理资源的情况下,Java提供了默认机制来清理该对象的资源,这个机制就是finalize方法。该方法是定义在Object类里的实例方法,方法原型:​

​protected void finalize() throws Throwable​

​​ 当finalize方法返回后,对象消失,垃圾回收机制开始执行。方法原型中的throws Throwable表示它可以抛出任何类型的异常。

任何Java类都可以重写Object类的finalize方法,在该方法中清理该对象占用的资源。如果程序终止之前始终没有进行垃圾回收,则不会调用失去引用对象的finalize方法来清理资源。垃圾回收机制何时调用对象的finalize方法是完全透明的,只有当程序认为需要更多的额外内存时,垃圾回收机制才会进行垃圾回收。因此,完全有可能出现这样一种情形:某个失去引用的对象只占用了少量内存,而且系统没有产生严重的内存需求,因此垃圾回收机制并没有试图回收该对象所占用的资源,所以该对象的finalize方法也不会得到调用。

finalize方法具有如下特点:

  • 永远不要主动调用某个对象的finalize方法,该方法应交给垃圾回收机制调用
  • finalize方法何时被调用,是否被调用具有不确定性,不要把finalize方法当成一定会被执行的方法
  • 当JVM执行可恢复对象的finalize方法时,可能使该对象或系统中其他对象重新变成可达状态。
  • 当JVM执行finalize方法时出现异常时,垃圾回收机制不会报告异常,程序继续执行。

getClass方法

hashCode方法

在默认情况下,Object类的hashCode()方法根据该对象的地址来计算(即与System.identityHashCode(Object x)方法的计算结果相同)。但很多类都重写了Object类的hashCode()方法,不再根据地址来计算其hashCode()方法值。

clone方法

Java提供了一个protected修饰的clone方法,该方法用于帮助其他对象来实现“自我克隆”,就是得到一个当前对象的副本,而且二者之间完全隔离。由于Object类提供的clone方法使用了protected修饰,因此该方法只能被子类重写或调用。

自定义实现克隆的步骤:

  1. 自定义类实现Cloneable接口。这是一个标记性的接口,实现该接口的对象可以实现自我克隆,接口里没有定义任何方法。
  2. 自定义类实现自己的clone方法
  3. 实现clone方法通过super.clone();调用Object实现的clone方法来得到该对象的副本,并返回该副本。

    Object类提供的Clone机制只对对象里各实例变量进行简单复制,如果实例变量的类型是引用类型,Object的Clone机制也只是简单地复制这个引用变量,这样原有对象的引用类型的实例变量与克隆对象的引用类型的实例变量与克隆对象的引用类型的实例变量依然指向内存中的同一个实例。这和C++中的浅拷贝类似。

    浅克隆-只克隆该对象的所有成员变量值,不会对引用类型的成员变量值所引用的对象进行克隆。

    深克隆-需要开发者自己进行递归克隆,保证所有引用类型的成员变量值所引用的对象都被复制了。

class Address{
    String detail;
    public Address(String detail){ this.detail = detail; }
}
//实现Cloneable接口
class User implements Cloneable
{
    int age;
    Address address;
    public User(int age)
    {
        this.age = age;
        address = new Address("上海");
    }
    //调用super.clone()来实现clone方法
    public User clone() throws CloneNotSupportedException
    {
        return (User)super.clone();
    }
}
public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        User u1 = new User(29);
        //clone得到u1对象的副本
        User u2 = u1.clone();
        //判断u1和u2是否相同
        System.out.println(u1 == u2);
        //判断u1和u2的address是否相同
        System.out.println(u1.address == u2.address);
    }
}      

Java 7新增的Objects类

public class ObjectsTest{
  //定义一个obj变量,默认值是null
  static ObjectsTest obj;
  public static void main(String[] args){
    //输出一个null对象的hashCode值,输出0
    System.out.println(Objects.hasnCode(obj));
    //输出一个null对象的toString,输出null
    System.out.println(Objects.toString(obj));
    //要求obj不能null,如果obj为null则引发异常
    System.out.println(Objects.requireNonNull(obj, "obj参数不能是null!"));
  }
}