欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

java,

来源: javaer 分享于  点击 43656 次 点评:173

java,


 

Miracle He

随笔 - 42  文章 - 0  评论 - 118

Java学习之旅基础知识篇:数组及引用类型内存分配

 

      在上一篇中,我们已经了解了数组,它是一种引用类型,本篇将详细介绍数组的内存分配等知识点。数组用来存储同一种数据类型的数据,一旦初始化完成,即所占的空间就已固定下来,即使某个元素被清空,但其所在空间仍然保留,因此数组长度将不能被改变。当仅定义一个数组变量(int[] numbers)时,该变量还未指向任何有效的内存,因此不能指定数组的长度,只有对数组进行初始化(为数组元素分配内存空间)后才可以使用。数组初始化分为静态初始化(在定义时就指定数组元素的值,此时不能指定数组长度)和动态初始化(只指定数组长度,由系统分配初始值)。

//静态初始化
int[] numbers = new int[] { 3, 5, 12, 8, 7 };
String[] names = { "Miracle", "Miracle He" };//使用静态初始化的简化形式
//动态初始化
int[] numbers = new int[5];
String[] names = new String[2];

建议不要混用静态初始化和动态初始化,即不要既指定数组的长度的同时又指定每个元素的值。当初始化完毕后,就可以按索引位置(0~array.length-1)来访问数组元素了。当使用动态初始化时,如在对应的索引位未指定值的话,系统将指定相应数据类型对应的默认值(整数为0,浮点数为0.0,字符为'\u0000',布尔类型为false,引用类型为null)。

public class TestArray {
    public static void main(String[] args) {
        String[] names = new String[3];
        names[0] = "Miracle";
        names[1] = "Miracle He";
        //以下代码将输出Miracle Miracle He null
        /*
        for(int i = 0; i < names.length;i++) {
            System.out.print(names[i] + " ");
        }
        */
        //还可以使用foreach来遍历
        for(String name : names) {
            System.out.print(name + " ");
        }
    }
}

请注意:java中是没有foreach这个关键字的,其语法是for(type item : items)来表示,但foreach只能用于遍历元素的值而不能改变,必须使用for才能实现。

public class TestForEach {
    public static void main(String[] args) {
        int[] numbers = { 3, 5, 12, 8, 7 };
        for(int number : numbers) {
            int num = number * 10;
            System.out.print(num + ",");
        }
        System.out.println("");
        //numbers仍然未发生变化(如果换成for将改变)
        for(int i = 0;i < numbers.length;i++) {
            System.out.print(numbers[i] + ",");
        }
    }
}

以上简单的介绍了数组的初始化和应用,接下来讲详细介绍数组(数组引用和数组元素)在内存中的存放形式。首先给出结论:数组引用变量是存放在栈内存(stack)中,数组元素是存放在堆内存(heap)中,通过栈内存中的指针指向对应元素的在堆内存中的位置来实现访问,以下图来说明数组此时的存放形式。

      那什么是栈内存和堆内存呢?我举例作一一解释。当执行方法时,该方法都会建立自身的内存栈,以用来将该方法内部定义的变量逐个加入到内存栈中,当执行结束时方法的内存栈也随之销毁,我们说所有变量存放在栈内存中,即随着寄存主体的消亡而消亡;反之,当我们创建一个对象时,这个对象被保存到运行时数据区中,以便反复利用(因为创建成本很高),此时不会随着执行方法的结束而消亡,同时该对象还可被其他对象所引用,只有当这个对象没有被任何引用变量引用时,才会在垃圾回收在合适的时间点回收,我们说此时变量所指向的运行时数据区存在堆内存中。

      只有类型兼容(即属于同一数据类型体系且遵守优先级由低到高原则),才能将数组引用传递给另一数组引用,但仍然不能改变数组长度(仅仅只是调整数组引用指针的指向)。

public class TestArrayLength {
    public static void main(String[] args) {
        int[] numbers = { 3, 5, 12 };
        int[] digits = new int[4];
        System.out.println("digits数组长度:" + digits.length);//4
        for(int number : numbers) {
            System.out.print(number + ",");//3,5,12,
        }
        System.out.println("");
        for(int digit : digits) {
            System.out.print(digit + ",");//0,0,0,0,
        }
        System.out.println("");
        digits = numbers;
        System.out.println("digits数组长度:" + digits.length);//3
    }
}

虽然看似digits的数组长度看似由4变成3,其实只是numbers和digits指向同一个数组而已,而digits本身失去引用而变成垃圾,等待垃圾回收来回收(但其长度仍然为4),但其内部运行机制如下图所示。

 

 因此当我们看一个数组时(或者其他引用变量),通常看成两部分:数组引用变量和数组元素本身,而数据元素是存放在堆内存中,只能通过数组引用变量来访问。

      从上述的示例中看出数组中存放的是基本类型,其实数组中还可以存放引用类型的。而存放基本类型的内存分布已经解释了,而存放引用类型的内存分布则相对复杂了。来看一段非常简单的程序。

public class TestPrimitiveArray {
    public static void main(String[] args) {
        //1.定义数组
        int[] numbers;
        //2.分配内存空间
        numbers = new int[4];
        //3.为数组元素指定值
        for(int i = 0;i < numbers.length;i++) {
            numbers[i] = i * 10;
        }
    }
}

按以上步骤的内存分布示意图:

从图中可看出数组元素直接存放在堆内存中,当操作数组元素时,实际上是操作基本类型的变量。接下来再看一段程序:

class Person {
    public int age;
    public String name;
    public void display() {
        System.out.println(name + "的年龄是: " + age);
    }
}
public class TestReferenceArray {
    public static void main(String[] args) {
        //1.定义数组
        Person[] persons;
        //2.分配内存空间
        persons = new Person[2];
        //3.为数组元素指定值
        Person p1 = new Person();
        p1.age = 28;
        p1.name = "Miracle";
        Person p2 = new Person();
        p2.age = 30;
        p2.name = "Miracle He";
        persons[0] = p1;
        persons[1] = p2;
        //输出元素的值
        for(Person p : persons) {
            p.display();
        }
    }
}

对于数组元素为引用类型在内存中的存储与基本类型不一样,此时数组元素仍然存放引用,指向另一块内存,在其中存放有效的数据。

谈到这里,不知是否有朋友要问:Java的多维数组是什么样的?我的回答是:可以有。为什么呢?从底层来看,数组元素可以存放引用类型,包含数组。也就是说在数组元素的内部还可以包含数组(如int[][] numbers = new int[length][]),也即二维数组可当作一维数组(数组长度为length)来处理,也可以同时指定多个维度的长度(如int[][] matrix = new int[length][width]),不过必须至少指定最左端的数组长度length。由此我们得出结论: 任何多维数组(维度为n,n>1)都当作一维数组,其数组元素为n-1维数组
public class TestMultiArray {
    public static void main(String[] args) {
        //1.定义二维数组
        int[][] numbers;
        //2.分配内存空间
        numbers = new int[3][];
        //可以把numbers看作一维数组来处理
        for(int i = 0;i < numbers.length;i++) {
            System.out.print(numbers[i] + ",");//null,null,null
        }
        System.out.println("");
        //3.为数组元素指定值
        numbers[0] = new int[2];
        numbers[0][1] = 1;
        for(int i = 0;i < numbers[0].length;i++) {
            System.out.print(numbers[0][i] + ",");//0,1
        }
    }
}
最后,简单介绍一下Arrays(位于java.util下)的静态方法:binarySearch、copyOf、copyOfRange、equals、fill、sort、toString等方法(具体用法参见JDK)。
import java.util.Arrays;
public class TestArrays {
    public static void main(String[] args) {
        int[] a = {3, 4, 5, 6};
        int[] b = {3, 4, 5, 6};
        System.out.println("a和b是否相等:" + Arrays.equals(a, b));//true
        System.out.println("5在a中的位置:" + Arrays.binarySearch(a, 5));//2
        int[] c = Arrays.copyOf(a, 6);
        System.out.println("a和c是否相等:" + Arrays.equals(a, c));//false
        System.out.println("c的元素:" + Arrays.toString(c));//3,4,5,6,0,0
        Arrays.fill(c, 2, 4, 1);//将c中第3个到第5个元素(不包含)赋值为1
        System.out.println("c的元素:" + Arrays.toString(c));//3,4,1,1,0,0
        Arrays.sort(c);
        System.out.println("c的元素:" + Arrays.toString(c));//0,0,1,1,3,4
    }
}

接下来,给出两个数组实际应用场景的示例。

数字转化为人民币大写(简易版) 五子棋游戏实现(简易版)

数字转化为人民币大写程序中,利用了一维数组表示大写及单位;五子棋游戏中,利用了二维数组表示棋盘。从程序中可看到throws Exception表示不处理任何异常,将在后续的篇章中继续讲解。

  分类: Java   好文要顶 关注我 收藏该文  Miracle He
关注 - 2
粉丝 - 159     +加关注 2 0       « 上一篇:Java学习之旅基础知识篇:数据类型及流程控制
» 下一篇:Java学习之旅基础知识篇:面向对象之封装、继承及多态 posted @ 2012-10-22 21:50 Miracle He 阅读(6396) 评论(2) 编辑 收藏  
评论列表      #1楼2012-10-22 22:46 dataexcel   谢谢楼主分享。http://www.downge.com 支持(0)反对(0)    #2楼2016-04-22 01:03 倔强的鸭子   不错 支持(0)反对(0)     刷新评论刷新页面返回顶部 注册用户登录后才能发表评论,请 登录 或 注册,访问网站首页。   【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
【活动】优达学城正式发布“无人驾驶车工程师”课程
【推荐】移动直播百强八成都在用融云即时通讯云
【推荐】别再闷头写代码!找对工具,事半功倍,全能开发工具包用起来
【福利】网易云信1周年接入开发者突破10万,送红包活动火热开展中   <iframe id="aswift_0" name="aswift_0" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" width="300" height="250"></iframe> 最新IT新闻:
· 途家创始人发内部信宣布并购携程、去哪儿公寓民宿业务
· 传谷歌签约CBS 将在明年第一季度推出网络电视服务
· iPhone 6被黑遭锁定勒索,黑客却说没动数据不是犯罪
· 神州优车突然做电商卖车,CEO是这样解释的
· 消费者市场触天花板 通讯巨头Line进军企业通讯领域
» 更多新闻... 最新知识库文章:
· 陈皓:什么是工程师文化?
· 没那么难,谈CSS的设计模式
· 程序猿媳妇儿注意事项
· 可是姑娘,你为什么要编程呢?
· 知其所以然(以算法学习为例) » 更多知识库文章...  

公告

昵称:Miracle He
园龄:7年6个月
粉丝:159
关注:2 +加关注
< 2012年10月 >
30 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 1 2 3
4 5 6 7 8 9 10

搜索

   

常用链接

  • 我的随笔
  • 我的评论
  • 我的参与
  • 最新评论
  • 我的标签

最新随笔

  • 1. 进入名企必读的.NET面试题
  • 2. Javascript学习之旅系列
  • 3. 面向对象的设计模式系列
  • 4. ASP.NET MVC架构与实战系列
  • 5. Java学习之旅系列
  • 6. Java学习之旅基础知识篇:面向对象之封装、继承及多态
  • 7. Java学习之旅基础知识篇:数组及引用类型内存分配
  • 8. Java学习之旅基础知识篇:数据类型及流程控制
  • 9. Java学习之旅开篇:运行机制及环境搭建
  • 10. ASP.NET MVC架构与实战系列之四:MVC实例演练
 

随笔分类(41)

  • .Net&C#(10)
  • Android开发
  • Asp.Net(4)
  • Design Patterns & Design Priciples(4)
  • Java(5)
  • Javascript&JQuery(13)
  • MVC(5)

随笔档案(42)

  • 2014年3月 (1)
  • 2013年3月 (1)
  • 2013年2月 (4)
  • 2012年10月 (4)
  • 2012年9月 (2)
  • 2012年5月 (5)
  • 2012年4月 (3)
  • 2012年3月 (2)
  • 2012年2月 (1)
  • 2012年1月 (4)
  • 2011年12月 (6)
  • 2011年11月 (9)

积分与排名

  • 积分 - 59873
  • 排名 - 4009

最新评论

  • 1. Re:ASP.NET MVC架构与实战系列之三:MVC控件解析
  • ASP.NET MVC下的控件,只用过ComponenetOne,这个控件集包含的控件还是比较多的
  • --zenmshuo
  • 2. Re:ASP.NET MVC架构与实战系列之一:理解MVC底层运行机制
  • 大神,问下为什么360浏览器,三个电脑中,其中两个访问的页面都相同,而其中就有一个访问的页面不同,其中三台电脑的浏览器版本一样,都是Windows操作系统,为什么会出现这总情况呢?
  • --4488
  • 3. Re:谈谈C#的异常处理机制


  • WebAPI的也举个例子
  • --maanshancss
  • 4. Re:Java学习之旅系列
  • Java学习之旅基础知识篇(5):集合与泛型 Java学习之旅基础知识篇(6):文件操作及异常处理 Java学习之旅基础知识篇(7):图形编程(AWT&Swing)高级技术篇 ......
  • --mysoftroad
  • 5. Re:Javascript基础知识篇(4): 面向对象之继承
  • Ext的内容
  • --夏天的知了

阅读排行榜

  • 1. ASP.NET MVC架构与实战系列之二:理解MVC路由配置(9085)
  • 2. ASP.NET MVC架构与实战系列之一:理解MVC底层运行机制(7964)
  • 3. ASP.NET MVC架构与实战系列之三:MVC控件解析(6547)
  • 4. Java学习之旅基础知识篇:数组及引用类型内存分配(6397)
  • 5. Java学习之旅基础知识篇:面向对象之封装、继承及多态(6320)

评论排行榜

  • 1. 谈谈web应用程序分层(多层)的优势(17)
  • 2. Javascript实战应用篇(2):继续完善网页文本框系列(增加水印和提示)(10)
  • 3. Javascript实战应用篇(1):让你的网页文本框增加光晕效果(类似QQ2012)(9)
  • 4. Javascript高级技术篇(1):搭建JS框架类库(8)
  • 5. 面向对象的设计模式系列之三:抽象工厂模式(AbstractFactory)(7)

推荐排行榜

  • 1. ASP.NET MVC架构与实战系列之一:理解MVC底层运行机制(15)
  • 2. Javascript基础知识篇(1): 初识Javascript(8)
  • 3. Javascript实战应用篇(2):继续完善网页文本框系列(增加水印和提示)(6)
  • 4. Javascript高级技术篇(1):搭建JS框架类库(5)
  • 5. ASP.NET MVC架构与实战系列之二:理解MVC路由配置(5)
    Copyright ©2016 Miracle He

相关文章

    暂无相关文章
相关栏目:

用户点评