java中引用对比C++指针
前置知识地址:https://blog.csdn.net/wangfei8348/article/details/51383805
重点在后面的引用对比实验(测试出内存地址,我很开心哈哈哈,客观给个好评呗~~~)
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("---------------------");
}
由结果可以看到,swap()
方法体内,c、d确实交换了对方的引用的对象。
代码实质是交换了临时引用变量c和d的指向的堆内的“地址”,c原来指向C即引用C后来引用D,d原来指向D即引用D后来引用C。
准确的讲,Java只存在一种传值方式便是值传递,c和d是形参并不能改变实参的值。形参是实参的复制,其引用实参指向的对象,但是其本身的修改不影响实参本身。实参没有改变,而c、d的引用的地址值确实发生了交换,对应的引用的对象发生了改变证明了这种说法。
进一步探索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<<c->getX()<<endl;//3
cout<<d->getX()<<endl;//4
Goal* temp = c; //temp指向c指向的对象
c = d;//c指向d指向的对象
d = temp;//d指向temp指向的对象
cout<<c->getX()<<endl;//4
cout<<d->getX()<<endl;//3
//但是c、d指向谁和C、D又没什么关系,所以C、D不变
}
int main() {
Goal *C = new Goal(3);
Goal *D = new Goal(4);
swap(C, D);
cout<<C->getX();//3
cout<<D->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
}
参考:
https://blog.csdn.net/mxd446814583/article/details/79599752 (获取对象地址的方法)
https://blog.csdn.net/tianwei0822/article/details/78921823 (c++与java区别的理解(一)–引用)
https://www.cnblogs.com/coderising/p/5697986.html java中的值传递和引用传递问题
https://blog.csdn.net/cout_operator/article/details/82799372
https://blog.csdn.net/hackersuye/article/details/78875119
java中引用对比C++指针的更多相关文章
- Java中到底有没有指针;同时注意引用和指针的区别
Java中引用的作用类似于指针,但是有区别:() (1) 指针必然指向一个内存地址,如果你定义的时候不指定,就会乱指(很可能造成安全隐患)但是引用定义出来后默认指向为空. (2) 指针可 ...
- C++中引用传递与指针传递区别
C++中引用传递与指针传递区别 在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值.值传递过程 ...
- C++中引用传递与指针传递的区别
最近Garena面试的过程中,面试官提了一个问题,C++中引用传递和指针传递的区别? 根据自己的经验,联想到了swap函数,只知道既可以用引用来实现,又可以用指针传递来实现,至于二者有何区别,自己还真 ...
- java中引用
java中引用分为,强,弱,虚,软 (1)强引用 使用最普遍的引用.如果一个对象具有强引用,它绝对不会被gc回收.如果内存空间不足了,gc宁愿抛出OutOfMemoryError,也不是会回收具有强引 ...
- Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义
一.Java中什么叫做引用类型变量?引用:就是按内存地址查询 比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...
- Java中引用的详解
Java中没有指针,到处都是引用(除了基本类型).所以,当然,你肯定知道java的引用,并用了很久,但是是不是对此了解地比较全面?而这些引用有什么作用,且有什么不同呢?Java中有个java.lang ...
- java中引用的原理
转自:http://blog.163.com/xubin_3@126/blog/static/112987702200962211145825/ 在Java中的引用类型,是指除了基本的变量类型之外的所 ...
- Java中引用类 strong reference .SoftReference 、 WeakReference 和 PhantomReference的区别
当在 Java 2 平台中首次引入 java.lang.ref 包,其中包含 SoftReference . WeakReference 和 PhantomReference 三个引用类,引用类的 ...
- 转:C++中引用传递与指针传递区别
从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变. 而引用是一个别名,它在逻辑上不是独立的,它的存在具有 ...
随机推荐
- MD5 密码加密算法 系统等待
MD5 密码加密算法 public static String md(String md, String pass) { MessageDigest m; String passok = " ...
- ExtJS4 带清除功能的文本框 triggerfield
Ext.onReady(function () { Ext.create('Ext.form.FormPanel', { title: 'Form with TriggerField', bodyPa ...
- python运行selenium时出现的一个错误总结
1.SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame 场景:运用pan ...
- selenium3 + python - js 内嵌滚动处理
一.js内嵌html <!DOCTYPE html><html lang="en"><head> <meta charset=" ...
- java-通过反射获取目标类的属性,方法,构造器
首先定义一个urse package com.studay_fanshe; public class User { private String uname; private int age; pri ...
- head first python /chapter7 web(python 3 转 python 2.7)
前言 书中使用的是python3,我这里使用的是python2.7 Web 的目录树 webapp/ ├── cgi-bin │ ├── athletelist.py │ ├── athletemod ...
- BZOJ 1396||2865 识别子串
这个不是题解,看不懂的,别看了 明明应该是会的,怎么还是写了6个小时呢... 把后缀数组.height数组.排名数组求出来,那么对于原串s的任意子串[x,y](表示第x个到第y个字符组成的子串,字符从 ...
- 字符串处理 BestCoder Round #43 1001 pog loves szh I
题目传送门 /* 字符串处理:是一道水题,但是WA了3次,要注意是没有加'\0'的字符串不要用%s输出,否则在多组测试时输出多余的字符 */ #include <cstdio> #incl ...
- Errors running builder 'JavaScript Validator'错误处理
MyEclipse2014编辑代码时,只要保存就会报出如下错误信息: Errors occurred during the build. Errors running builder 'JavaScr ...
- html 测试
斯蒂芬斯蒂芬 20:23你过来吧,我们好好谈一谈 好好学习 21:22这是一个无法避免的错误 作为一个新手,我在学习HTML文件的格式,我觉得博客园的编辑器很棒, 查看这些源代码让我学习到了许多知识. ...