Java中的引用和C++中引用的区别

首先了解C++ 中引用的含义:“引用”即“别名”。C++中的引用代表的就是实际的存储空间。对其进行操作就是对存储空间进行操作。

而在Java中的引用:可以看做是C语言中的“指针”或者“地址”。对java中引用的属性(即指针指向的存储空间)进行操作才是有效的。

1)Java引用作为函数(方法)参数

Java的方法参数只是传值,引用作为参数使用时,会给函数内引用的值的COPY,所以在函数内交换两个引用参数是没有意义的,因为函数交换的是参数的COPY值;但是在函数内改变一个引用参数的属性是有意义的,因为引用参数的COPY值指向的对象和原引用指向的是同一个对象。

2)C++引用作为函数参数

由于C++引用传进去的就是“别名”,所以在函数内对其进行的全部操作都将直接作用于实际的对象存储空间上。

产生这个困惑的原因很可能是涉及到在函数(方法)中进行malloc(new)新的堆空间有关。其实这是一个比较有意思的问题。

Java中没有了指针,这种不便可以通过Java的引用特性得到弥补。即对于Java的任何对象,我们可以申明对象变量,但不产生实例,这样,把该变量指向具有实际实例的对象,即可实现同一实例对象的多个变量引用,如:

int x[]={1,2,3,4,5}, y[];

y=x;

for(int i=0; i<y.length; i++) System.out.print(“   ”+y[i]);

则完成了通过y对x的引用。从这个实际效果看,y在这里就很象C语言中的指针了。只不过对于“指针”y我们不能进行+或-这类算数运算,即Java的引用只能指向程序限定的能够访问的现存对象,所以Java的实现者认为它是灵活同时也是安全的。

但对于C或者C++中能够通过函数简单实现的两个数交换问题,即C++如下函数:

void swap(int &x, int &y) { int t; t=x; x=y; y=t; }

在Java中是否能够实现呢?

按照Java的规定,Java的函数参数在传递的时候有两种方式。对于基本类型,如int,double等作为函数参数传递时,采取的是传值方式。而对于对象,如数组、字符串等作为参数传递时,采用的是引用方式,即此时在函数中对传递的对象的修改将完全影响原对象。那能否对于对象利用引用完成值的交换呢?下面的程序充分地演示了这个问题:

public class test {

public static void main(String[] arg) {

int x1[]={1,2,3},x2[]={3,2,1};

swap(x1,x2);//采用swap函数,即直接利用参数引用进行交换

System.out.print("swap->X1:\t"); printarr(x1);

System.out.print("swap->X2:\t"); printarr(x2);

swapArray(x1,x2);//采用swapArray函数,利用对于对象的值的修改进行交换

System.out.print("swapArr->X1:\t"); printarr(x1);

System.out.print("swapArr->X2:\t"); printarr(x2);

Object t;

t=x1; x1=x2; x2=(int[])t;//在非函数调用中直接利用引用进行交换

System.out.print("Tswap->X1:\t"); printarr(x1);

System.out.print("Tswap->X2:\t"); printarr(x2);

}

public static void swap(Object x, Object y) {//直接利用参数引用交换

Object t=x;

x=y;

y=t;

}

public static void swapArray(int x[], int y[]) {//对引用对象的值进行修改完成交换

if(x.length!=y.length) return;

int t[]=x.clone();

for(int i=0; i<x.length; i++) x[i]=y[i];

for(int i=0; i<y.length; i++) y[i]=t[i];

}

public static void printarr(int x[]) {//打印数组

for(int i=0; i<x.length; i++) System.out.print(x[i]+"  ");

System.out.println();

}

}

在函数swap中,我们直接利用参数进行交换。在函数swapArray中,我们通过修改参数指向的两个数组的值进行交换。而在main函数没有进行函数参数传递的情况下,我们直接利用参数的引用进行了一次交换。

程序的运行结果如下:

swap->X1:     1  2  3

swap->X2:     3  2  1

swapArr->X1: 3  2  1

swapArr->X2: 1  2  3

Tswap->X1:   1  2  3

Tswap->X2:   3  2  1

从运行结果我们可以清楚地看到,函数swap实际没有完成交换,而函数swapArray和直接在main中利用引用进行的交换是成功的。从这里我们可以得知,虽然Java的引用可以实现C和C++的指针的类似的效果,这在主函数中的引用交换得到了证明。但是一但进行了函数的参数传递,这种引用方式的交换便实效了。虽然它的交换方式和主函数中利用Object引用t进行的交换方式相同。猜测其原因(因为我不是Java的实现者),只能说明,函数中的引用变量和主函数中调用的变量是不相同的。即在调用swap函数时,虽然将x1的引用传递给了x,x2传递给了y,x和y进行了交换,但x1和x2并没有进行交换。也就是说,在函数swap申明参数x和y时,实际另外真正的生成了与x1和x2完全不相干的引用,只不过x和y都同样指向了x1和x2罢了,即此时,数组对象x1和x2同时分别有两个指针x、x1和y、y1指向它们。这样的结果当然不能完成如C和C++类似的交换。唯一的办法是如swapArray函数中一样,不要试图交换,只能试图修改参数所指向的两个对象的值来达到交换的效果。

所以我得出的一个相关的结论是:Java永远也不能实现如C和C++一样的swap函数。

Java交换两个数

在java中没有指针的概念,java中时引用,但这一概念已经被淡化了这里有两种方法:

【1】使用全局变量进行数值传递

public class Swap{

public Swap(int x,int y){

int z;

z=x;x=y;y=z;

a=x; b=y;

}

public void getInfo(){

System.out.println("交换后:a= "+a+",b="+b);

}

private static int a;

private static int b;

public static void main(String args[]){

a=10;

b=8;

System.out.printf("交换前: a="+a+",b="+b+"\n");

F w1=new F(a,b);

w1.getInfo();

}

}

【2】把用于交换的参数作为对象的一个变量

class T{

int t;

}

public class G {

public static void main(String args[]){

T a=new T();

T b=new T();

a.t=8;

b.t=10;

System.out.println("交换前 :a="+a.t+"  ,b="+b.t);

change(a,b);

System.out.println("交换后 :a="+a.t+" ,b="+b.t);

}

public static void change(T a,T b){

T c=new T();

c.t=a.t; a.t=b.t; b.t=c.t;

}

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-14 16:50:29

Java中的引用和C++中引用的区别的相关文章

Java中的软(弱)引用

一.Java中的强.软.弱.虚引用 在JDK中我们可以看到有一个java.lang.ref的包,这个包中就是Java中实现强.软.弱.虚引用的包,如下: PhantomReference 虚引用:如果一个对象持有虚引用,就和没有持有引用一样,在任何时候都可能被垃圾回收器回收.虚引用主要用来跟踪对象被垃圾回收的活动,虚引用还有一个和弱.软引用不同的地方是虚引用必须和引用队列联合使用.当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象内存之前,把这个虚引用加入到与之关联的引用队列中

Java中带包(创建及引用)的类的编译与调试

Java中带包(创建及引用)的类的编译与调试 java源程序的编译大家都知道,也就是cmd中到源文件所在目录下javac **.java即可,当程序中有包声明还能简简单单的直接javac **.java吗?答案当然是no,下面举个简单的例子证明一下直接javac **.java会怎么样. 如下:F:\javaweb2班\20160531目录下有A.java文件,注意源文件中有包声明 package mypack; public class A { String name; int age; pu

java中虚引用PhantomReference与弱引用WeakReference(软引用SoftReference)的差别

之前的这篇博客介绍了java中4种引用的差别和使用场景,在最后的总结中提到: "软引用和弱引用差别不大,JVM都是先把SoftReference和WeakReference中的referent字段值设置成null,之后加入到引用队列:而虚引用则不同,如果某个堆中的对象,只有虚引用,那么JVM会将PhantomReference加入到引用队列中,JVM不会自动将referent字段值设置成null".这段总结写的比较仓促,也没有给出实际的例子加以佐证.本文主要是重申下这几种引用的差别,并

Java中的克隆close()和赋值引用的区别

学生类Student: package 克隆clone; /*要克隆必须实现这个借口:Cloneable,以标记这个对象可以克隆 Cloneable:此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制. 这个接口是标记接口,告诉我们实现该接口的类就可以实现对象的复制了. */ public class Student implements Cloneable { private String name; private int ag

this.getClass().getClassLoader().getResourceAsStream(fileName)中的路径问题。(引用)

ClassLoader.readResourceAsStream 是从 classpath 中读取,也就是说目标资料必须在某个 classpath 节点路径中,比如在某个磁盘文件夹 bin 中或某个 jar 文件里面.放在 src 里面的话,eclipse 会自动在编译时默认地复制到 bin 目录下,当然你可以故意禁用这个默认功能(参数页中 Java > Compiler > Building 里面有个 Filtered Resources).eclipse 默认配置下你放在 src 下面就可

有关打包成可执行jar包后引用jar包中配置文件问题

一 问题由来 有时候我们做一些项目时,需要将一些配置信息写入配置文件中,以供调用.比如说这样: 如果我们需要在Demo.java中读取config.txt这个文件中的配置信息,在这种工程目录下是可以使用File来读取的,但是打包成jar后,使用File将不能读取到config.txt了,除非将这个配置信息放在jar包的外面. 假如说我们用File来读取文件: BufferedReader reader = new BufferedReader(new FileReader(new File("r

JavaSE8基础 多态 子类重写了父类的普通方法 父类引用调用子类中重写的方法

os :windows7 x64    jdk:jdk-8u131-windows-x64    ide:Eclipse Oxygen Release (4.7.0)        代码: class Father { public int num = 1; public void sayHello() { System.out.println("hello"); } public static void staticFun() { System.out.println("s

JavaSE8基础 多态 子类没有重写 父类引用调用父类中的方法

os :windows7 x64    jdk:jdk-8u131-windows-x64    ide:Eclipse Oxygen Release (4.7.0)        代码: class Father { public int num = 1; public void sayHello() { System.out.println("hello"); } public static void staticFun() { System.out.println("s

html或者jsp页面引用jar包中的js文件

一,页面上引用jar包中的js文件的方法 使用java web框架AppFuse的时候发现,jquery.bootstrap等js框架都封装到jar包里面了.这些js文件通过一个wro4j的工具对其进行了压缩集成到一个js文件里面.页面使用的时候的时候,引用这一个js文件即可.通过解读wro对于js处理的过程,找到了html或者jsp引用jar包中的js文件的方法: <c:set var="base" value="${pageContext.request.conte