一、Java中的引用及C/C++中的指针
Java作为C++的“派生类”,其大部分底层逻辑和C++十分接近甚至相同,因此要想理解Java中的引用变量,就要先理解C++中的指针。
1.C/C++中的指针
指针是标准C与C++中都存在的一种重要的数据类型,可以说是C语言的核心。C/C++中为编程者提供了丰富的指针类型,其中包括各种基本类型的指针、构造类型(数组、结构体、对象)的指针、数组指针、函数指针、二级(或者以上)的指针,再结合“&”(取地址操作符)以及“*”(解引用操作符)可以实现更加多样化的编程逻辑与程序。
2.Java中的引用
Java 语法中并没有为编程者提供类似C语言中指针的数据类型,也就是说编程者无法通过关键字直接创建指针。但是Java在创建基本数据类型、类的对象的过程中都会创建一种隐式的指针,即Java中的引用。
二、Java在定义不同数据类型时创建的引用
以下为综合Java特性以及C++中指针特性的个人理解,其中可能包含非客观的过程,谨为逻辑思考提供思路,深入理解提供借鉴,如有不当,敬请斧正。
1.定义基本数据类型时创建的引用
(1)数值型
public class Shuzhi {
public void test(){
int shuzhi=1;
}
}
以上代码完成的操作是:
1.创建了该基本数据类型(示例中为int)的引用,引用名为该基本数据类型名(示例中为shuzhi)。
2.在栈区创建了该基本数据类型(示例中为int)的变量内容(示例中为1)。
3.变量内容在编译器处理下实际为该内容的地址(示例中即1这个代码实际上返回1的地址),将内容的地址赋给引用,完成定义。
4.该数值类变量定义后被再次使用时都被会被自动解引用(即根据引用内容自动取内容),因此之后可以继续完成赋值等操作。如:
shuzhi=2
该代码完成的操作为(*shuzhi)=2。
byte,char,long,float,double等数据类型引用的创建同int。
2.定义引用数据类型时创建的引用
(1)数组
public class Shuzu {
public void test(){
int[][] shuzu=new int[][]{{1,2,3},{4,5,6}};
}
}
以上代码完成的操作是:
1.创建了该数组(示例中为int[][])中数据类型的引用,引用的维数(类似于C++中数组指针的维数)取决于关键字中的方括号的个数,即数组的维数,并且要比数组维数低一维(示例中为int类的一维数组引用),引用名为该数组名(示例中为shuzu)。
2.在栈区创建了该数组(示例中为int一维数组)的变量内容(示例中为1,2,3)。
3.new 关键字以及其后数组(类似于C++中的动态内存开辟)在编译器处理下实际为该数组内容首元素的地址(示例中即new int[]{1,2,3}这个代码实际上返回首元素1的地址),将内容的地址赋给引用,完成定义。
4.该数组定义后可以通过“[]”下标引用实现赋值等操作,如:
shuzu[0][0]=1;
该代码完成的操作为*(*(shuzu+0)+0)=1。
byte,char,long,float,double等类型数组引用的创建同int。
(2)字符串
字符串是Java中特殊的引用数据类型——String类,其对象的引用的创建和数组有所区别。
public class Zifuchuan {
public void test(){
String zifuchuan="Hello World";
//或者表示为 String zifuchuan=new String("Hello World");
//这两种表示方式等效的,不过非注释的形式是简写形式。
}
}
以上代码完成的操作是:
1.创建了该String类的引用,引用名为该String类的对象名(示例中为zifuchuan)。
2.在JVM(java虚拟机)的堆区的字符串常量池中创建了该对象的内容(示例中为Hello World)。
3.new 关键字以及其后字符串(类似于C++中的动态内存开辟)在编译器处理下实际为该对象内容首元素的地址(示例中即new String("Hello World")这个代码实际上返回首元素字符H的地址),将内容的地址赋给引用,完成定义。
4.该字符串定义完成后可以通过String的引用调用其方法等,如:
String zifuhchuan2=zifuchuan.toUpperCase();
该代码调用了String类中的转换大写方法,值得注意的是toUpperCase()的定义。
定义中返回类型标明是String类,实则为String类的引用,如此同为String类引用的zifuchuan2才可以接受方法返回值的赋值。
(3)自定义类
自定义类对象的引用的创建和String类对象的引用创建类似。
class Lei{
int x;
public Lei(int x) {
this.x = x;
}
}
public class Main {
public static void main(String[] args) {
Lei lei=new Lei(1);
}
}
以上Main类中main方法中代码完成的操作是:
1.创建了自定义类的引用(示例中为Lei),引用名为该自定义类的对象名(示例中为lei)。
2.在JVM(java虚拟机)的堆区的中创建了该对象的内容(示例中包含了一个成员变量int x)。
3.new 关键字以及其后构造方法(类似于C++中的动态内存开辟)在编译器处理下实际为该对象内容首元素的地址(示例中即new Lei(1)这个代码实际上返回首元素的地址),将内容的地址赋给引用,完成定义。
4.该类定义完成后可以通过其引用调用其字段,如:
System.out.println(lei.x);
(4)自定义类的数组
自定义类数组的引用的创建和自定义类对象的引用创建类似,但又有所区别。
class Lei{
int x;
public Lei(int x) {
this.x = x;
}
}
public class Main {
public static void main(String[] args) {
Lei[] lei=new Lei[]{new Lei(1),new Lei(2),new Lei(3)};
}
}
以上Main类中main方法中代码完成的操作是:
1.创建了自定义类数组中对象的引用(示例中为Lei),引用的维数(类似于C++中数组指针的维数)取决于关键字中的方括号的个数,即数组的维数,并且要比数组维数低一维(示例中就为数组内容中对象的引用),引用的级数为2级(类似于C++中的二级指针),引用名为该数组名(示例中为lei)。
2.在JVM(java虚拟机)的堆区的中创建了该对象数组的内容(示例中包含了三个对象 )。
3.数组内new 关键字以及其后构造方法(类似于C++中的动态内存开辟)在编译器处理下实际为该对象内容首元素的地址(示例中即new Lei(1)、new Lei(2)、new Lei(3)这几个代码实际上分别返回首元素的地址),将内容的地址储存在该数组中;而new关键字以及其后的数组(示例中为new Lei[])在编译器处理下实际同样为内容首元素的地址,将内容的地址赋给引用,完成定义。
这里也就说明了为什么创建的是自定义数组中对象的二级引用。
4.该类定义完成后可以通过其引用调用其元素,如:
System.out.println(lei[0].x);
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理