Java学习随笔小计(1)

Java中 == 和 equals() 有何区别

==

  • 概念:== 等于比较运算符,如果进行比较的两个操作数都是数值类型,即使他们的数据类型不相同,只要他们的值相等,也都将返回true.如果两个操作数都是引用类型,那么只有当两个引用变量的类型具有父子关系时才可以比较,而且这两个引用必须指向同一个对象,才会返回true
  • 对于基本数据类型,比较值是否相等;对于引用数据类型,比较两个变量的内存地址是否相等

equals()

  • 概念:equals()方法是Object类的方法,在Object类中的equals()方法体内实际上返回的就是使用==进行比较的结果
  • 比较最终指向的值的内存地址,而非直接比较变量的内存地址

重写equals()方法

  • 所有的类都继承至Object类,而且Object中的equals()方法没有使用final关键字修饰,如果我们需要使用equals()方法进行比较,需要关注是否重写了equals()方法,例如下方代码块
class User {
        String name;
        int age;

        //重写其equals()
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (obj instanceof User) {
                User u = (User) obj;
                return this.age == u.age && this.name.equals(u.name);
            }
            return false;
        }
    }

Java垃圾回收机制

  • 垃圾回收机制只回收JVM堆内存里的对象空间,对其他物理连接,例如数据库连接、I/O流、Socket连接无能为力
  • 垃圾回收的发生具有不可预知性,程序无法精确控制垃圾回收机制执行
  • 可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否立即进行垃圾回收依然是不确定的
  • 垃圾回收机制回收任何对象之前,会先调用它的finalize()方法,如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活该对象
  • 可以将对象的引用变量设置为null,暗示垃圾回收机制可以对该对象进行回收
  • 不要主动调用某个对象的finalize()方法,应该交给垃圾回收机制调用
  • 现在的JVM有多种垃圾回收实现算法,表现各异,有兴趣可深入了解

finally代码块执行情况

try-catch-finally代码块的执行顺序

  • 通常情况下,finally代码块会在try代码块的return之前执行
  • catch到异常时,finally代码块会在catch代码块return或结束之前执行
  • 当finally代码块中对变量值进行修改而无return时,对象的值仍会返回未修改前的值
  • 当finally代码块中对变量值进行修改且包含return时,try或catch的return语句不会执行,变量的值修改成功(避免在finally代码块里出现return语句)

finally代码块不执行的情况

  • 不进入try代码块,finally代码块自然不会被执行
  • 在进入try或catch代码块时调用System.exit()强制终止虚拟机
  • 非守护线程被中止时。Java线程分为守护线程和非守护线程两类,当所有的非守护线程中止时,不论是否还有非守护线程未结束,Java虚拟机都会kill掉守护线程中止程序。例如,main方法线程是一个非守护线程,而垃圾回收机制是一个守护线程,main方法执行结束,程序就中止了,不管垃圾回收机制是否中止都会被kill。因此如果守护线程中存在finally代码块,而所有的非守护线程都结束时,守护线程被kill,finally代码块就不会被执行到,如下方代码demo
public class Test {
    public static void main(String[] args) {
        Thread t = new Thread(new Task());
        t.setDaemon(true); //置为守护线程
        t.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException("the " + Thread.currentThread().getName() + " has been interrupted", e);
        }
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println("enter run()");
        try {
            System.out.println("enter try block");
            TimeUnit.SECONDS.sleep(5); //阻塞5s
        } catch (InterruptedException e) {
            System.out.println("enter catch block");
            throw new RuntimeException("the " + Thread.currentThread().getName() + " has been interrupted", e);
        } finally {
            System.out.println("enter finally block");
        }
    }
}
/**
 * 控制台打印如下
 * enter run()
 * enter try block
 */

finally代码块存在的意义就是一定会被执行的代码块,因此只需知道finally代码块何时不会被执行,尽量避免该类操作

上一篇:对于JAVA异常的小总结


下一篇:C# 中 finally 的用法