精华内容
下载资源
问答
  • 2017-11-09 22:56:43
    首先,你要明白什么是变量,变量的实质是一小块内存单元,这一小块内存里存储着变量的值。
    
    比如int a = 1;
    
    a就是变量的名名,1就是变量的值。
    
    而当变量【变量名】指向一个对象时,这个变量就被称为引用变量
    
    比如A a =new A();
    
    a就是引用变量,它指向了一个A对象,也可以说它引用了一个A对象。我们通过操纵这个a来操作A对象。 此时变量a的值为它所引用对象的地址。
    
    
    分隔符--------------------------------------------
    在java实现某个功能的时候,会将类实例化成对象,然后jvm再对实例化后的对象进行操作。
    实例化后的对象可以赋值,也可以引用。赋值时,java会开辟一个新的地址用于存放变量,而引用则不开辟地址。
    String a = "a";
    String b = "a";
    将String类实例化成对象a与b,并赋值
    String c = new String("a");
    将c指向new出来的String型对象"a"
    System.out.println(a==b);
    System.out.println(a==c);
    由于a与b都为对象赋值,打印出来的结果应该是true
    而c是引用对象“a”,所以打印出来的结果应该是false
    对象:一个类的具体实例化;
    引用:对象的别名,使用该别名可以存放该对象,编译器不会为引用分配空间,新对象与源对象共用一个存储地址空间;引用的生命周期是它所引用的对象的生命周期,函数里返回一个局部对象的引用是很危险的
    给你推荐一种最简单的理解方式:引用就好比是给商品贴的标签,你通过标签可以拿到这个商品.......我开始就是这么理解的,后来用多了就意会啦..... 
    
    更多相关内容
  • 一段关于对象引用的形象解释.pdf
  • JNI:全局引用&局部引用&弱全局引用

    千次阅读 2022-03-05 00:44:08
    从Java虚拟机创建的对象传到本地 C/C++ 代码时就会产生引用。根据Java的垃圾回收机制,只要有引用存在就不会触发该引用指向的Java对象的垃圾回收。这些引用在 JNI 中分为三种全...

    从Java虚拟机创建的对象传到本地 C/C++ 代码时就会产生引用。根据Java的垃圾回收机制,只要有引用存在就不会触发该引用指向的Java对象的垃圾回收。这些引用在 JNI 中分为三种

    1. 全局引用 (Global Reference)

    2. 局部引用 (Local Reference)

    3. 弱全局引用 (Weak Global Reference), JDK 1.2 引入

    1. 局部引用

    • 最常见的引用类型,基本上通过JNI返回来的引用都是局部引用

    例如,使用NewObject就会返回创建出来的实例的局部引用。局部引用只在该native函数中有效,所有在该函数中产生的局部引用,都会在函数返回的时候自动释放(freed)。也可以使用DeleteLocalRef函数进行手动释放该引用。

    • 想一想既然局部引用能够在函数返回时自动释放,为什么还需要DeleteLocalRef函数呢?

    实际上局部引用存在,就会防止其指向的对象被垃圾回收。尤其是当一个局部引用指向一个很庞大的对象,或是在一个循环中生成了局部应用;最好的做法就是在使用完该对象后,或在该循环尾部把这个引用释放掉,以确保在垃圾回收器被触发的时候被回收。

    • 在局部引用的有效期中,可以传递到别的本地函数中,要强调的是它的有效期仍然只在一次的Java本地函数调用中,所以千万不能用C++全局变量保存它或是把它定义为C++静态局部变量。

    2. 全局引用

    • 全局引用可以跨越当前线程,在多个native函数中有效,不过需要编程人员手动来释放该引用。全局引用存在期间会防止在Java的垃圾回收的回收。

    • 与局部引用不同,全局引用的创建不是由 JNI 自动创建的,全局引用需要调用 NewGlobalRef 函数,而释放它需要使用 ReleaseGlobalRef 函数。

    3. 弱全局引用

    弱全局应用是 JDK 1.2 新出来的功能,与全局引用相似,创建跟释放都需要由编程人员来进行操作。这种引用与全局引用一样可以在多个本地代码有效,也可以跨越多线程有效;不一样的是,这种引用将不会阻止垃圾回收器回收这个引用所指向的对象。

    使用 NewWeakGlobalRef 跟 ReleaseWeakGlobalRef 来产生和释放应用。

    4. 关于引用的一些函数

    jobject NewGlabalRef(jobject obj);
    jobject NewLocalRef(jobject obj);
    jobject NewWeakGlobalRef(jobject obj);
    
    
    void DeleteGlobalRef(jobject obj);
    void DeleteLocalRef(jobject obj);
    jboolean IsSameObject(jobject obj1, jobject obj2);

    IsSameObject 函数对于弱引用全局应用还有一个特别的功能,把NULL传入要比较的对象中,就能够判断弱全局引用所指向的Java对象是否被回收。

    5. 缓存jfieldID / jmethodID

    获取 jfieldID与jmethodID 的时候会通过该属性/方法名称加上签名来查询相应的 jfieldID/jmethodID。这种查询相对来说开销较大。在开发中可以将这些 FieldID/MethodID 缓存起来,这样就只需要查询一次,以后就使用缓存起来的 FieldID/MethodID。

    • 下面介绍两种缓存方式

    1. 在使用时缓存 (Caching at the Point of Use)

    2. 在Java类初始化时缓存 (Caching at the Defining Class's Inititalizer)

    5.1 在使用时缓存

    在native 代码中使用static局部变量来保存已经查询过的jfieldID/jmethodID ,这样就不会在每次的函数调用时查询,而只要一次查询成功后就保存起来了。

    JNIEXPORT void JNICALL Java_Test_native( JNIEnv* env, jobject ojb) {
    static jfieldID fieldID_str = NULL;
       jclass clazz = env->GetObjectClass( obj );
       if(fieldID_str == NULL){
           fieldID_str = env->GetFieldID(clazz, "strField", "Ljava/lang/String");
       }
         //TODO Other codes
    }

    不过这种情况下,就不得不考虑多线程同时调用此函数时可能导致同时查询的并发问题,不过这种情况是无害的,因为查询同一个属性或者方法的ID,通常返回的值是一样的。

    5.2 在Java类初始化时缓存

    • 更好的一个方式就是在任何native函数调用之前把id全部缓存起来。

    • 可以让Java在第一次加载这个类的时候,首先调用本地代码初始化所有的 jfieldID/jmethodID,这样的话就可以省去多次判断id是否存在的冗余代码。当然,这些 jfieldID/jmethodID 是定义在C/C++ 的全局。

    • 使用这种方式还有好处,当Java类卸载或者重新加载的时候,也会重新调用该本地代码来重新计算IDs。

    java代码

    public class TestNative {
    
    
       static {
           initNativeIDs();
       }
    
    
       static native void initNativeIDs();
    
    
       int propInt =0;
    
    
       String propStr = "";
    
    
       public native void otherNative();
    
    
            //TODO Other codes
        }

    C/C++ 代码

    //global variables
    jfieldID g_propInt_id = 0;
    jfieldID g_propStr_id = 0;
    
    
    
    
    JNIEXPORT void JNICALL Java_TestNative_initNativeIDs( JNIEnv* env, jobject clazz){
       g_propInt_id = env->GetFieldID(clazz, "propInt", "I");
       g_propStr_id = env->GetFieldID(clazz, "propStr", "Ljava/lang/String;");    
    }
    
    
    
    
    JNIEXPORT void JNICALL Java_TestNative_otherNative( JNIEnv* env, jobject obj){
        // TODO get field with g_propInt_id/g_propStr_id
    }

    6. 总结

    • 最简单的Java调用C/C++函数的方法

    • 获取方法/属性的ID;学会了获取/设置属性;还有Java函数的调用

    • Java/C++之间的字符串的转换问题

    • 在C/C++下如何操作Java的数组

    • 三种引用方式

    • 如何缓存属性/方法的ID

    7. 回顾

    • 使用了JNI,那么这个Java应用将不能跨平台了。如果要移植到别的平台上,那么native代码就需要重新进行编写

    • Java是强类型的语言,而C/C++不是。因此,必须在写JNI时倍加小心

    • 总之,必须在构建Java程序的时候,尽量不用或者少用本地代码

    • 异常处理

    • C/C++ 如何启动JVM

    • JNI与多线程

    《The Java Native Interface Programmer's Guide and Specification》
    《JNI++ User Guide》

    834c331da56a042c79f1dd072338b3c9.png

    分享&在看

    展开全文
  • Excel中的相对引用和绝对引用是怎么操作的?对列标(ABCD等)和(123等)绝对引用时要加上“$”,引用时不用加任何符号。相对引用和绝对引用是指将公式向右或复制时列标和行号是否跟着变化。即相对引用时将公式向右或向...

    Excel中的相对引用和绝对引用是怎么操作的?

    对列标(ABCD等)和(123等)绝对引用时要加上“$”,引用时不用加任何符号。

    相对引用和绝对引用是指将公式向右或复制时列标和行号是否跟着变化。

    即相对引用时将公式向右或向下复制时列标和行号跟着变化;绝对引用时将公式向右或向下复制时列标和行号固定不变。

    举例:

    D5单元格公式为:

    =A1 B1

    为相对引用,将公式复制到E5单元格时变为=B1 C1,将公式复制到D6单元格时变为=A2 B2

    D5单元格公式为:

    =$A$1 $B$1

    为绝对引用,将公式复制到E5单元格时仍为=$A$1 $B$1,将公式复制到D6单元格时仍为=$A$1 $B$1

    D5单元格公式为:

    =$A1 B$1

    为混合引用,将公式复制到E5单元格时变为=$A1 C$1,将公式复制到D6单元格时变为=$A2 B$1

    绝对引用可用快捷键F4完成,即用光标选中单元格A1,按下F4键,A1就变成$A$1了。

    excel中绝对引用符号怎么打

    在使用Excel公式的时候要打出“绝对引用符号”的方法步骤如下。

    首先打开需要进行此项操作的Excel,对选中范围进行公式套用,如图。

    然后将鼠标左键,拖动选中需要修改引用的范围,如图。

    随后按下“F4”键,选中部分就可以变为绝对引用格式了。

    excel中的绝对引用有什么用?请解释得通俗一点

    EXECL一般都是相用,比如你B1单元格输入公式=A1,当你把公式复制拉时,A1也会随你复制公式的位置发生行的变动,当你把B1公式复制到C1时,C1的公式会变成=B1,发生相对列的变化,你把B1公式复制到B2,B2公式会变成=A2,发生相对行变化,你把B1公式复制到C2时C2的公式会变成=B2,同时发生相对行和列的变化,

    绝对引用就不发生这种相对变化,如上例,当你相复制B1的公式到C2,又还想引用A1的值时,就用绝对引用,这时候,你在B1的公式就要就=$A$1,复制到C2后还是=$A$1,

    绝对引用符号$可以用在字母前面,如$A1,表示列绝对引用,复制公式时,列不会变化,行会变化,如B1=$A1,复制到C2,会变成=$A2

    绝对引用符号$可以用在数字前面,如A$1,表示行绝对引用,复制公式时,行不会变化,列会变化,如B1=A$1,复制到C2,会变成=B$1

    绝对引用符号$也可以在数字和字母前同时使用,如$A$1,表示行列都是绝对引用,复制公式时,行列都不会变化,如B1=$A$1,复制到C2,还是=$A$1

    大白话说的,希望能说清楚

    excel中的绝对引用怎么用

    A1是相用

    $A1绝对列是混合引用

    A$1绝对引用行是混合引用

    $A$1绝对引用行和列是绝对引用

    $在谁的前面就绝对引用谁

    F4是在四种引用间相互转换的快捷键(在编辑栏输入公式时按下F4功能键可进行切换)

    A1(相对引用)在下拉拖动引用时,会变成引用A2,A3,A4...,右拉拖动时引用变成B1,C1,D1....

    A$1(混合引用)当你下拉复制时想保证引用的只是A1单元格时,A1就要加$符号,成A$1,这样在下拉时能保证对A列第一行的相对引用(即保持行号在引用时不产生变动)

    $A1(混合引用)当你右拉复制时想保证引用的只是A1单元格时,A1就要加$符号,成$A1,这样在右拉时能保证对A列第一行的相对引用(即保持列标在引用时不产生变动)

    $A$1(绝对引用)当你在下拉和右拉复制时想保证引用的只是A1单元格时,A1就要加$符号,成$A$1,这样在下拉和右拉时能保证对A列第一行的绝对引用(即保持行号列标在引用时不产生变动)

    相对引用、绝对引用和混合引用是指在公式中使用单元格或单元格区域的地址时,当将公式向旁边复制时,地址是如何变化的。

    具体情况举例说明:

    1、相对引用,复制公式时地址跟着发生变化,如C1单元格有公式:=A1 B1

    当将公式复制到C2单元格时变为:=A2 B2

    当将公式复制到D1单元格时变为:=B1 C1

    2、绝对引用,复制公式时地址不会跟着发生变化,如C1单元格有公式:=$A$1 $B$1

    当将公式复制到C2单元格时仍为:=$A$1 $B$1

    当将公式复制到D1单元格时仍为:=$A$1 $B$1

    3、混合引用,复制公式时地址的部分内容跟着发生变化,如C1单元格有公式:=$A1 B$1

    当将公式复制到C2单元格时变为:=$A2 B$1

    当将公式复制到D1单元格时变为:=$A1 C$1

    规律:加上了绝对地址符“$”的列标和行号为绝对地址,在公式向旁边复制时不会发生变化,没有加上绝对地址符号的列标和行号为相对地址,在公式向旁边复制时会跟着发生变化。混合引用时部分地址发生变化。

    注意:工作薄和工作表都是绝对引用,没有相对引用。

    技巧:在输入单元格地址后可以按F4键切换“绝对引用”、“混合引用”和“相对引用”状态。

    Excel中绝对引用是怎么用的?

    在你复制公式时,如果你需要被引用的单元格或单元格区域不会因公式拉动变化而变化,就要用到绝对引用或混合引用,在输入时按F4键可快速切换。

    展开全文
  • 一、值的类型  早在介绍JS的数据类型的时候就提到过... 为变量赋值时,ECMAScript的解释程序必须判断该值是原始类型,还是引用类型。要实现这一点,解释程序则需尝试判断该值是否为ECMAScript的基本类型之一,即Und
  • 本人经过长时间收集的最经典、最有说服力、最易懂的关于this引用传递的详解资料~包看包会~发出去真有些不舍得~
  • Java弱引用最精彩的解释

    千次阅读 2019-03-26 11:54:35
    原文出自:...这个解释是关于弱引用最精彩的 public class EmployeeVal { public EmployeeVal(String ...

    原文出自:https://stackoverflow.com/questions/299659/whats-the-difference-between-softreference-and-weakreference-in-java

    这个解释是关于弱引用最精彩的 

     

    public class EmployeeVal {
      public EmployeeVal(String userName) {
        this.userName = userName;
      }
    
    
      public String getUserName() {
        return userName;
      }
    
      public void setUserName(String userName) {
        this.userName = userName;
      }
    
    
      private String userName;
    
    }
        public static void main(String args[]) {
            HashMap<Employee, EmployeeVal> aMap = new HashMap<Employee, EmployeeVal>();
            Employee emp = new Employee("Vinoth");
            EmployeeVal val = new EmployeeVal("Programmer");
            aMap.put(emp, val);
            emp = null;
            System.gc();
            System.out.println("Size of Map: " + aMap.size());
        }

    输出:Size of Map: 1

      public static void main(String args[]) {
        WeakHashMap<Employee, EmployeeVal> aMap = new WeakHashMap<Employee, EmployeeVal>();
    
        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");
        aMap.put(emp, val);
        emp = null;
    
        System.gc();
        int count = 0;
    
        while (0 != aMap.size()) {
          ++count;
          System.gc();
        }
        System.out.println("Took " + count+ " calls to System.gc() to result in weakHashMap size of : "+ aMap.size());
      }

    随机每次不确定的一个count值:

    Took 3 calls to System.gc() to result in weakHashMap size of : 0

    Took 22 calls to System.gc() to result in weakHashMap size of : 0

    Took 0 calls to System.gc() to result in weakHashMap size of : 0

     

    ----------------

    Understanding Weak References Blog

    强引用

    强引用是一种普通的Java引用,是您每天使用的类型。例如,代码:

    StringBuffer buffer = new StringBuffer();

    创建一个新的StringBuffer()并在变量缓冲区中存储对它的强引用。强引用的重要部分 - 使它们变得“强大”的部分 - 是它们与垃圾收集器交互的方式。具体来说,如果一个对象可以通过一系列强引用(强烈可访问)访问,则它不符合垃圾回收的条件。由于您不希望垃圾收集器销毁您正在处理的对象,因此这通常正是您想要的。

    当强引用过于强烈时

    应用程序使用无法合理扩展的类并不罕见。该类可能只是标记为最终的,或者它可能更复杂,例如由未知(甚至可能是不可知)的具体实现支持的工厂方法返回的接口。假设您必须使用类Widget,并且无论出于何种原因,extendWidget都不可能或不实际添加新功能。

    当您需要跟踪有关对象的额外信息时会发生什么?在这种情况下,假设我们发现自己需要跟踪每个Widget的序列号,但是Widget类实际上没有序列号属性 - 并且由于Widget不可扩展,我们无法添加一个。没问题,这就是HashMaps所代表的:

    serialNumberMap.put(widget,widgetSerialNumber);

    我们必须知道(100%确定)何时不再需要特定的Widget序列号,因此我们可以从Map中删除其条目。否则我们将会发生内存泄漏(如果我们不应该删除Widgets)或者我们会莫名其妙地发现自己缺少序列号(如果我们删除了我们仍在使用的Widgets)。如果这些问题听起来很熟悉,那么它们应该是:它们正是非垃圾收集语言的用户在尝试管理内存时所面临的问题,我们不应该用像Java这样的文明语言来担心这个问题。

    强引用的另一个常见问题是缓存,特别是对于像图像这样的非常大的结构。假设您有一个必须使用用户提供的图像的应用程序,例如我工作的网站设计工具。当然,您希望缓存这些图像,因为从磁盘加载它们非常昂贵,并且您希望避免在内存中同时存储两个(可能是巨大的)图像副本的可能性。

    因为当我们不绝对需要时,图像缓存应该阻止我们重新加载图像,你会很快意识到缓存应该总是包含对已经在内存中的任何图像的引用。但是,对于普通的强引用,该引用本身将强制图像保留在内存中,这需要您(如上所述)以某种方式确定何时在内存中不再需要该图像并将其从缓存中删除,以便它变为有资格进行垃圾收集。您再次被迫复制垃圾收集器的行为并手动确定对象是否应该在内存中。

    弱引用

    简单地说,弱引用是一个不足以强迫对象保留在内存中的引用。弱引用允许您利用垃圾收集器为您确定可达性的能力,因此您不必自己执行此操作。你创建一个像这样的弱引用:

    WeakReference <Widget> weakWidget = new WeakReference <Widget>(widget);

    然后在代码的其他地方你可以使用wewWidget.get()来获取实际的Widgetobject。当然,弱引用不足以阻止垃圾收集,因此您可能会发现(如果没有对小部件的强引用)weakWidget.get()突然开始返回null。

    要解决上面的“小部件序列号”问题,最简单的方法是使用内置的WeakHashMap类.

    WeakHashMap的工作原理与HashMap完全相同,只是使用弱引用引用键(而不是值!)。如果WeakHashMap键变为垃圾,则会自动删除其条目。这避免了我描述的陷阱,并且除了从HashMap切换到WeakHashMap之外不需要任何更改。如果您遵循通过Map接口引用地图的标准惯例,则其他代码甚至不需要知道更改。

    Reference queues

    一旦WeakReference开始返回null,它指向的对象就变成了垃圾,WeakReference对象几乎没用。这通常意味着需要进行某种清理;例如,WeakHashMap必须删除这些已经过时的条目,以避免持有越来越多的deadWeakReferences。

    ReferenceQueue类可以轻松跟踪死引用。如果将ReferenceQueue传递给弱引用的构造函数,则当引用它的对象变为垃圾时,引用对象将自动插入引用队列。然后,您可以按照一定的时间间隔处理ReferenceQueue并执行死引用所需的任何清理。

    不同程度的弱引用

    到目前为止,我刚刚提到“弱引用”,但实际上有四种不同程度的参考强度:强,弱,弱和幻像,从最强到最弱。我们已经讨论过强弱参考,所以让我们来看看另外两个。

    软引用

    软引用与弱引用完全相同,只是它不太愿意丢弃它引用的对象。一个只能弱到达的对象(对它的最强引用是WeakReferences)将在下一个垃圾收集周期被丢弃,但是一个可以轻松到达的对象通常会暂停一段时间。

    SoftReferences不需要与WeakReferences有任何不同的行为,但实际上,只要内存供应充足,就可以保留软可访问对象。这使得它们成为缓存的良好基础,例如上面描述的图像缓存,因为您可以让垃圾收集器担心对象的可达性(永远不会从缓存中移除强可达对象)以及它有多糟糕需要他们消耗的记忆。

     

    幻影引用

    幻像引用与软引用或WeakReference完全不同。它对它的对象的抓握是如此脆弱,你甚至无法检索对象 - 它的get()方法总是返回null。这种引用的唯一用途是跟踪它何时被引入ReferenceQueue,因为在那时你知道它指向的对象已经死了。但是,与WeakReference有何不同?

    区别在于排队发生的时间。一旦他们指向的对象变得微弱,WeakReferences就会排队。这实际上发生在最终化或垃圾收集之前;理论上,对象甚至可以通过非正统的finalize()方法“复活”,但WeakReference仍然会死亡。只有在从内存中物理移除对象时才会将幻像引用排队,并且get()方法始终返回null,以防止您“复活”几乎死亡的对象。

    幻像引用有什么用?我只知道它们有两个严重的情况:首先,它们允许您确定何时从内存中删除对象。事实上,它们是确定这一点的唯一方法。这通常不是很有用,但在某些非常特殊的情况下可能会派上用场,例如操作大图像:如果你确定图像应该被垃圾收集,你可以等到它实际上是在尝试加载下一个图像之前,因此不太可能使可怕的OutOfMemoryError。

    其次,幻像引用避免了最终化的基本问题:f​​inalize()方法可以通过创建对它们的新的强引用来“复活”对象。那么,你说什么?好吧,问题是现在必须确定一个覆盖最终化()的对象至少在两个单独的垃圾收集周期中是垃圾才能被收集。当第一个周期确定它是垃圾时,它有资格完成。由于在完成期间对象被“复活”的(微小的,但不幸的是真实的)可能性,垃圾收集器必须在实际移除对象之前再次运行。并且由于最终确定可能没有及时发生,因此在对象等待最终确定时可能会发生任意数量的垃圾收集周期。这可能意味着实际清理垃圾对象的严重延迟,这就是为什么即使大多数堆都是垃圾也可以getOutOfMemoryErrors。

    使用PhantomReference,这种情况是不可能的 - 当PhantomReference入队时,绝对没有办法获得指向现在死对象的指针(这很好,因为它不再存在于内存中)。因为PhntomReference不能用于复活对象,所以可以在第一个垃圾收集周期中立即清理该对象,在该周期中可以发现该对象是幻象可达的。然后,您可以在方便时处置所需的任何资源。

    可以说,应该首先提供finalize()方法。 PhantomReferences肯定更安全,使用效率更高,而且甚至最大化()会使虚拟机的某些部分变得更加简单。但是,它们也需要更多的工作来实现,所以我承认在大多数时候仍然使用finalize()。好消息是,至少你有一个选择。

    ---------------

    ReferenceQueue的使用

    我们希望当一个对象被gc掉的时候通知用户线程,进行额外的处理时,就需要使用引用队列了。ReferenceQueue即这样的一个对象,当一个obj被gc掉之后,其相应的包装类,即ref对象会被放入queue中。我们可以从queue中获取到相应的对象信息,同时进行额外的处理。比如反向操作,数据清理等。

     

    在这次处理中,map并没有因为不断加入的1M对象由产生OOM异常,并且最终运行结果之后map中的确有1万个对象。表示确实被放入了相应的对象信息。不过其中的key(即weakReference)对象中的byte[]对象却被回收了。即不断new出来的1M数组被gc掉了。

    从命令行中,我们看到有9995个对象被gc,即意味着在map的key中,除了weakReference之外,没有我们想要的业务对象。那么在这样的情况下,是否意味着这9995个entry,我们认为就是没有任何意义的对象,那么是否可以将其移除掉呢。同时还期望size值可以打印出5,而不是10000.
    WeakHashMap就是这样的一个类似实现。

     这个也可以理解为就是一个类似cache的实现。
    在cache中,key不重要并且通常都很少,value才是需要对待的。这里通过监控value变化,反向修改map,以达到控制kv的目的,避免出现无用的kv映射。

    -----------------

    利用虚引用PhantomReference实现对象被回收时收到一个系统通知

    虚引用PhantomReference, 在<<深入理解Java虚拟机>>一文中,它唯一的目的就是为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

    import java.lang.ref.PhantomReference;
    import java.lang.ref.Reference;
    import java.lang.ref.ReferenceQueue;
    import java.lang.reflect.Field;
     
    public class Test {
        public static boolean isRun = true;
        @SuppressWarnings("static-access")
        public static void main(String[] args) throws Exception {
            String abc = new String("abc");
            System.out.println(abc.getClass() + "@" + abc.hashCode());
            final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
            new Thread() {
                public void run() {
                    while (isRun) {
                        Object obj = referenceQueue.poll();
                        if (obj != null) {
                            try {
                                Field rereferent = Reference.class
                                        .getDeclaredField("referent");
                                rereferent.setAccessible(true);
                                Object result = rereferent.get(obj);
                                System.out.println("gc will collect:"
                                        + result.getClass() + "@"
                                        + result.hashCode() + "\t"
                                        + (String) result);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }.start();
            PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc, referenceQueue);
            abc = null;
            Thread.currentThread().sleep(3000);
            System.gc();
            Thread.currentThread().sleep(3000);
            isRun = false;
        }
    }

     

    展开全文
  • 在示例所示的交互式控制台中,无法使用“变量是盒子”做解释。图说明了在 Python 中为什么不能使用盒子比喻,而便利贴则指出了变量的正确工作方式。 变量 a 和 b 引用同一个列表,而不是那个列表的副本 >>> a = [1,...
  • 一、前言 Objective-C 使用引用计数作为 iPhone 应用的内存...虽然 Objective-C 通过引入弱引用技术,让开发者可以尽可能地规避这个问题,但在引用层级过深,引用路径不那么直观的情况下,即使是经验丰富的工程师,也
  • 在php中使用引用赋值只需要在原始对象前加个&就可以了,具体休怎么用呢,可以看下文解释和实例
  • 反向引用的比较容易理解的解释。 正则表达式中的分组是基础,反向引用和编号(命名)组是对相应分组的两种不同的引用方式――反向引用是在匹配(或者说同一个)模式中引用分组,而编号(命名)组则是在替换模式中...
  • 在谈到变量的作用域之前,我们先对python解释器运行时代码的执行顺序、内存分配、内存引用、内存释放机制先了解一下。 1、运行一个py文件时,python解释器是怎么工作的? 在pycharm运行一个py文件时,我们右键点击...
  • 深入理解C++——引用传递

    千次阅读 2019-09-30 19:12:28
    引用传递,是C++非常重要的特性。引用传递能够将变量或对象本身作为参数传递,而不是复制一份副本后,传递副本。 引用传递的主要作用有二: 第一,函数内部可修改变量或对象。函数返回后,函数调用者得到的也是被...
  • 引言:Java中数据传递的方式,除了基本数据类型是按照值传递,其它类型全部是按照引用传递,这和C++有很大区别,但是很多网上文章都解释的不清楚,甚至是错误的,在查阅资料之后,下面整理出一个比较容易理解的版本...
  • excel表格的绝对引用和相对引用

    千次阅读 2019-09-04 08:50:51
    讲到数据的引用,你可能会想到两种比较常见的引用方式,绝对引用和相对引用,下面就着两种方式做一下通俗的解释。 首先是相对引用,说到相对肯定是会想到相对于谁,其实物理学中的参照物,所以excel中...
  • 参考文献的引用,不外乎两种方式,直接引用原文献的内容,并做好引注;间接引用,转述原文献的意思。那么,当你在引用文献的时候,你是选择直接引用还是间接引用呢?回答这个问题之前,不妨先来了解这两种引用方式。 ...
  • excel中的绝对引用怎么用excel中 相对引用、绝对引用和混合引用 相对引用、绝对引用和混合引用是指在公式中使用单元格或单元格区域的地址时,当将公式向旁边复制时,地址是如何变化的。 具体情况举例说明:相对引用...
  • C++:引用(数组引用

    千次阅读 2021-11-26 10:27:09
    C++:引用(数组引用) 在C++里,数组引用如下: //第一种方法(常用) //1,定义数组类型 typedef int(my_arr)[5]; typedef int my_arr1[5]; //2,建立引用 my_arr1& arref = arr;//建立引用,相当于int &...
  • C++ 引用的本质是什么?

    千次阅读 多人点赞 2017-04-07 23:45:16
    C++中的引用本质上是 一种被限制的指针。由于引用是被限制的指针,所以引用是占据内存的。在使用高级语言的层面上,是没有提供访问引用的方法的。并且引用创建时必需初始化,创建后还不能修改。下面是找到的相关资料...
  • 主要介绍了 PHP7 中全新的 zval 容器和引用计数机制的相关知识, 主要侧重于解释新 zval 容器中的引用计数机制。需要的朋友可以参考下
  • Java引用对象

    万次阅读 2018-12-11 10:09:03
    结果证明它们在这种场景下用处不大,我下面会解释原因。但当引用类型才进入我的“工具箱”后,我发现了很多其他用途,并且对JVM也有了更好的理解。 Java堆和对象生命周期 对于刚接触Java的C++程序员来说,栈和...
  • word交叉引用的理解

    千次阅读 2021-07-20 21:52:26
    交叉引用,就类似一个超链接,其状态跟自动生成的目录一样,只要按住ctrl键,单击后即可切换到引用的地方。 引用的类型包括对标题的引用,对图Figure 对表Table的引用等。 存在一个问题:自定义的标题,在交叉...
  • 参考文献格式详细解释引用(常见)

    万次阅读 多人点赞 2018-10-11 16:19:29
    一般大学毕业论文的参考文献格式采用如下方式: 一、进入知网,查找到自己需要的文章,点击文章右侧“引用”符号。 二、直接复制知网提供的“GB/T 7714-2015 格式引文”格式即可,注意采用该格式后,文章中的所有...
  • 指针与引用总结

    千次阅读 多人点赞 2018-10-15 22:58:07
    //这里b是一个引用,它是变量i的引用引用是什么?它的本质是什么?下面会具体讲述 int * &c = a;//这里c是一个引用,它是指针a的引用 int & *d;//这里d是一个指针,它指向引用,但引用不是实体,所以这是错误的 ...
  • 引用变量及其作用

    千次阅读 2020-05-16 10:58:24
    首先,先来明白一下什么是引用
  • 一、值传递与引用传递的区别 ? 值传递 值传递的时候,将实参的值,copy一份给形参。 引用传递 引用传递的时候,将实参的地址值,copy一份给形参。 也就是说,不管是值传递还是引用传递,形参拿到的仅仅是实参...
  • 引用、常指针、常引用、指针常量、引用常量

    千次阅读 多人点赞 2017-08-29 14:19:03
    引用的本质以及const的位置在语法和作用上的区别
  • Java 是值传递还是引用传递

    万次阅读 多人点赞 2019-03-20 02:40:16
    最近整理面试题,整理到值传递、引用传递,到网上搜了一圈,争议很大。带着一脸蒙圈,线上线下查了好多资料。最终有所收获,所以分享给大家,希望能对你有所帮助。 首先说下我的感受,这个题目出的很好,但是在 ...
  • var base = "${base}"; ; charset=UTF-8"> ${base}/plug-in/easyui/themes/default/easyui.css" type="text/css"> ${res}/css/default.css" type="text/css" /> ${base}/plug-in/icons/icons.css" type=...
  • 指向不同类型的指针的区别在于指针类型可以知道编译器解释某个特定地址(指针指向的地址)中的内存内容及大小,而void*指针则只表示一个内存地址,编译器不能通过该指针所指向对象的类型和大小,因此想要通过void*...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 731,768
精华内容 292,707
关键字:

引用释义