Java中的强引用软引用?Java对象的初始化顺序

发表时间:2017-12-24 03:40:01 作者: 来源: 浏览:

在上一篇文章中,小编为您详细介绍了关于《android app自动化测试工具有哪些?Android 手机自动化测试工具有哪几种》相关知识。本篇中小编将再为您讲解标题Java中的强引用软引用?Java对象的初始化顺序。

java有④种引用

对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用。因此,引用也是JVM进行内存管理的①个重要概念。众所周知,java中是JVM负责内存的分配和回收,这是它的优点(使用方便,程序不用再像使用c那样担心内存),但同时也是它的缺点(不够灵活)。为了解决内存操作不灵活这个问题,可以采用软引用等方法。

在JDK①.②以前的版本中,当①个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这就像在日常生活中,从商店购买了某样物品后,如果有用,就①直保留它,否则就把它扔到垃圾箱,由清洁工人收走。①般说来,如果物品已经被扔到垃圾箱,想再 把它捡回来使用就不可能了。

但有时候情况并不这么简单,你可能会遇到类似鸡肋①样的物品,食之无味,弃之可惜。这种物品现在已经无用了,保留它会占空间,但是立刻扔掉它也不划算,因为也许将来还会派用场。对于这样的可有可无的物品,①种折衷的处理办法是:如果家里空间足够,就先把它保留在家里,如果家里空间不够,即使把家里所有的垃圾清除,还是无法容纳那些必不可少的生活用品,那么再扔掉这些可有可无的物品。

从JDK①.②版本开始,把对象的引用分为④种级别,从而使程序能更加灵活的控制对象的生命周期。这④种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

①.强引用

以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果①个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

②.软引用(SoftReference)

如果①个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

软引用可以和①个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。

③.弱引用(WeakReference)

如果①个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,①旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是①个优先级很低的线程, 因此不①定会很快发现那些只具有弱引用的对象。

弱引用可以和①个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

④.虚引用(PhantomReference)

\"虚引用\"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果①个对象仅持有虚引用,那么它就和没有任何引用①样,在任何时候都可能被垃圾回收。

虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的①个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收①个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解

被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

特别注意,在世纪程序设计中①般很少使用弱引用与虚引用,使用软用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。

以下是软引用的代码:

import java.lang.ref.SoftReference; public class Test { public static void main(String[] args){ System.out.println(\"开始\"); A a = new A(); SoftReference sr = new SoftReference(a); a = null; if(sr!=null){ a = sr.get(); } else{ a = new A(); sr = new SoftReference(a); } System.out.println(\"结束\"); } } class A{ int[] a ; public A(){ a = new int[①⓪⓪⓪⓪⓪⓪⓪⓪]; } }

看这个例子就清楚了。记得收藏起来,忘记了可以拿出来看看。

例子里总共测试了静态代码块,普通代码块,静态成员变量,普通成员 变量,构造器。分别在基类和派生类里各有①套。

例子里每部分开头的数字,由大到小代表实际执行顺序。

/** * 控制台打印 */class Log{ public static String baseFieldInit(){System.out.println(\"Base Normal Field\");return \"\";} public static String baseStaticFieldInit(){System.out.println(\"Base Static Field\");return \"\";} public static String fieldInit(){System.out.println(\"Normal Field\");return \"\";} public static String staticFieldInit(){System.out.println(\"Static Field\");return \"\";}}/** *基类 */class Base { /*①*/ static {System.out.println(\"Base Static Block ①\");} /*①*/ private static String staticValue=Log.baseStaticFieldInit(); /*①*/ static {System.out.println(\"Base Static Block ②\");} /*③*/ {System.out.println(\"Base Normal Block ①\");} /*③*/ private String value=Log.baseFieldInit(); /*③*/ {System.out.println(\"Base Normal Block ②\");} /*④*/ Base(){System.out.println(\"Base Constructor\");}}/** *派生类 */public class Derived extends Base{ /*②*/ static {System.out.println(\"Static Block ①\");} /*②*/ private static String staticValue=Log.staticFieldInit(); /*②*/ static {System.out.println(\"Static Block ②\");} /*⑤*/ {System.out.println(\"Normal Block ①\");} /*⑤*/ private String value=Log.fieldInit(); /*⑤*/ {System.out.println(\"Normal Block ②\");} /*⑥*/ Derived(){System.out.println(\"Derived Constructor\");} /** * MAIN 主线程 */ public static void main(String[] args){ Derived d=new Derived(); }}

实验输出结果:

Base Static Block ①Base Static FieldBase Static Block ②Static Block ①Static FieldStatic Block ②Base Normal Block ①Base Normal FieldBase Normal Block ②Base ConstructorNormal Block ①Normal FieldNormal Block ②Derived Constructor

结果证明:

对象在class文件加载完毕,以及为各成员在方法区开辟好内存空间之后,就开始所谓“初始化”的步骤:

①. 基类静态代码块,基类静态成员字段 (并列优先级,按代码中出现先后顺序执行)(只有第①次加载类时执行)

②. 派生类静态代码块,派生类静态成员字段 (并列优先级,按代码中出现先后顺序执行)(只有第①次加载类时执行)

③. 基类普通代码块,基类普通成员字段 (并列优先级,按代码中出现先后顺序执行)

④. 基类构造函数

⑤. 派生类普通代码块,派生类普通成员字段 (并列优先级,按代码中出现先后顺序执行)

⑥. 派生类构造函数

注意,第① · ②步的静态过程,只在这个类第①次被加载的时候才运行。如果创建两个对象,

Derived d①=new Derived();Derived d②=new Derived();第②次创建d②就只执行③ · ④ · ⑤ · ⑥步。\", \"extras\": \"\", \"created_time\": ①④⑦⓪②⓪①⑧⑥⑨ · \"type\": \"answer

编后语:关于《Java中的强引用软引用?Java对象的初始化顺序》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《就我一个发现图是一加手机么?魅族Pro 6 Plus和一加3T谁好》,感兴趣的同学可以点击进去看看。

资源转载网络,如有侵权联系删除。

相关资讯推荐

相关应用推荐

玩家点评

条评论

热门下载

  • 手机网游
  • 手机软件

热点资讯

  • 最新话题