乐趣区

关于后端:Java后端面试题答案2



final finally finalize

  • final 能够润饰类、变量、办法,润饰类示意类不能够被继承,润饰变量示意变量不能够被从新赋值,是一个常量,润饰办法示意这个办法是最终的,不能被重写。
  • finally 代码块个别配合 try-catch 应用,在解决异样的时候,通常咱们将肯定要执行的代码办法 finally 代码块 中,示意不论是否出现异常,该代码块都会执行,个别用来寄存一些敞开资源的代码。
  • finalize 是一个办法,属于 Object 的一个办法,而 Object 类是所有类的父类,该办法个别由垃圾回收器调用,当咱们手动启动 GC(调用 System.gc())时,由垃圾回收器调用 finalize 办法。

对象的四种援用

1. 强援用(FinalReference)

强援用是 Java 中最为常见的一种援用形式,只有援用存在,就不会被垃圾回收器回收。

Object obj = new Object();
User user = new User();

可间接通过 obj 获得对应的对象 如 obj.equels(new Object()); 而这样 obj 对象对前面 new Object 的一个强 援用,只有当 obj 这个援用被开释之后,对象才会被开释掉,这也是咱们常常所用到的编码模式。
如果想中断强援用和某个对象之间的关联,能够显式地将援用赋值为 null,这样的话,JVM 在适合的工夫就会回收该对象。

2. 弱援用(WeakReference)

// 示例 1 
WeakReference<String[]> weakBean = new WeakReference<String[]>(new String[]{"a", "b", "c"});
// 示例 2 
ReferenceQueue<String[]> referenceQueue = new ReferenceQueue<String[]>();
WeakReference<String[]> softBean = new WeakReference<String[]>(new String[]{"a", "b", "c"}, referenceQueue);

弱援用就是只有 JVM 垃圾回收器发现了它,就会将之回收, 弱援用与软援用的区别在于:只具备弱援用的对象领有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具备弱援用的对象,不论以后内存空间足够与否,都会回收它的内存。不过,因为垃圾回收器是一个优先级很低的线程,因而不肯定会很快发现那些只具备弱援用的对象。
弱援用能够和一个援用队列(ReferenceQueue)联结应用,如果弱援用所援用的对象被垃圾回收,Java 虚拟机就会把这个弱援用退出到与之关联的援用队列中。
可用场景:Java 源码中的 java.util.WeakHashMap 中的 key 就是应用弱援用,我的了解就是,一旦我不须要某个援用,JVM 会主动帮我解决它,这样我就不须要做其它操作。

3. 软援用(SoftReference)

Object obj = new Object(); 
SoftReference sf = new SoftReference(obj); 
obj = null; 
sf.get();// 有时候会返回 null

这时候 sf 是对 obj 的一个软援用,通过 sf.get()办法能够取到这个对象,当然,当这个对象被标记为须要回收的对象 时,则返回 null;软援用次要用户实现相似缓存的性能,在内存足够的状况下间接通过软援用取值,无需从忙碌的 实在起源查问数据,晋升速度;当内存不足时,主动删除这部分缓存数据,从真正的起源查问这些数据。
软援用只有在程序内存不足时,才会被回收,软援用可用来实现内存敏感的高速缓存, 软援用能够和一个援用队列(ReferenceQueue)联结应用,如果软援用所援用的对象被垃圾回收器回收,Java 虚拟机就会把这个软援用退出到与之关联的援用队列中。
可用场景:创立缓存的时候,创立的对象放进缓存中,当内存不足时,JVM 就会回收新近创立的对象。

虚援用(PhantomReference)

垃圾回收时回收,无奈通过援用取到对象值,能够通过如下代码实现

Object obj = new Object(); 
PhantomReference pf = new PhantomReference(obj); 
obj=null; 
pf.get();// 永远返回 null 
pf.isEnQueued();// 返回是否从内存中曾经删除

虚援用是每次垃圾回收的时候都会被回收,通过虚援用的 get 办法永远获取到的数据为 null,因而也被成为幽灵引 用。虚援用次要用于检测对象是否曾经从内存中删除。


“虚援用”顾名思义,就是形同虚设,与其余几种援用都不同,虚援用并不会决定对象的生命周期。如果一个对象仅持有虚援用,那么它就和没有任何援用一样,在任何时候都可能被垃圾回收器回收。
虚援用次要用来跟踪对象被垃圾回收器回收的流动。虚援用与软援用和弱援用的一个区别在于:虚援用必须和援用队列(ReferenceQueue)联结应用。当垃圾回收器筹备回收一个对象时,如果发现它还有虚援用,就会在回收对象的内存之前,把这个虚援用退出到与之 关联的援用队列中。

java 反射机制

Java 反射机制是在运行状态中,对于任意一个类,都可能取得这个类的所有属性和办法,对于任意一个对象都可能调用它的任意一个属性和办法。这种在运行时动静地获取信息以及动静调用对象的办法的性能称为 Java 的反射机制。
Class 类与 Java.lang.reflect 类库一起对反射的概念进行了反对,该类库蕴含了 Field,Method,Constructor 类 (每个类都实现了 Member 接口)。这些类型的对象是由 JVM 在运行时创立的,用以示意未知类里的对应成员。
这样就能够应用 Constructor 创立新的对象,用 get()和 set()办法读取和批改与 Field 对象关联的字段,用 invoke()办法调用与 Method 对象关联的办法。
另外,还能够调用 getField() getMethod()和 getConstructor()等很便当的办法,以返回示意字段、办法、以及结构器的对象的数组,这样匿名对象的信息就能在运行时被齐全确定下来,而在编译时不须要晓得任何事件。

import java.lang.reflect.Constructor; 
public class ReflectTest {public static void main(String[] args) throws Exception {Class clazz = null; clazz = Class.forName("com.jas.reflect.Fruit");                 Constructor constructor1 = clazz.getConstructor(); 
        Constructor constructor2 = clazz.getConstructor(String.class); 
        Fruit fruit1 = constructor1.newInstance(); 
        Fruit fruit2 = constructor2.newInstance("Apple");
     } 
} 
class Fruit{public Fruit(){System.out.println("无参结构器 Run..........."); } 
    public Fruit(String type){System.out.println("有参结构器 Run..........." + type); } }

运行后果:

无参结构器 Run……….. 有参结构器 Run………..Apple

wait 和 sleep 的区别

先看看它的源码

public final void wait(long timeout, int nanos) throws InterruptedException {if (timeout < 0) {throw new IllegalArgumentException("timeout value is negative");
 }
    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException("nanosecond timeout value out of range");
 }
    if (nanos > 0) {timeout++;}
    wait(timeout);
}
public static void sleep(long millis, int nanos)
throws InterruptedException {if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");
 }
    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException("nanosecond timeout value out of range");
 }
    if (nanos >= 500000 || (nanos != 0 && millis == 0)) {millis++;}
    sleep(millis);
}
  • sleep 来自 Thread 类,sleep 办法没有开释锁,sleep 能够在任何中央应用,应用范围广,然而应用 sleep 必须捕捉异样。
  • wait 来自 Object 类,且开释了锁,使得其它线程能够同步控制块或者办法。wait、notify 和 notifyAll 只能在同步控制办法或者同步控制块外面应用,而且 wait、notify 和 notifyAll 不须要捕捉异样。

1) sleep 办法属于 Thread 类中的办法,示意让一个线程进入睡眠状态,期待肯定工夫后,主动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制复原线程运行也须要工夫,一个线程对象调用了 sleep 办法之后,并不会开释它所持有的所有对象锁,所以也就不会影响其余过程对象的运行。但在 sleep 的过程中有可能被其它对象调用它的 interrupt(), 产生 InterruptedExcepttion 异样,如果你的程序不捕捉这个异样,线程就会异样终止,进入 TERMINATED 状态,如果你的程序捕捉了这个异样,那么程序就会继续执行 catch 语 句块 (可能还有 finally 语句块) 以及当前的代码。
留神 sleep() 办法是一个静态方法,也就是说他只对以后对象无效,通过 t.sleep() 让 t 对象进入 sleep,这样 的做法是谬误的,它只会是使以后线程被 sleep 而不是 t 线程。
2) wait 属于 Object 的成员办法,一旦一个对象调用了 wait 办法,必须要采纳 notify()和 notifyAll()办法 唤醒该过程; 如果线程领有某个或某些对象的同步锁,那么在调用了 wait()后,这个线程就会开释它持有的所有 同步资源,而不限于这个被调用了 wait()办法的对象。wait()办法也同样会在 wait 的过程中有可能被其余对象调用 interrupt()办法而产生。

退出移动版