java 对比c 指针_java中引用对比C++指针

java对象的声明和初始化

java中,Object o 等价于C++中的 Obejct &o (改正:Object o等价于 Object* o),o本身是一个引用(其实是指针),在o未被初始化(对o进行赋值)前,o的引用为空。也就是此时o为null。进一步讲,此时o仅是一个标识符,存在于java栈中,对象Obeject没有被类加载器进行加载,也就不会有初始化的过程。

Object o = new Object()是一个声明引用并对引用赋值,把对象进行初始化的过程。此时,java类加载器加载Obejct,堆中存在Object的Class对象。

初识Java引用

下面是java引用对象的案例,可见B = A;后,B实质等价于A了。B修改对象的值A也会受到影响。此时A、B指向Java堆内同一个内存空间3594623912。

class Goal {

public int x ;

public Goal(int x){

this.x = x;

}

public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}

}

public static void testQuote(){

Goal A ;

Goal B ;

A = new Goal(1);

B = A;

B.setX(2);

System.out.println(A.getX());//2

System.out.println(B.getX());//2

A.setX(1);

System.out.println(A.getX());//1

System.out.println(B.getX());//1

System.out.println("Addess: " + Addresser.addressOf(A));//3594623912

System.out.println("Addess: " + Addresser.addressOf(B));//3594623912

}

~~~~~打个补丁,之前讲java引用等同于C++引用是不严谨的。

java引用不同于C++引用

对比引用

java中的引用:“每种编程语言都有自己的数据处理方式。有些时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C/C++里的指针)来操作对象。所有这些在 Java 里都得到了简化,一切都被视为对象。因此,我们可采用一种统一的语法。尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)。”这是java编程思想的原话。

c++中的引用:引用是已定义的变量的别名。

而观察java引用于C++指针的工作流程

对于Java引用:先在栈中存对象的引用,再向堆中申请内存空间来存该类的对象,然后指向对象所在的内存。

对于c++的指针:先在栈中存指针,再向堆中申请内存空间存该指针所指向的元素,然后指向该地址。

发现java引用和C++指针非常相似。

案例分析

观察下面的代码1

public static void testQuote() {

Goal C = new Goal(3);

Goal D = new Goal(4);

swap(C, D);//交换没有成功

System.out.println(C.getX());//3

System.out.println(D.getX());//4

}

public static void swap(Goal c, Goal d) {

Goal temp = c;//temp指向c指向的对象

c = d;//c指向d指向的对象

d = temp;//d执行temp指向的对象

// 但是c、d指向什么东西与C、D没有半毛钱关系。

}

上述代码发生了什么呢?如果c、d是C、D的引用(C++,别名),那么交换应该成功的,但是没成功啊?

利用工具查看C和D的指向的堆内对象地址,发现他们的引用地址并未发生改变。但是,形参c和d的指向的地址发生改变,指向了与原来不同的对象。(注意,初学C++的同学可能混淆指针的地址改变还是指针指向的地址(即指针的值)发生改变)

public static void testQuote() throws Exception {

Goal C = new Goal(3);

Goal D = new Goal(4);

System.out.println("Addess: " + Addresser.addressOf(C));//Addess: 3589856168

System.out.println("Addess: " + Addresser.addressOf(D));//Addess: 3589856184

swap(C, D);

System.out.println("Addess: " + Addresser.addressOf(C));//Addess: 3589856168

System.out.println("Addess: " + Addresser.addressOf(D));//Addess: 3589856184

System.out.println(C.getX());//3

System.out.println(D.getX());//4

}

//

public static void swap(Goal c, Goal d) throws Exception {

System.out.println("---------------------");

System.out.println("Addess: " + Addresser.addressOf(c));//Addess: 3589855840

System.out.println("Addess: " + Addresser.addressOf(d));//Addess: 3589855856

System.out.println(c.getX());//3

System.out.println(d.getX());//4

Goal temp = c;//temp指向c指向的对象

c = d;//c指向d指向的对象

d = temp;//d指向temp指向的对象

System.out.println("Addess: " + Addresser.addressOf(c));//Addess: 3589855856,c指向的地址发生改变,所以引用的对象也发生了改变。

System.out.println("Addess: " + Addresser.addressOf(d));//Addess: 3589855840,d指向的地址发生改变,所以引用的对象也发生了改变。

System.out.println(c.getX());//4

System.out.println(d.getX());//3

System.out.println("---------------------");

}

b11af977f3d22dff738186faa9b0e6bd.png

由结果可以看到,swap()方法体内,c、d确实交换了对方的引用的对象。

代码实质是交换了临时引用变量c和d的指向的堆内的“地址”,c原来指向C即引用C后来引用D,d原来指向D即引用D后来引用C。

准确的讲,Java只存在一种传值方式便是值传递,c和d是形参并不能改变实参的值。形参是实参的复制,其引用实参指向的对象,但是其本身的修改不影响实参本身。实参没有改变,而c、d的引用的地址值确实发生了交换,对应的引用的对象发生了改变证明了这种说法。

c0d4edea75ecd9db0502c816c34b73eb.png

进一步探索Java“指针”

(这个部分统一将Java引用称之为Java指针)

其实,上面的交换的代码等价于C++的这段代码:

class Goal {

public:

int x;

Goal(int x) {

this->x = x;

}

int getX() {

return x;

}

void setX(int x) {

this->x = x;

}

};

void swap(Goal* c, Goal* d) {

cout<getX()<

cout<getX()<

Goal* temp = c; //temp指向c指向的对象

c = d;//c指向d指向的对象

d = temp;//d指向temp指向的对象

cout<getX()<

cout<getX()<

//但是c、d指向谁和C、D又没什么关系,所以C、D不变

}

int main() {

Goal *C = new Goal(3);

Goal *D = new Goal(4);

swap(C, D);

cout<getX();//3

cout<getX();//4

return 0;

}

由代码结果知,上断的结果与Java版本结果相同。以指针为函数参数实现了与Java版本相同的效果。这给我们猜测Java引用是指针留下了依据。同时观察对比C++的交换两个数的实现:

void swap(int &a,int &b) //方法1改进 (引用传递) &a &b为实参ab的地址,真交换

{

int temp=a;

a=b;

b=temp;

}

void swap(int *a,int *b) //方法1改进 (指针传递) 用指针,真交换

{

int temp;

temp=*a;

*a=*b;

*b=temp;

}

依据第一个函数,Java传入的对象参数是引用这个就不成立了。至少Java传入对象不同于C++的引用(别名)。而上文我们讲过Java实质只存在一种传参方式即值传递。众所周知,C++中存在三种传值方式:值传递、引用传递、地址传递(指针)。

在C++中,指针是一种变量,可以作为参数传递,

指针最为重要的作用是通过“解引用”实现对变量的间接使用。在Java中,函数传入参数为对象时,实参指向的对象可以被形参引用,形参通过这种方式也可以实现“间接使用”

从这个角度上讲,任何对象如果被当作函数参数进行传递,那么其就可以被看作一种“指针“

所以,java引用并非C++中的引用。

那么又有一个问题,C++指针可以通过*实现解引用,Java”指针“怎么使用呢?

因为Java中指针式对象,可以直接使用对象的方法,以此实现”解引用“

例如,如果想修改对象的成员的值,可以利用传入对象(指针)的set方法修改,这种修改并不会随着函数弹出Java栈而消失,是Java指针实现的”间接使用“的方式,如最开始的例子。

Q:那么C++指针与Java指针还有什么不同呢?

A:我的理解是,Java所有对象都可以是指针们就像所有对象都有”锁“一样,这一点不同于C++的显示声明指针对象。

最后是一个形参指针指向不同对象的例子,由结果知,该形参integer原指向堆内位置为3594611568的对象,即var2,var1;指向的对象,后来指向了新new出来的Integer(2);对象。

代码如下:

@Test

public void test3() throws Exception {

Integer var1=new Integer(1);

Integer var2=var1;

System.out.println("Addess: " + Addresser.addressOf(var1));//3594611568

System.out.println("Addess: " + Addresser.addressOf(var2));//3594611568

doSomething(var2);

System.out.println("Addess: " + Addresser.addressOf(var1));//3594611568

System.out.println("Addess: " + Addresser.addressOf(var2));//3594611568

System.out.println(var1.intValue());

System.out.println(var2.intValue());

System.out.println(var1==var2);

}

public static void doSomething(Integer integer) throws Exception {

System.out.println("Addess: " + Addresser.addressOf(integer));//3594611568

integer=new Integer(2);

System.out.println("Addess: " + Addresser.addressOf(integer));//3594634008

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值