• JAVA-Object


    Object类是所有类的基类,了解他很是重要

    分类来看Object类的方法

    1. hashCode()和equals(Object obj)
    2. clone()
    3. notify()、notifyAll()、wait(long timeout)、wait(long timeout, int nanos)、wait()
    4. finalize()
    5. toString()

    hashCode & equals

    hashCode()方法由native方法底层实现,默认由对象的地址转换而来,对底层是散列表的对象有提升性能的功能。

    • 同一个对象(如果该对象没有被修改):那么重复调用hashCode()那么返回的int是相同的

    equals()方法默认是比较对象的地址,使用的是==等值运算符

    • 传入的参数为null,返回的是false

    二者关系

    • 重写equals()方法,就必须重写hashCode()的方法
    • 同一个对象(如果该对象没有被修改):那么重复调用hashCode()那么返回相同、重复调用equals返回相同

    todo: hashCode和HashMap的key的关系:看一下美团技术团队的文章

    todo: 如何编写hashCode和equals方法

    要注意这两个方法在集合、容器上的作用,可以看另一篇介绍集合和容器的文章;另外这两个方法对于一些compare接口的实现可能也有着作用效果,值得注意

    clone

    todo: 值得注意的是深拷贝和浅拷贝问题

    克隆的对象要实现Cloneable接口(该接口没有任何方法),重写clone方法。

    Address address = new Address(1, 2, 3);
    address.clone();//error
    

    上面的代码不能执行成功,因为clone在Object中是protected方法,而Address和Object不在同一包之下

    wait & notify

    调用这些方法必须持有锁,即必须在synchronized中调用(todo: ???可不可以被lock包围???),否则会抛出异常。

    调用wait()的线程会释放掉锁。导致wait()的线程被唤醒可以有4种情况

    • 该线程被中断

    • wait()时间到了

    • 被notify()唤醒

    • 被notifyAll()唤醒

    notify()唤醒的是在等待队列的某个线程(不确定会唤醒哪个),notifyAll()唤醒的是等待队列所有线程。notifyAll()唤醒所有进程后,哪个线程接下来能够获取到锁要具体依赖于操作系统的调度。被唤醒之后不意味着立刻就能获得到锁。

    • notify方法调用后,被唤醒的线程不会立马获得到锁对象。而是等待notify的同步代码块执行完之后才会获得锁对象
    • Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权。主要的区别在于锁释放上面:Object.wait()在释放CPU同时,释放了对象锁的控制。而Thread.sleep()没有对锁释放
    • wait和notify方法均可释放对象的锁,但wait同时释放CPU控制权,即它后面的代码停止执行,线程进入阻塞状态,而notify方法不立刻释放CPU控制权,而是在相应的synchronized(){}语句块执行结束,再自动释放锁

    要注意这些方法在并发上的作用,可以看另一篇介绍并发库文章,值得注意

    finalize

    finalize()在垃圾回收器清除对象之前调用,一般不会重写。如非必要,尽量避免使用finalize。finalize不应该用来管理socket, file handle, database connection等昂贵资源,因为finalize是在object被GC的时候才调用——如果内存足够,它可能永远都不会被调用。

    对于关闭JVM的时候必须要做的事情,应该用Runtime#addShutdownHook(Thread hook)来实现,放到finalize里面的code并不保证在这个时候会被调用

    即使Override了finalize,事情也没有那么简单,首先,override了finalize的object并不是和其他情况下一样直接释放内存,也不是直接调用finalize,而是放到finalizing queue,由JVM上一个单独的thread来进行处理,同时你要当心在finalize里面不小心调用了code,把object自己重新reference到——这个时候它就复活了,可能事情做到一半,又从finalizing queue里面拿出来了,造成不稳定的状态——这种风险是不值得绝大多数情况下的应用场景的。

    Java的垃圾回收器只会释放由我们new出来的内存堆块,那些不是由new出来的“特殊内存”,垃圾回收器是不会管理的。这些所谓的特殊内存指通过JNI用C/C++向系统申请的内存,这些内存如果不手动去清除就会一直占据在内存中。

    finalize在对象被垃圾收集器析构(回收)之前调用,finalize()方法由GC至多执行一次(用户当然可以手动调用对象的finalize()方法,但并不影响GC对finalize()的行为)。

    执行流程:当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。

    finalize清理可以用于:

    1. 清理本地对象(通过JNI创建的对象);
    2. 确保某些非内存资源(如Socket、数据库、文件等)的释放:在finalize()方法中显式调用其他资源释放方法。

    需要注意执行 super.finalize();

  • 相关阅读:
    Java开源框架推荐(全)
    Java性能提示(全)
    国外程序员整理的 C++ 资源大全 (zt)
    技术杂记之:在阿里云centos7上部署JDK MYSQL TOMCAT
    技术杂记之:vi使用入门
    Java全栈程序员之09:IDEA+GitHub
    SpringCloud无废话入门05:Spring Cloud Gateway路由、filter、熔断
    SpringCloud无废话入门04:Hystrix熔断器及监控
    SpringCloud无废话入门03:Feign声明式服务调用
    SpringCloud无废话入门02:Ribbon负载均衡
  • 原文地址:https://www.cnblogs.com/cheaptalk/p/12549714.html
Copyright © 2020-2023  润新知