改变指向-怎么在函数中让函数参数指向null

改变指向---如何在函数中让函数参数指向null都说Java里面没有“&”,这个若大悲剧就在于,很多时候做事情不方

改变指向---如何在函数中让函数参数指向null
都说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 ;放在外面。
2.即使你不放在外面,也没关系,过了main函数,a的生命周期也结束了,java中不需要你手动销毁对象,貌似也没提供api供你销毁单个对象,java有自带的垃圾收集机制。

其实java是简化了程序员的操作(相对c++来说),有C++基础学java还是很轻松的。少数地方转变下观念,大部分地方跟c++还是很类似的。

你的需求描述中,在方法内部改变方法外部变量的引用,java貌似是做不到的。
[解决办法]
你那是什么写法。。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();
}
}

[解决办法]
A a=new A();

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


执行System.gc()销毁的也是new A()这个对象
[解决办法]
1、函数的参数是要入栈的。
2、将对象传入之后,就是指向该对象的地址,在函数内再将对象置空。只是改变的局部的变量和外界的没关系。
可以看图:改变指向-怎么在函数中让函数参数指向null
[解决办法]

引用:
Quote: 引用:

1.为什么不把a = null ;放在外面。
2.即使你不放在外面,也没关系,过了main函数,a的生命周期也结束了,java中不需要你手动销毁对象,貌似也没提供api供你销毁单个对象,java有自带的垃圾收集机制。

其实java是简化了程序员的操作(相对c++来说),有C++基础学java还是很轻松的。少数地方转变下观念,大部分地方跟c++还是很类似的。

你的需求描述中,在方法内部改变方法外部变量的引用,java貌似是做不到的。


不是我要乱想,是真实需求决定的,可能我上面的那个特别说明没有说清楚,我现在举个例
子:
假设
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”这个需求没有必要,不知道我的理解对不对。


[解决办法]
虽然看起来有点迷惑性,但其实吧。当调用fun函数的时候确实让fun里面的行参a指向了对象A,这时引用变量a和fun的行参a同时指向对象A,没错。但是马上又让行参a指向了null,那么这时行参a已经不再指向对象A了,那么对行参a的操作即让其等于null也就不会在对象A中保存。也就是说对行参a的操作不会影响到对象A了,此时它们是两个不同的对象。但是引用变量a还是指向对象A,所以你输出的是引用变量a指向的那个对象的值。
[解决办法]
还有一点就是  java中设计到对象的声明周期的 都是跟该对象的引用计数器有关  你再函数内部将a=null 即使你显示调用System.gc()即使马上回收内存 也不会回收new A()的内存  因为此时在main函数中A a 还依旧指向new A()的那块内存....
[解决办法]

引用:
Quote: 引用:

你的back方法,我仔细看了下,是不是这个意思?
将传进来的a(也是alist中的一个)放到alist中,再把传进来的这个对象a销毁掉。
整个业务是不是:将alist中的一个对象拿出来用一下,再放回去。

如果是这个意思的话,以下是我的看法。
1.get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。
2.如果为了对象在list中的顺序之类的需求,必须取出放回的话,应该使用LinkedList,类似队列。

所以感觉你的“将a指向null”这个需求没有必要,不知道我的理解对不对。


首先,很感谢你的阅读,的确是先从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中引用指向的堆中对象数量并没有变。
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

你的back方法,我仔细看了下,是不是这个意思?
将传进来的a(也是alist中的一个)放到alist中,再把传进来的这个对象a销毁掉。
整个业务是不是:将alist中的一个对象拿出来用一下,再放回去。

如果是这个意思的话,以下是我的看法。
1.get方法只会获得对象的引用,类似指针,并不是拷贝了一个新的对象,对象依然在alist中,你不需要再放回去。
2.如果为了对象在list中的顺序之类的需求,必须取出放回的话,应该使用LinkedList,类似队列。

所以感觉你的“将a指向null”这个需求没有必要,不知道我的理解对不对。


首先,很感谢你的阅读,的确是先从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中应该调用了本地方法。
[解决办法]
 conn.close()关于关闭连接的部分,就是发个通知而已。
[解决办法]
你的这个需求很明确是做不到的,根本原因是Java只有值传递,也许有人要喷我说“基本类型才是值传递,对象类型是引用传递”,对于这个观点已不想再多辩解,但是将来如果继续有人说Java有引用传递我会拉他来看看这个帖子
[解决办法]
Java核心技术中是这样解释参数传递的:认为方法参数的传递方式都是值传递。
我是这么理解的,对于8中基本类型,传递的自然是值。而对于对象类型的参数,传递的应该是该对象所指向的内存地址,也就是一个地址值。
对于你的程序:当你将实参a传入方法时,形参a得到实参a的地址,也就是说实参a和形参a指向了同一个内存空间(对象)。而你将形参a赋值为空,此时实参a并没有改变指向地址。所以说,你System.out.println(a);时还能打印出a的地址,你也可以在a =null;这句话下面添加System.out.println(a);,看能不能打印出形参a的地址。
改变指向-怎么在函数中让函数参数指向null