[关闭]
@TryLoveCatch 2022-04-14T16:47:18.000000Z 字数 5998 阅读 561

Java知识体系之Object类

Java知识体系


getClass()

  1. public final native Class<?> getClass();

这是一个 final 类型的native方法,也就是说这个方法不能被子类重写,同时它的实现并不是通过Java语言实现的,而是用其他语言(C/C++)实现的,一般主要用在反射里面。
由于设计到JNI,所以这个方法是有一定耗时的是,使用的时候需要注意,还就是,toString()就使用了该方法。

toString()

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

返回一个 String 对象,一般子类都有覆盖。默认返回格式如下:对象的 class 名称 + @ + hashCode 的十六进制字符串。

调用到的方法:

equals() & hashcode()

  1. public native int hashCode();
  2. public boolean equals(Object obj) {
  3. return (this == obj);
  4. }

equals()和hashcode()关系

考虑一下HashMap,其实就是先判断hashCode再判断equals。

equals()原则

除了遵循这三原则之外,还要遵循:

equals() & ==

hashCode如何重写

关于相应的哈希算法,一个简单的算法如下:

组合公式:result = 31 * result + c

比如,String 类的 hashCode 方法如下(JDK 1.8):

  1. public int hashCode() {
  2. int h = hash;
  3. if (h == 0 && value.length > 0) {
  4. char val[] = value;
  5. for (int i = 0; i < value.length; i++) {
  6. h = 31 * h + val[i];
  7. }
  8. hash = h;
  9. }
  10. return h;
  11. }
  1. class Baz {
  2. private int id;
  3. private String name;
  4. private double weight;
  5. private float height;
  6. private String note;
  7. @Override
  8. public boolean equals(Object o) {
  9. if (this == o) return true;
  10. if (o == null || getClass() != o.getClass()) return false;
  11. Baz baz = (Baz) o;
  12. if (id != baz.id) return false;
  13. if (Double.compare(baz.weight, weight) != 0) return false;
  14. if (Float.compare(baz.height, height) != 0) return false;
  15. if (name != null ? !name.equals(baz.name) : baz.name != null) return false;
  16. return !(note != null ? !note.equals(baz.note) : baz.note != null);
  17. }
  18. @Override
  19. public int hashCode() {
  20. int result;
  21. long temp;
  22. result = id;
  23. result = 31 * result + (name != null ? name.hashCode() : 0);
  24. temp = Double.doubleToLongBits(weight);
  25. result = 31 * result + (int) (temp ^ (temp >>> 32));
  26. result = 31 * result + (height != +0.0f ? Float.floatToIntBits(height) : 0);
  27. result = 31 * result + (note != null ? note.hashCode() : 0);
  28. return result;
  29. }
  30. }

clone()

  1. protected native Object clone() throws CloneNotSupportedException;

为什么需要clone

目的是想要两个相同的对象,重新new一个还得自己重新赋值,太麻烦

深拷贝&浅拷贝

举个例子,一个男孩拥有一台电脑

浅拷贝实现

  • 需要拷贝的对象(Student)实现Cloneable接口
  • 重写clone()方法
    • 访问修饰符修改为public
    • 通过super.clone()调用Object类中的原clone方法。
  1. public class Student implements Cloneable {
  2. private String name;
  3. private Bag bag;
  4. public Student(String name,Bag bag) {
  5. this.name = name;
  6. this.bag = bag;
  7. }
  8. @Override
  9. public Student clone(){
  10. Student stu = null;
  11. try{
  12. stu = (Student)super.clone();
  13. } catch (CloneNotSupportedException e){
  14. e.printStackTrace();
  15. }
  16. return stu;
  17. }
  18. }
  19. //背包类
  20. public class Bag {
  21. private String name;
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. }

深拷贝实现

多层实现Cloneable类
  • 需要拷贝的对象(Student)以及其所有的对象成员变量(Bag)实现Cloneable接口
  • 重写clone()方法
    • 访问修饰符修改为public
    • 通过super.clone()调用Object类中的原clone方法。
    • 对于成员变量,都调用其重写的clone()方法
  1. public class Student implements Cloneable {
  2. private String name;
  3. private Bag bag;
  4. public Student(String name,Bag bag) {
  5. this.name = name;
  6. this.bag = bag;
  7. }
  8. // 这里不一样!!!!!
  9. @Override
  10. public Student clone(){
  11. Student stu = null;
  12. try{
  13. //浅克隆
  14. stu = (Student)super.clone();
  15. } catch (CloneNotSupportedException e){
  16. e.printStackTrace();
  17. }
  18. //深克隆
  19. stu.bag = (Bag)bag.clone();
  20. return stu;
  21. }
  22. }
  23. //背包类
  24. public class Bag {
  25. private String name;
  26. public Bag(String name) {
  27. this.name = name;
  28. }
  29. // 这里不一样!!!!!
  30. @Override
  31. public Bag clone(){
  32. Bag bag= null;
  33. try{
  34. bag= (Bag )super.clone();
  35. } catch (CloneNotSupportedException e){
  36. e.printStackTrace();
  37. }
  38. return bag;
  39. }
  40. }
利用序列化和反序列化
  • 需要拷贝的对象(Student)实现Serializable接口
  • 在需要拷贝的对象(Student)里面增加新方法,例如myClone()
    • 通过ObjectOutputStream和ObjectInputStream序列化和反序列化获取到新的对象
  1. // 这里不一样!!!!!
  2. public class Student implements Serializable {
  3. private String name;
  4. private Bag bag;
  5. public Student(String name,Bag bag) {
  6. this.name = name;
  7. this.bag = bag;
  8. }
  9. // 这里不一样!!!!!
  10. public Student myClone(){
  11. Student stu = null;
  12. try {
  13. //将对象序列化到流里
  14. ByteArrayOutputStream os = new ByteArrayOutputStream();
  15. ObjectOutputStream oos = new ObjectOutputStream(os);
  16. oos.writeObject(this);
  17. //将流反序列化成对象
  18. ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
  19. ObjectInputStream ois = new ObjectInputStream(is);
  20. stu = (Student) ois.readObject();
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. } catch (ClassNotFoundException e) {
  24. e.printStackTrace();
  25. }
  26. return stu;
  27. }
  28. }
  29. // 这里不一样!!!!!
  30. public class Bag implements Serializable {
  31. private String name;
  32. public Bag(String name) {
  33. this.name = name;
  34. }
  35. }

如果某个属性被transient修饰,那么该属性就无法被拷贝了。

finalize()

  1. protected void finalize() throws Throwable { }

finalize()方法是保护方法,主要用于在 GC 的时候再次被调用,如果我们实现了这个方法,对象可能在这个方法中再次复活,从而避免被 GC 回收。

finalize & final & finally

notify & notifyAll & wait

  1. public final native void notify();
  2. public final native void notifyAll();
  3. public final native void wait(long timeout) throws InterruptedException;
  4. public final void wait() throws InterruptedException {
  5. wait(0);
  6. }

都是final方法,不能被子类重写。

参考

https://www.sczyh30.com/posts/Java/java-hashcode-equal/
https://zhuanlan.zhihu.com/p/41880899

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注