Java对象、对象引用关系及参数传递讨论

学习Java的过程中,很容易将对象及对象引用混为一谈,而且我们平时在交流时为了方便起见也只是对象怎样、对象怎样,但很多时候我们操作的,根本上来说是对象,但直接操作的却是对象的引用。

先贴一篇博文,非常形象的解释了对象及对象引用间的关系

  • .Java语言中通过对象的引用来操纵对象,要注意的一点是对象和对象的引用是存储在不同的地方的,因为对象往往所占的空间要求比较大,所以对象存储在堆中,而为了便于操作,对象的引用则存储在堆栈中。
  • Object obj = new Object();通过这个动作在Java中可以创建一个对象,其实这包含了4个动作:
    • new Object,以Object类为模板,在堆中创建一个对象
    • new Object(),调用Object类的构造方法,对刚生成的对象进行初始化
    • 左边的”Object obj“则是创建了一个Object类的引用变量,即obj变量是可以指向Object对象的对象引用
    • “=”操作符将对象引用obj指向刚刚创建的那个对象
  • 可以近似的将Java中对象的引用理解为C语言中的指针,即对象引用在堆栈中存储的是它所指向的对象在堆中的地址。
  • Java中的基本类型,不是通过new来创建变量,尽管基本类型变量存储在堆栈中,但它并不是引用型变量,这个变量直接存储“值”,因此更加高效。此外,由于Java是需要面向对象的,所以基本类型都会有对应的包装类。对这些包装类的值操作实际上都是通过对其对应的基本类型操作而实现的。

包装类的用途主要包含两种:

a、作为和基本数据类型对应的类类型存在,方便涉及到对象的操作。

b、包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。

c、注意Java的基本类型及其对应的包装器类型所占存储空间的大小,并不像其他大多数语言那样随机器硬件架构的变化而变化,这就使得Java程序更便于移植。

  • Java中对象的引用是存储在堆栈中的,然而对象是存储在堆中的,由于对象是通过对象的引用进行操作的,所以如果一旦一个对象没有指向它的引用变量,这个对象就成为“垃圾”,需要JVM进行垃圾回收。
  • Java只有一种参数传递方式:那就是按值传递,即Java中传递任何东西都是传值。如果传入方法的是基本类型(或其对应包类型)的东西,你就得到此基本类型的一份拷贝。如果是传递引用,就得到引用的拷贝,即指向同一块地址空间。

    Java中的基本类型及其对应包类型:

    这些类型的变量的参数传递都是值传递,此外尽管String类型不是基本类型,但可以将其当做是char[]的包装类,这也就解释了为什么String类型的变量在方法参数传递时是值传递的原因。这也就是为什么当对字符串的操作在通过不同方法来实现的时候,推荐大家使用StringBuffer的真正原因了。

public class Main {

    public static void op1(StringBuffer s){
        s.append(" world!");
        System.out.println("s:"+s);
    }
    public static void op2(StringBuffer s){
        s = new StringBuffer("java");
        System.out.println("s:"+s);
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        StringBuffer str;
        str = new StringBuffer("hello");
        System.out.println("str:"+str);
        op1(str);
        System.out.println("str:"+str);
        op2(str);
        System.out.println("str:"+str);
    }

}

要理解Java中值传递的运行机制,最好从Java内存空间分配的角度去理解,毕竟对象和对象的引用是存储在不同位置的,所以Java对象和引用的关系可以说是互相关联,却又彼此独立。彼此独立主要表现在:引用是可以改变的,它可以指向别的对象。

运行结果:

分析:

op1操作:

op2操作:str,s是两个独立的引用变量,s是Java在内存中新建立的变量,将s指向“Java”时,原先str仍然指向“hello world”。

参数传递时,如果是对象的引用,则拷贝对象引用,使其指向相同的地址空间。

public class Main {

    public static void op1(String s){
        s += " world!";
        System.out.println("s:"+s);
    }
    public static void op2(String s){
        s = new String("java");
        System.out.println("s:"+s);
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String str;
        str = new String("hello");
        System.out.println("str:"+str);
        op1(str);
        System.out.println("str:"+str);
        op2(str);
        System.out.println("str:"+str);
    }

}

运行结果:

分析:可以看到外部方法并没有对str产生影响,因为Java语言规定String是不可变的,对String的任何操作都是产生一个新的对象。

在JAVA里,“=”不能被看成是一个赋值语句,它不是在把一个对象赋给另外一个对象,它的执行过程实质上是将右边对象的地址传给了左边的引用,使得左边的引用指向了右边的对象。JAVA表面上看起来没有指针,但它的引用其实质就是一个指针,引用里面存放的并不是对象,而是该对象的地址,使得该引用指向了对象。在JAVA里,“=”语句不应该被翻译成赋值语句,因为它所执行的确实不是一个赋值的过程,而是一个传地址的过程,被译成赋值语句会造成很多误解,译得不准确。

综上,在初始化时,“=”语句左边的是引用,右边new出来的是对象。

在后面的左右都是引用的“=”语句时,左右的引用同时指向了右边引用所指向的对象。

在参数传递时,尤其是传递的是对象的引用时,要注意“形参”和“实参”是独立的,形参在堆栈中是确实存在的,所以如果在调用方法中让形参指向了另外一个对象,实参仍然指向原来的对象。null也是一个“对象”,在Java中让形参值为null,实参的值并不等于null。

Java只有一种参数传递方式:那就是按值传递,即Java中传递任何东西都是传值。如果传入方法的是基本类型的东西,你就得到此基本类型的一份拷贝。如果是传递引用,就得到引用的拷贝,而接收这个引用的变量(形参),虽然是和实参一样指向同一块内存空间的,对指向对象操作后,其他变量访问时会得到同样的结果,但如果在此外部方法中,形参指向了另外一个对象,那么形参和实参就是独立的了,接下来的操作不会对另外一个产生任何的影响!例如,如果要是将想将某个变量置为null的话,千万不要通过类的方法setNull实现,因为那样只是让形参置值为null,不会对实参产生任何的影响,置null直接让其赋值为null即可。

时间: 2025-01-06 20:01:01

Java对象、对象引用关系及参数传递讨论的相关文章

我的Java——对象的关系

1.继承 当对象A是对象B的特例时,称对象A继承了对象B.例如,黑白电视是电视机的一种特例,彩色电视是电视的另一种特例.如果分别为黑白电视机和彩色电视机抽象出黑白电视机对象和彩色电视机对象,则这两种与电视机对象之间都是继承关系. 2.包含 当对象A是对象B的属性时 称对象B包含对象A.例如,每台电视机都包括一个显像管.当把显像管抽象成一个计算机逻辑中的对象时,他与电视机对象之间就是包含关系. 当一个对象包含另一个对象时,他将自己的内存空间中为这个被包含对象留出专门的空间,即被包含对象将被保存在包

转:Java对象及对象引用变量

Java对象及其引用 关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没法很好地理解下面的面向对象技术.把自己的一点认识写下来,或许能让初学Java的朋友们少走一点弯路. 为便于说明,我们先定义一个简单的类: class Vehicle { int passengers; int fuelcap; int mpg; } 有了这个模板,就可以用它来创建对

Java对象及对象引用变量

Java对象及其引用 关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没法很好地理解下面的面向对象技术.把自己的一点认识写下来,或许能让初学Java的朋友们少走一点弯路. 为便于说明,我们先定义一个简单的类: class Vehicle { int passengers; int fuelcap; int mpg; } 有了这个模板,就可以用它来创建对

Java对象的生命周期与作用域的讨论(转)

导读: Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除.因此,对象的生命周期长度可用如下的表达式表示:T = T1 + T2 +T3.其中T1表示对象的创建时间,T2表示对象的使用时间,而T3则表示其清除时间.由此,我们可以看出,只有T2是真正有效的时间,而T1.T3则是对象本身的开销.下面再看看T1.T3在对象的整个生命周期中所占的比例. 我们知道,Java对象是通过构造函数来创建的,在这一过程中,该构造函数链中的所有构造函数也都会被自动调用.另外,默认情况下,调用

深刻理解Java中形参与实参,引用与对象的关系

声明:本博客为原创博客,未经允许,不得转载!原文链接为http://blog.csdn.net/bettarwang/article/details/30989755 我们都知道,在Java中,除了基本数据类型之外,其他的都是引用类型,当它们作为函数参数时,传递的也是引用,通过引用可以改变对象的值,很多人便因此而忽略形参与实参,引用与对象的关系问题.废话不多说,先看下面一个例子: import java.util.*; public class Student { private String

Java对象及其引用 (1)

Java对象及其引用 [文章转载自:http://zwmf.iteye.com/blog/1738574] 说明:所有转载为个人学习存档使用,凡转载内容均注明转载出处.以后不再说明. 关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没法很好地理解下面的面向对象技术.把自己的一点认识写下来,或许能让初学Java的朋友们少走一点弯路. 为便于说明,我们先定

实习第二天-对象-对象引用-引用变量-精-精-精-下雨天

class Person{ } Person是一个数据类型-引用类型 数据类型-变量名   Person a;  声明一个引用类型的变量a,然后在栈中给引用变量a分配了内存空间 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没法很好地理解下面的面向对象技术.把自己的一点认识写下来,或许能让初学Java的朋友们少走一点弯路. 为便于说明,我们先定义一个简单的类: class Vehicl

java中的进程与线程及java对象的内存结构【转】

原文地址:http://rainforc.iteye.com/blog/2039501 1.实现线程的三种方式: 使用内核线程实现 内核线程(Kernel Thread, KLT)就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操作调度器对线程进行调度,并负责将线程的任务映射到各个处理器上.程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程(Light Weight Process,LWP),轻量级进程就是我们通常意义上所讲的线程,由于每个轻量

Java对象与引用

总结: 1. 基本数据类型的赋值不是引用,系统会自动创建两个独立的对象(内存空间) 2. 引用的赋值会覆盖两者在内存中的地址(即将两个对象合二为一),而基本数据类型的赋值不会 3. 引用存放在stack, 对象存放在heap.对象是引用的实体,我们日常看到的都是引用 对象引用 我们沿用之前定义的Human类,并有一个Test类: public class Test { public static void main(String[] args) { Human aPerson = new Hum