关闭

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

发表于:2024-8-23 09:38

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:田硕1895    来源:CSDN

  一、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),我们将立即处理
《2024软件测试行业从业人员调查问卷》,您的见解,行业的声音!

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号