以前就知道JAVA对象分对象引用和值引用,并且还知道8种基础数据类型,即引用时是值引用的数据类型,比如int,short,long,byte,float,double,char,boolean,其它都是对象引用。可是其它的对象引用我一直都以为跟c里面是一样的指针传递,直到今天才发现原来JAVA里面还是别有一番天地的。
1. 方法调用的时候,并不是类似c的指针传递,而是引用的复制
比如代码:
-
void func1(List s) {
-
s.add("dfdsa");
- }
-
-
void test() {
-
List<String> list = new ArrayList<String>();
-
list.add("abc");
- func1(list);
-
System.out.println(list.size());
- }
以前一直以为在func1里面的s跟外面的list变量是同一个引用(暂且理解为指针好了)即在栈(stack)里面是同一个东东,这个结论无可厚非,可是看代码:
-
void func(String s) {
-
s += "tail";
- }
-
-
void test() {
-
String a = "abc";
- func(a);
-
System.out.println(a);
- }
-
经过讨论才发现,原来在stack里面a和func里面的s是完全不同的两个引用,虽然它们指向同一个堆(heap)里面的对象,之所以跟上面的代码结果看起来不一样,只是因为String是一个非可变类(immutable),简单的说就是实例是不可被修改的。在func里面执行s += "tail";操作的时候,s这个引用已经变成指向heap里面另外一个值为"abctail"的对象了,老的s引用已经被废了,随时可以被gc回收了
2. String对象在内存中的位置
既然String是一个immutable的类,那么对于同样值的String实例,我们是可以不必重复创建的,于是就有了JVM中的String Pool的概念。简单的说,String Pool里面放着heap里面String对象的引用。看代码:
当程序执行该代码的时候,JVM会在String Pool里面通过equal("abc")方法查找有没有现成的String对象引用,如果没有,则在heap里面创建一个String对象并将该对象的引用保存到String Pool里面;如果有了,那么就直接返回该对象的引用。
再看一段非常类似的代码:
-
String s = new String("abc");
当程序执行该代码的时候,JVM会像普通对象一样生成这个String对象,在heap里面保存,直接返回引用,并不会与String Pool交互,这样一来,String Pool的优势就没有被发挥了,怎么办呢?难道我们就不去使用new的方法创建String了吗?答案是JVM还提供了一个方法:String.intern();来让String Pool管理这种String对象。
intern方法的工作原理是这样的:首先在heap里面创建一个完全一样的String对象,并且将该对象的引用放入String Pool中,最后返回给调用方,看代码:
-
String s1=new String("abc");
- String s2=s1.intern();
-
String s3="abc";
-
System.out.println(s1==s2);
-
System.out.println(s2==s3);
-
System.out.println(s1==s3);
- s1引用的是heap里面的一个普通String对象,在String Pool中没有该对象的引用
- s2是heap中另一个String对象的引用,并且该对象的引用已经存在在String Pool中了
- s3在创建的时候JVM通过查找String Pool发现已经有一个同样的对象,所以直接返回给s3一个到该对象的引用
结论:我们在写JAVA代码的时候要尽量避免使用String s = new String("abc");这种方式,因为这样产生的对象并没有“注册”到String Pool中,无法被重复使用,如果已经存在这种对象了,我们可以通过使用s = s.intern();的方式重新创建对象并“注册”到String Pool中,方便后面的重复使用。
3. 深入JVM内存的划分
由于JVM对与heap和stack内存的使用有其特殊的规则,深入了解JVM是如何使用内存的,非常有助于我们在写程序的时候搞清楚自己的对象到底在什么地方,从而可以帮助我们在多线程程序和性能要求较高的程序中优化自己代码,有兴趣的同学可以参考sun的官方文档(http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#1732),下面仅就部分知识做简单描述。
a. 每个线程都有自己独占的stack,里面存放的是当前线程执行的method及其局部变量
b. heap中有部分是公共区域,存放的是类实例(class instance)和已分配内存的数组(array)
c. heap中对于每个线程都有各自独立的内存区域,存放以下内容:
运行时常量池(runtime constant pool),上面提到的String Pool就属于其中的一部分
方法代码(method code),即线程要执行的方法代码
静态变量和方法(static variables and method),我们定义的static类型的变量和方法都存放在这里
更详细的描述可以参考图片:
相关推荐
这里的“值”指的是基本类型的实际值,以及对象引用的值。 1. **基本类型的参数传递**:当传递基本类型作为参数时,实际上传递的是这些基本类型的值的副本。这意味着在方法内部对这些值所做的任何更改都不会影响...
### Java 错误处理:java.lang.OutOfMemoryError: Java heap space 在Java应用程序开发过程中,经常遇到的一个问题就是内存溢出错误,特别是在处理大量数据或长时间运行的应用时。其中,“java.lang....
2. **内存泄露**:某些对象引用未能正确释放,导致垃圾回收器无法回收这些对象,占用大量内存。 3. **堆内存配置不足**:JVM启动时设定的堆内存大小不足以支持应用程序的运行需求。 #### 解决方案 ##### 调整JVM堆...
在编程中,变量的引用方式分为两大类:值引用(Value Reference)和对象引用(Object Reference)。这两种引用方式决定了程序如何处理数据以及数据的存储方式。理解这些概念对于编写高效、安全的代码至关重要。 ###...
### Java中对象与引用 在Java编程中,深入理解对象与引用的概念对于掌握面向对象编程至关重要。本文将从以下几个方面详细解析对象与引用的基本概念及其相互间的关系。 #### 一、对象与引用的基础概念 **对象**: ...
在Java中正确地区分对象与对象引用是非常重要的,这不仅关系到程序的正确性,也影响到资源管理和性能优化。理解了这些基本概念之后,开发者能够更加灵活地运用Java进行开发工作,避免常见的错误和陷阱。
综上所述,在Java中,对于基本数据类型的参数传递实际上是按值传递,而对于对象类型的参数传递则是按引用传递的一种特殊形式——传递的是对象引用的副本,但由于这些副本指向同一个对象,因此对对象的修改会影响到...
### Java对象和对象的引用之间的关系 #### 一、Java对象和对象的引用的基本概念 在Java编程语言中,理解对象和对象引用之间的关系是非常重要的基础。对象是类的一个实例,而对象引用则是用于访问该对象的一种手段...
### Java对象引用详解 #### 一、Java对象与引用的基本概念 在Java中,对象是类的一个实例,而引用则是指向这些对象的变量。理解Java中的对象与引用之间的区别至关重要,因为这涉及到如何管理和操作对象。 #### 二...
总的来说,理解Java中的值传递和对象引用传递对于编写高效、无误的代码至关重要。无论是基本类型还是对象类型,参数传递都是以值的形式进行,但对象类型的值是其引用,允许我们在方法内修改对象的状态,而不影响方法...
在Java学习过程中,对于面向对象的理解和引用机制的掌握是至关重要的。本文将围绕这两个概念进行深入探讨,并针对初学者常见的疑惑点进行解答。 #### Java面向对象基础 Java是一种完全面向对象的语言,几乎所有的...
在 Java 中,对象和引用对象的关系是一个非常重要的概念。从宏观的角度来看,对象是类的实例。例如,我们可以定义一个名为 Someone 的类,代表一些人(通过指定年龄、性别、性格等基本信息)。 ```java class ...
参数传递有两种方式:值传递和引用传递。了解这两种方式的区别是非常重要的,因为它们对程序的执行结果产生了很大的影响。 值传递是指将实际的内存中的值传递给另外一个变量。例如,int a = 3; a 就指向了内存中的...
首先,我们需要理解什么是Java对象。在Java中,对象是类的实例。当我们使用`new`关键字创建一个类的实例时,就创建了一个对象。对象包含了数据(称为属性或成员变量)和行为(称为方法)。例如,如果我们有一个名为`...
在Java编程语言中,了解值传递和引用传递的概念至关重要,因为它们直接影响到函数参数的处理方式。下面将详细探讨这两个概念及其区别。 首先,我们来理解什么是值传递。在Java中,基本数据类型(如int、double、...
对象引用分析图解,描述了java对象引用在栈、堆中的分布及作用。
- **引用传递的本质**:Java中的引用传递本质上是传递对象的引用,而不是对象本身。这意味着在方法内部对对象所做的任何改变都会影响到原始对象。 - **引用与值的区别**:与基本类型的值传递不同,引用传递不会创建...
#### 一、Java对象、引用及创建过程 在Java中,对象是程序的基本单位,它包含了属性(成员变量)和行为(方法)。对象是由类创建出来的实例,而类则是一组具有相同属性和行为的对象的模板。 ##### 1. 对象创建与...
在Java编程语言中,函数参数的传递方式有两种:值传递和引用传递。理解这两种机制对于编写高效、无误的代码至关重要。以下是对这两种传递方式的详细解析。 首先,值传递是指函数调用时,实际参数的值被复制一份传给...
在Java开发中,NullPointerException(NPE)是一种常见的运行时错误,它发生在试图在null对象上调用方法或访问字段时。本资源详细介绍了如何诊断和解决这类问题,包括环境配置、错误现象、处理步骤及最终效果。