Java笔记1

一、Java的值传递

(作者:知乎用户
链接:https://www.zhihu.com/question/20628016/answer/15683373
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处)

Java 中的所有函数调用都是值传递。

值传递是指,函数在调用时,传递的参数不是实参本身,而是它的副本。

引用传递是指,函数在调用时,传递的参数就是实参本身(的地址)。

显然,在使用引用传递的情况下,在函数体内可以对参数本身进行修改,修改结果会对函数调用者产生影响。而使用值传递,由于函数内对参数的修改实际上不是对参数本身,而是对参数的副本进行的修改,因此,修改结果不会对调用者产生影响。

在 Java 中,对象(类的实例)都是通过引用来访问的。例如:

    Object foo = new Object();

其中,foo 是一个引用,指向了新创建的这个 Object 对象。

的确,你可以在某个方法(函数)中,对其参数引用的对象进行修改,例如:

    void doSth(Object bar) {
        bar.attr = newValue;
    }


假设某个调用者调用了 doSth 方法,并且将 foo 传入。在方法返回之后,foo 所引用的对象的 attr 属性变成了 newValue。但这并不是值传递。因为 doSth 方法体内修改的是 foo 所引用的对象,而不是 foo 本身。

在 Java 中,你绝不可能在方法体内,把作为参数传入的引用本身指向其他对象。因为 Java 所有的函数调用都是值传递。这样的修改只会修改参数的副本,而不是参数本身。

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

Java 的设计目的之一就是为了填 C/C++ 的各种「坑」,让编程语言更加易用和易于理解,例如垃圾自动回收机制,单继承策略,等等。引用传递使得方法内部可以对方法外的数据进行修改,这无疑增加了一定的(但我觉得这很少)危险性。当然,这会使语言的灵活性降低,就算你对你的数据掌控得很好,你也不能随心所欲地修改它。事实上,你完全可以通过传递引用参数来修改方法外创建的对象。因此,受到制约的实际上就只有那些原生类型而已。

或许这是 Java 注重安全性与实用性而宁愿放弃一些灵活性的设计哲学的一种体现。
 

1.这个解释的不错,其实不用长篇大论,本质上讲java没有所谓的引用(地址)传递是因为java规定了引用本身不能操作修改内存地址;
2.值传递与引用传递的最大区别就是内存属于copy还是share,前者属于copy,基本类型直接copy内容,object的变量copy的是内存地址(也就是引用),copy过来的引用是被包装过的,因此在java里没办法操作引用去修改变量的内存地址,也就是你代码解释的情况;
3.假如说java中有"引用传递",那么违背了java资深的规定,引用是"只读"的(而C++的指针是可读写的);
4.而C++由于采用的是指针,指针是"可写"的,因此才分别给了“”copy(值传递)“”和"share(地址传递)"来作明确区分.

二、JAVA中堆和栈的区别

 

在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。   

  当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。   

  堆内存用来存放由new创建的对象和数组。   

  在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。   

  在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。   

  引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。   

java中变量在内存中的分配

1、类变量(static修饰的变量):在程序加载时系统就为它在堆中开辟了内存,堆中的内存地址存放于栈以便于高速访问。静态变量的生命周期--一直持续到整个"系统"关闭

2、实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量(比如说类实例),然后根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的"物理位置"。 实例变量的生命周期--当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存

3、局部变量:局部变量,由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放

附:java的内存机制

Java 把内存划分成两种:一种是栈内存,另一种是堆内存。

      在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

  堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。

  这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

C或C++中的指针详解

三、Java的ThreadLocal源码分析

四、Java  ThreadLocalMap的引申 (强引用,弱引用,软引用,虚引用)

五、Redis服务及应用场景

六、Java Spring Redis(spring配置,RedisTemplate类详解,@CachePut@Cacheable@CacheEvict)

七、Java并发编程:线程池的使用       ThreadPoolExcuter详解

八、并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法

九、FIFO原则,JAVA CAS原理深度分析(java.util.concurrent包源码实现、Lock 与 Synchronized 的比较)

http://blog.csdn.net/hsuxu/article/details/9467651(CAS原理)

https://www.cnblogs.com/onlywujun/articles/3531568.html(Lock源码分析)

 
原文地址:https://www.cnblogs.com/tooy/p/8033997.html