Java基础知识(引用,单例)

540 阅读3分钟

1、Java中有哪几种引用?它们的含义和区别是什么?

  1. 强引用

只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象

Obejct obj = new Object();
obj = null;//强行中断引用可以赋值为Null
  1. 软引用(SoftReference)

有用但是不必须对象 , 只有在内存不足的时候JVM才会回收该对象

Object obj = new Object();
SoftReference<Object> sr = new SoftReference<>(obj);
Object obj2 = sr .get();
  1. 弱引用(WeakReference)

当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象

Object obj = new Object();
WeakReference<Object> wr= new WeakReference<>(obj);
wr.get();
  1. 虚引用(PhantomReference)

虚引用不会决定对象的生命周期,如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解 被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

2、请用Java实现一个线程安全且高效的单例模式。

1.静态内部类

public class A {
    public A(){
    }
    public A getInstance(){
        return B.sInstance;
    }
    private static class B{
        private static final A sInstance = new A();
    }
}

利用类加载机制来保证只创建一个Instance实例,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会去创建单例对象

不安全的地方: (1) 可以被反射强行调用私有构造器 (2) 需要额外的工作来实现序列化,否则反序列化的时候,都会创建新的实例

静态内部类实现线程安全的原因:

  1. 内部类加载时机是在类被调用的时候,也就是A.getInstance(),B才会加载,属于延迟加载
  2. static 对象具有唯一性,只会在类加载的时候初始化一次

2.双重锁定检查(DCL)

public class A implements Serializable {
    private A(){
    }

    private static  volatile A sInstance ;

    public static A getInstance(){
            if (sInstance   != null){
                synchronized (A.this){
                    if (sInstance   != null){
                        sInstance   = new A();
                    }
                }
            }
        return sInstance;
    }

   //序列化安全
    private Object readResolve(){
        return sInstance;
    }
}

防止序列化,消除指令重排对单例的影响

3、为什么Java内部类要设计成静态和非静态两种。

根据Oracle官方的说法:Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are called static nested classes. Non-static nested classes are called inner classes.

从字面上看,一个被称为静态嵌套类,一个被称为内部类。

什么是嵌套?嵌套就是我跟你没关系,自己可以完全独立存在,但是我就想借你的壳用一下,来隐藏一下我自己。 什么是内部?内部就是我是你的一部分,我了解你,我知道你的全部,没有你就没有我。(所以内部类对象是以外部类对象存在为前提的)