深入理解Java中的指针——引用

 一、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);

三、总结

以上便是个人关于Java中引用的理解,再次声明:其中可能包含非客观的过程,谨为逻辑思考提供思路,深入理解提供借鉴,如有不当,敬请斧正。

  • 31
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值