Object类
java.lang.Object类所有类的根类,每个类都将Object作为超类,所有类的对象,包括数组都实现这个类的方法。常用的方法:
String toString():返回对象的字符串表示。假设Person定义如下所示,它默认继承了Object这个超类:
public class Person {
private String name;
private int age;
public Person() {
}
public Person(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;
}
}
如果我们直接使用toString方法来输出对象调用toString方法的结果,最后得到的对象的地址值,本质上和直接输出对象自己没有区别。public class ObjectMain { public static void main(String[] args) { Person person = new Person("Forlogen", 18); System.out.println(person); // Object.Person@1b6d3586 // 直接打印对象的名字本质上就是调用了对象的toString方法 String s = person.toString(); System.out.println(s); // Object.Person@1b6d3586
所以,为了更加是toString符合具体的应用场景,我们需要重写toString方法,在IDEA中使用自动生成得到:@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
如上所示,通过重写方法最后得到的是类的成员变量信息而不是对象的地址值。那么,我们再看一些Java内置的其他类是否也重写了toString方法:Random r = new Random(); System.out.println(r); // java.util.Random@74a14482
从输出结果可以看出,Random并没有重写toString方法。// 重写了toString Scanner sc = new Scanner(System.in); System.out.println(sc); // java.util.Scanner[delimiters=\p{javaWhitespace}+][position=0] ...
从输出结果可以看出,Scanner类重写了toString方法,我们通过源码看一下具体的重写过程:/** * <p>Returns the string representation of this <code>Scanner</code>. The * string representation of a <code>Scanner</code> contains information * that may be useful for debugging. The exact format is unspecified. * * @return The string representation of this scanner */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("java.util.Scanner"); sb.append("[delimiters=" + delimPattern + "]"); sb.append("[position=" + position + "]"); sb.append("[match valid=" + matchValid + "]"); sb.append("[need input=" + needInput + "]"); sb.append("[source closed=" + sourceClosed + "]"); sb.append("[skipped=" + skipped + "]"); sb.append("[group separator=" + groupSeparator + "]"); sb.append("[decimal separator=" + decimalSeparator + "]"); sb.append("[positive prefix=" + positivePrefix + "]"); sb.append("[negative prefix=" + negativePrefix + "]"); sb.append("[positive suffix=" + positiveSuffix + "]"); sb.append("[negative suffix=" + negativeSuffix + "]"); sb.append("[NaN string=" + nanString + "]"); sb.append("[infinity string=" + infinityString + "]"); return sb.toString(); }
重写过程中使用了StringBuilder来保存输出的结果,最后使用StringBuilder中的toString方法输出字符串。ArrayList<String> list = new ArrayList<>(); list.add("Forlogen"); list.add("kobe"); System.out.println(list); // [Forlogen, kobe]
可以看到ArrayList也重写了toString方法,但是在ArrayList的实现中并没有自己重写toString,而ArrayList继承了java.util包下的AbstractCollention类,该类中进行了toString方法的重写。 /** * Returns a string representation of this collection. The string * representation consists of a list of the collection's elements in the * order they are returned by its iterator, enclosed in square brackets * (<tt>"[]"</tt>). Adjacent elements are separated by the characters * <tt>", "</tt> (comma and space). Elements are converted to strings as * by {@link String#valueOf(Object)}. * * @return a string representation of this collection */ public String toString() { Iterator<E> it = iterator(); if (! it.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) { E e = it.next(); sb.append(e == this ? "(this Collection)" : e); if (! it.hasNext()) return sb.append(']').toString(); sb.append(',').append(' '); } }
重写的过程和Scanner是类似的。boolean equals(Object obj):指示其他某个对象是否和此对象相等,Object类中的equals方法实现代码为:
public boolean equals(Object obj) { return (this == obj); }
它实现了本身和传入的对象的对比。我们知道 == 对于引用类型来说,进行的是地址值的比较,所以如果不是两个完全相同的对象,那么得到的就是false。public class ObjectEquals { public static void main(String[] args) { Person person = new Person("Forlogen", 18); Person person1 = new Person("kobe", 24); System.out.println(person.equals(person1)); // false } }
同样为了具体的应用场景,通常需要重写equals方法:@Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Person)) return false; Person person = (Person) o; return getAge() == person.getAge() && Objects.equals(getName(), person.getName()); } @Override public int hashCode() { return Objects.hash(getName(), getAge()); }
Java内置的其它类中很多也重写了equals方法,如String中就进行了equals方法:/** * Compares this string to the specified object. The result is {@code * true} if and only if the argument is not {@code null} and is a {@code * String} object that represents the same sequence of characters as this * object. * * @param anObject * The object to compare this {@code String} against * * @return {@code true} if the given object represents a {@code String} * equivalent to this string, {@code false} otherwise * * @see #compareTo(String) * @see #equalsIgnoreCase(String) */ public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
通过对象直接调用public class ObjectEquals { public static void main(String[] args) { String s1 = "abc"; String s2 = "abc"; System.out.println(s1.equals(s2)); // true } }
通常为了避免使用equals方法出现空指针异常,可以使用Objects的equals方法:
public class ObjectEquals {
public static void main(String[] args) {
String s1 = null;
String s2 = "abc";
System.out.println(s1.equals(s2)); // 会出现空指针异常
System.out.println(Objects.equals(s1, s2)); // false
}
}