————————————
想要了解clone方法的小伙伴,可以看看之前所讲解 原型模式
getClass()
getClass方法是干什么的呢?首先,getClass方法用于获取一个对象的运行时类(Class),进而通过返回的Class对象,获取该类的相关信息,比如获取该类的构造方法、该类有哪些方法、该类有哪些成员变量等信息。
// Java用native方法实现 getClass() public final native Class<?> getClass(); // Android 特殊的实现方式 private transient Class<?> shadow$_klass_; public final Class<?> getClass() { return shadow$_klass_; }
Java默认的Hotspot虚拟机并没有开辟单独的Method Area空间,而是有GC Heap的老生代的Metaspace实现的。而Android采用ART VM,这才造成了这种差异。大黄:这是因为是
finalize()
finalize()方法,是Object的protected方法,在发生GC时触发该方法。
该方法的大致流程,是当对象变成GC Roots不可达时,GC判断该对象是否覆盖了finalize()方法,若未覆盖,则直接将其回收;否则,若对象未执行过finalize()方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize()方法。
执行finalize()方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收;否则,对象“复活”。
子类可以override该方法,用于防止对象被回收,亦或是防止对象不被回收。
要防止对象被回收,只需让该对象与GC ROOTS之间存在可达链即可。
我们重点看看FileInputStream、FileOutputStream、Connection等类怎么防止用户忘记释放资源吧,如下是FileInputStream的部分源码:
protected void finalize() throws IOException { // Android新增 CloseGuard确保FlieInputStream回收更安全 if (guard != null) { guard.warnIfOpen(); } //Java利用 FileDescriptor确保FileInputStream不可达,可以被安全回收 if ((fd != null) && (fd != FileDescriptor.in)) { close(); } }
toString()
toString()方法,恐怕是大家最常用的方法了,该方法返回该对象的String表示。
举个例子,Integer的toString()方法,就针对Android做了一定适配:
public String toString() { return toString(this.value); } //返回指定十进制整数的 String public static String toString(int i) { if (i == Integer.MIN_VALUE) return "-2147483648"; // small是 Android特有的变量,用二维Array缓存较小(两位数)数字的 String boolean negative = i < 0; boolean small = negative ? i > -100 : i < 100; if (small) { final String[] smallValues = negative ? SMALL_NEG_VALUES : SMALL_NONNEG_VALUES; if (negative) { i = -i; if (smallValues[i] == null) { smallValues[i] = i < 10 ? new String(new char[]{'-', DigitOnes[i]}): new String(new char[]{'-', DigitTens[i], DigitOnes[i]}); } } else { if (smallValues[i] == null) { smallValues[i] = i < 10 ? new String(new char[]{DigitOnes[i]}): new String(new char[]{DigitTens[i], DigitOnes[i]}); } } return smallValues[i]; } int size = negative ? stringSize(-i) + 1 : stringSize(i); // getChars()方法略 char[] buf = new char[size]; getChars(i, size, buf); return new String(buf); }
equals() 和 hashcode()
public boolean equals(Object obj) { return (this == obj); }
想要比较值是否相同,该怎么办呢?需要重写equals()。
重写equals(),要注意以下几点注意事项:
(1)对任意x,x.equals(x)一定返回true
(2)对任意x,y,如果x.equals(y)返回true,则y.equals(x)也一定返回true
(3)对任意x,y,z,如果x.equals(y)返回true,y.equals(z)也返回true,则x.equals(z)也一定返回true
(4)对任意x,y,如果对象中用于比较的信息没有改变,那么无论调用多少次x.equals(y),返回的结果应该保持一致,要么一直返回true,要么一直返回false
(5)对任意不是null的x,x.equals(null)一定返回false
下面,我们先看一下String类是如何实现equals方法的:
//比较这个String和另一个对象,当且仅当那个对象不为null,且与这个String有相同的字符排列顺序时返回true public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = length(); if (n == anotherString.length()) { int i = 0; while (n-- != 0) { if (charAt(i) != anotherString.charAt(i)) return false; i++; } return true; } } return false; }
接下来,我们再看一下String类是如何实现hashcode方法的:
//缓存String的hashcode() private int hash; // 默认为0 public int hashCode() { int h = hash; final int len = length(); if (h == 0 && len > 0) { for (int i = 0; i < len; i++) { h = 31 * h + charAt(i); } hash = h; } return h; }
如果两个对象的hashCode返回值相同,但它们的equals()方法却有可能最终返回false,这种情况叫做hash碰撞。
熟悉HashMap底层原理的朋友,对这个概念一定不会陌生。