都说Java里面没有“&”,这个若大悲剧就在于,很多时候做事情不方便!
比如,要改变对象中的内容,应该传递整个对象过去!
有人说,这是Java中的引用传递,是类似C中的引用。
姑且不说这种说法对不对【注:我本人相当反对】,
但是,Java中这个所谓的引用十分不好用倒是真的!!!
----------------------分割线-----------------------------------------------我碰到问题了,正如很多跟我一样在学习Java的同仁们一样,我也掉到沟里了,
这个沟就是那个所谓的“Java引用”我想做的事:
    将一个类A的对象a作为参数,放入一个函数中,使a不在指向new A(),而是指向null【指向这个词,没办法我还是改不了C的叫法】,于是,我写了这个代码:public static void main(String[] args) {
class A{

}
class B{
void fun(A a){
a = null ;
System.gc();
}
}
A a = new A();
B b = new B();
b.fun(a);
System.out.println(a);
}
上面的代码结果: test.test$1A@ca0b6 ---[Java真智能,这个输出把我的工程包泄露了]
显然,我失败了!!!
我打算在fun(A a)里面中改变a的指向,使其指向null,结果失败了 ... 求兄弟们指教下! 
【特别注明: 
      类对象一定要作为函数参数,然后调用函数时指向null,这不是我胡思乱想,而是有实际意义的,我在写连接池时发现,假如有一个List list ,list中有6个数据,只要这6个数据不销毁,就能被外界直接指向,比如:一旦 A a = (A)list.get(0),然后,只要list.get(0)不被销毁,a这东西就存在,然而,我这里又要保存list数据,销毁外部引用,也就是a,纠结死了,所以写了上面这个测试例。 
   哎哟,跑题,扯远了 ...

解决方案 »

  1.   


    a = null;
    System.out.println(a); 
      

  2.   

    1.为什么不把a = null ;放在外面。
    2.即使你不放在外面,也没关系,过了main函数,a的生命周期也结束了,java中不需要你手动销毁对象,貌似也没提供api供你销毁单个对象,java有自带的垃圾收集机制。其实java是简化了程序员的操作(相对c++来说),有C++基础学java还是很轻松的。少数地方转变下观念,大部分地方跟c++还是很类似的。你的需求描述中,在方法内部改变方法外部变量的引用,java貌似是做不到的。
      

  3.   


    朋友,你这样,不太行。
    理由:
        a=null ,fun()里面我上面的代码就这样写了,
    至于System.out.println(a);我只能表示沉默 ... 
      

  4.   

    你那是什么写法。。main方法里面2个类。。JAVA中参数都是值传递,要实现你的功能可以这样。
    public class A {
    public static void main(String[] args) { A[] a = new A[] { new A() };
    B b = new B();
    b.fun(a);
    System.out.println(a[0]);
    }
    }class B {
    void fun(A[] a) {
    a[0] = null;
    System.gc();
    }
    }
      

  5.   

    A a=new A();
    a只是一个引用,new A()才是对象,当a=null的时候,a已经与new A()没有关系了,但它的类型仍然是A,所以才会输出test.test$1A@ca0b6,但它指向的是null,已经不再指向内存中任何对象
    执行System.gc()销毁的也是new A()这个对象
      

  6.   

    再说显示调用System.gc();并不一定保证回收这个内存空间
      

  7.   


    不是我要乱想,是真实需求决定的,可能我上面的那个特别说明没有说清楚,我现在举个例
    子:
    假设
    class A{...}
    class AList{
      List<A> alist = new ArrayList<A>(5) ;//假定alist中包含5个A对象a1、a2、a3、a4、a5
      public void back(A a){
         A mustBack = a ;
         alist.add(mustBack);
         /**
          * 将a指向null ,问题所在
          */
      }
      public A get(int i){
         ... 
         return alist.get(i);
      }
    }
    Alist 用于控制A的对象的使用数量 --- 【这是我提这个问的核心,控制A对象的数量】现在,外部有一个class UserA{ ... },其必须要使用A,
    于是,我要在class UserA中这么写
    class UserA{
       void userA_fun(){
          AList alist = new AList();
          A a = alist.get(i);//i是根据其他事物来确定的
          ......使用......
          ......完毕......
          list.back(a);
       }
    }注意到没有,我这里UserA中用的是list.back(a)将用完的放回原来list对象的。
    现在回过头看back(A a)方法:
      public void back(A a){
         A mustBack = a ;
         alist.add(mustBack);
         /**
          * 将a指向null ,问题所在
          */
      }
    发现没,传过来的参数a必须要在back中指向null ,别处是不行!!!----------------------
    这就是我问题的所在 !
      

  8.   

    六楼正解  关键是函数参数会入栈  而你修改的是该函数 入栈参数的引用(修改的是局部变量...)
    而对new A()没有任何影响
      

  9.   


    我想改变的就是那个引用 !!!
    但问题是,那个引用在函数局部是a=null,出了函数这个范围,那么他依然是指向new A();
    我想在就想在函数内部改变引用a,使得其出了函数这个局部,也为null !!!
      

  10.   


    呵呵 ... 
    首先:一个测试例,写得比较乱,望谅解...莫口水
    其次:你这个方法的确可以解决问题
    最后:都最后了,自然,要来个但是咯 ... 
    咳咳 ... 
    但是:
    1、假如我这个程序不是业务程序,而是稍底的功能模块,是供上面业务层调用的,那么,总不至于业务层的同志们都要[]{new A()}把!
    2、其实,通过你的指点,我自己有了些思路,不过,我不理解fun(A a)已经传引用了,怎么还是改变不了a(我指的不是func函数内部,而是调用func(a)后,在外部的a还是不等于null)。
    3、请看看我的8楼,这里说明了我的业务原因,求思路,谢谢 ... 
      

  11.   


    不是我要乱想,是真实需求决定的,可能我上面的那个特别说明没有说清楚,我现在举个例
    子:
    假设
    class A{...}
    class AList{
      List<A> alist = new ArrayList<A>(5) ;//假定alist中包含5个A对象a1、a2、a3、a4、a5
      public void back(A a){
         A mustBack = a ;
         alist.add(mustBack);
         /**
          * 将a指向null ,问题所在
          */
      }
      public A get(int i){
         ... 
         return alist.get(i);
      }
    }
    Alist 用于控制A的对象的使用数量 --- 【这是我提这个问的核心,控制A对象的数量】现在,外部有一个class UserA{ ... },其必须要使用A,
    于是,我要在class UserA中这么写
    class UserA{
       void userA_fun(){
          AList alist = new AList();
          A a = alist.get(i);//i是根据其他事物来确定的
          ......使用......
          ......完毕......
          list.back(a);
       }
    }注意到没有,我这里UserA中用的是list.back(a)将用完的放回原来list对象的。
    现在回过头看back(A a)方法:
      public void back(A a){
         A mustBack = a ;
         alist.add(mustBack);
         /**
          * 将a指向null ,问题所在
          */
      }
    发现没,传过来的参数a必须要在back中指向null ,别处是不行!!!----------------------
    这就是我问题的所在 !
    你的back方法,我仔细看了下,是不是这个意思?
    将传进来的a(也是alist中的一个)放到alist中,再把传进来的这个对象a销毁掉。
    整个业务是不是:将alist中的一个对象拿出来用一下,再放回去。如果是这个意思的话,以下是我的看法。
    1.get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。
    2.如果为了对象在list中的顺序之类的需求,必须取出放回的话,应该使用LinkedList,类似队列。所以感觉你的“将a指向null”这个需求没有必要,不知道我的理解对不对。
      

  12.   

    虽然看起来有点迷惑性,但其实吧。当调用fun函数的时候确实让fun里面的行参a指向了对象A,这时引用变量a和fun的行参a同时指向对象A,没错。但是马上又让行参a指向了null,那么这时行参a已经不再指向对象A了,那么对行参a的操作即让其等于null也就不会在对象A中保存。也就是说对行参a的操作不会影响到对象A了,此时它们是两个不同的对象。但是引用变量a还是指向对象A,所以你输出的是引用变量a指向的那个对象的值。
      

  13.   

    你想让一个对象指向null太简单了,但是这时你得注意一个问题了,那就是引用一个值为空的对象所产生的空指针问题了
      

  14.   

    首先我感觉 你还是木有理解  你修改的函数fun的局部变量的引用  对外部a变量的指向根据没有影响过....在C/C++也不能通过一级指针修改  也需要通过二级指针才能达到你的效果  我个人感觉   你需要深刻了解参数入栈 这句话....
      

  15.   

    alist.add(alist.indexOf(a),null);  搞不懂你想干什么
      

  16.   

    还有一点就是  java中设计到对象的声明周期的 都是跟该对象的引用计数器有关  你再函数内部将a=null 即使你显示调用System.gc()即使马上回收内存 也不会回收new A()的内存  因为此时在main函数中A a 还依旧指向new A()的那块内存....
      

  17.   


    首先,很感谢你的阅读,的确是先从alist中拿出A的对象a,给别的对象用,用完了,放回去!
    但是:
        你说“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”,我却不赞同 !理由:
        a本来就在alist中,只是“借出去”给了userA用,但是,“借了要还”,于是back(A a),此时,出现问题了:
                  假设从alist中拿出getA给userA用,用完后,alist中还有getA,但是userA也还依然指向了getA,那么,程序随时会因为userA的变化,导致getA的变化,从而破坏alist中存放的getA的内容!那么将来再次使用getA时,结果就不可知了!
                  所以,我才想方设法的想要在back()时将userA置为null求解
      

  18.   


    我就是想让引用变量a变成null ! 
    理由:如果引用变量不为null,那位a还是指向new A(),那么,则a随时可以破坏new A()进而破坏alist原本保存的数据!!!所以我才想方设法在back(A a)时,想让引用变量a和形参a都置为null。求指教!
      

  19.   


    请恕我唠叨,我现在是想方设法让 形参 和 引用变量都为null ,只是没有办法!理由,同楼上 ... 
      

  20.   


    首先,很感谢你的阅读,的确是先从alist中拿出A的对象a,给别的对象用,用完了,放回去!
    但是:
        你说“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”,我却不赞同 !理由:
        a本来就在alist中,只是“借出去”给了userA用,但是,“借了要还”,于是back(A a),此时,出现问题了:
                  假设从alist中拿出getA给userA用,用完后,alist中还有getA,但是userA也还依然指向了getA,那么,程序随时会因为userA的变化,导致getA的变化,从而破坏alist中存放的getA的内容!那么将来再次使用getA时,结果就不可知了!
                  所以,我才想方设法的想要在back()时将userA置为null求解
    1.变量生命周期,a是局部变量,生命周期userA_fun函数中,不是类的成员变量,出了这个函数,是不可能同userA的对象来改变a,从而改变list。
    2.即使a被声明成类的成员变量,也是可以在userA_fun函数最后一行将a设成null,为什么偏要到back中处理,我在哪里声明变量,就在哪里结束变量,不是更清晰吗。
    3.还是前面的观点:“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”因为你通过给a赋值为null,是无法销毁,list中的对象的,前面也说了,java中是无法手工销毁单个指定的对象的。所以,这会导致一个结果:back函数会不断的向list中add引用,list中的引用数量会越来越多,而list中引用指向的堆中对象数量并没有变。
      

  21.   


    首先,很感谢你的阅读,的确是先从alist中拿出A的对象a,给别的对象用,用完了,放回去!
    但是:
        你说“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”,我却不赞同 !理由:
        a本来就在alist中,只是“借出去”给了userA用,但是,“借了要还”,于是back(A a),此时,出现问题了:
                  假设从alist中拿出getA给userA用,用完后,alist中还有getA,但是userA也还依然指向了getA,那么,程序随时会因为userA的变化,导致getA的变化,从而破坏alist中存放的getA的内容!那么将来再次使用getA时,结果就不可知了!
                  所以,我才想方设法的想要在back()时将userA置为null求解
    1.变量生命周期,a是局部变量,生命周期userA_fun函数中,不是类的成员变量,出了这个函数,是不可能同userA的对象来改变a,从而改变list。
    2.即使a被声明成类的成员变量,也是可以在userA_fun函数最后一行将a设成null,为什么偏要到back中处理,我在哪里声明变量,就在哪里结束变量,不是更清晰吗。
    3.还是前面的观点:“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”因为你通过给a赋值为null,是无法销毁,list中的对象的,前面也说了,java中是无法手工销毁单个指定的对象的。所以,这会导致一个结果:back函数会不断的向list中add引用,list中的引用数量会越来越多,而list中引用指向的堆中对象数量并没有变。你的意思我懂了 !!!
    那只能这样了 ... 那么最后一问:java.sql.Connection中,Connection conn怎么做到 conn.close()就可以关闭conn呢?
    他这个比我的back(conn)还要绝!自己关闭自己 ?
      

  22.   


    首先,很感谢你的阅读,的确是先从alist中拿出A的对象a,给别的对象用,用完了,放回去!
    但是:
        你说“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”,我却不赞同 !理由:
        a本来就在alist中,只是“借出去”给了userA用,但是,“借了要还”,于是back(A a),此时,出现问题了:
                  假设从alist中拿出getA给userA用,用完后,alist中还有getA,但是userA也还依然指向了getA,那么,程序随时会因为userA的变化,导致getA的变化,从而破坏alist中存放的getA的内容!那么将来再次使用getA时,结果就不可知了!
                  所以,我才想方设法的想要在back()时将userA置为null求解
    1.变量生命周期,a是局部变量,生命周期userA_fun函数中,不是类的成员变量,出了这个函数,是不可能同userA的对象来改变a,从而改变list。
    2.即使a被声明成类的成员变量,也是可以在userA_fun函数最后一行将a设成null,为什么偏要到back中处理,我在哪里声明变量,就在哪里结束变量,不是更清晰吗。
    3.还是前面的观点:“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”因为你通过给a赋值为null,是无法销毁,list中的对象的,前面也说了,java中是无法手工销毁单个指定的对象的。所以,这会导致一个结果:back函数会不断的向list中add引用,list中的引用数量会越来越多,而list中引用指向的堆中对象数量并没有变。你的意思我懂了 !!!
    那只能这样了 ... 那么最后一问:java.sql.Connection中,Connection conn怎么做到 conn.close()就可以关闭conn呢?
    他这个比我的back(conn)还要绝!自己关闭自己 ?
    java中,自己搞自己是非常常见,而且可以说是推荐这么做的,单一职责功能,应该说是面向对象都这样吧。Connection 源代码我没看过,不过conn.close()这句必须要显示的调用,否则数据库连接无法关闭。jvm无法回收数据库连接,因为数据库连接属于操作系统层面的了,超过了java虚拟机管理的范围。所以可以猜测,connection也就是对数据库链接的包装,这个类的内部应该有关于数据库链接的成员变量,所以可以通过conn.close()方法来关闭链接。java可以通过jni调用c/c++代码。所以connection中应该调用了本地方法。
      

  23.   

    在你的f方法里进行一系列判断,如果需要把a变成null,可以在f里return null,用a来接收即可:a = f(a);
      

  24.   

    变通一下就很简单了,为什么一定要把a=null放里面呢?这是得有多蛋疼呢
      

  25.   


    首先,很感谢你的阅读,的确是先从alist中拿出A的对象a,给别的对象用,用完了,放回去!
    但是:
        你说“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”,我却不赞同 !理由:
        a本来就在alist中,只是“借出去”给了userA用,但是,“借了要还”,于是back(A a),此时,出现问题了:
                  假设从alist中拿出getA给userA用,用完后,alist中还有getA,但是userA也还依然指向了getA,那么,程序随时会因为userA的变化,导致getA的变化,从而破坏alist中存放的getA的内容!那么将来再次使用getA时,结果就不可知了!
                  所以,我才想方设法的想要在back()时将userA置为null求解
    1.变量生命周期,a是局部变量,生命周期userA_fun函数中,不是类的成员变量,出了这个函数,是不可能同userA的对象来改变a,从而改变list。
    2.即使a被声明成类的成员变量,也是可以在userA_fun函数最后一行将a设成null,为什么偏要到back中处理,我在哪里声明变量,就在哪里结束变量,不是更清晰吗。
    3.还是前面的观点:“get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。”因为你通过给a赋值为null,是无法销毁,list中的对象的,前面也说了,java中是无法手工销毁单个指定的对象的。所以,这会导致一个结果:back函数会不断的向list中add引用,list中的引用数量会越来越多,而list中引用指向的堆中对象数量并没有变。你的意思我懂了 !!!
    那只能这样了 ... 那么最后一问:java.sql.Connection中,Connection conn怎么做到 conn.close()就可以关闭conn呢?
    他这个比我的back(conn)还要绝!自己关闭自己 ?
    java中,自己搞自己是非常常见,而且可以说是推荐这么做的,单一职责功能,应该说是面向对象都这样吧。Connection 源代码我没看过,不过conn.close()这句必须要显示的调用,否则数据库连接无法关闭。jvm无法回收数据库连接,因为数据库连接属于操作系统层面的了,超过了java虚拟机管理的范围。所以可以猜测,connection也就是对数据库链接的包装,这个类的内部应该有关于数据库链接的成员变量,所以可以通过conn.close()方法来关闭链接。java可以通过jni调用c/c++代码。所以connection中应该调用了本地方法。
    明白了 ... 
      

  26.   

     conn.close()关于关闭连接的部分,就是发个通知而已。
      

  27.   

    你的这个需求很明确是做不到的,根本原因是Java只有值传递,也许有人要喷我说“基本类型才是值传递,对象类型是引用传递”,对于这个观点已不想再多辩解,但是将来如果继续有人说Java有引用传递我会拉他来看看这个帖子
      

  28.   


    怎么发通知 ?我很好奇 ?
    因为,就算Connection里面包含里一个真正连接jni的代码块,在conn = getConnection()的时候也是conn指向了那个代码块,此时conn链接了conn,又怎么自我关闭呢 ?关于这一设计方式,我没想通!求解释
      

  29.   

    Java核心技术中是这样解释参数传递的:认为方法参数的传递方式都是值传递。
    我是这么理解的,对于8中基本类型,传递的自然是值。而对于对象类型的参数,传递的应该是该对象所指向的内存地址,也就是一个地址值。
    对于你的程序:当你将实参a传入方法时,形参a得到实参a的地址,也就是说实参a和形参a指向了同一个内存空间(对象)。而你将形参a赋值为空,此时实参a并没有改变指向地址。所以说,你System.out.println(a);时还能打印出a的地址,你也可以在a =null;这句话下面添加System.out.println(a);,看能不能打印出形参a的地址。
      

  30.   

    楼主别纠结了,java只有值传递。你这个问题稍微变通一下就好了。