`

理解 java 数组(转载)

阅读更多

本文转载自:http://www.blogjava.net/flysky19/articles/92763.html?opt=admin

 

参考资料:
1.《java jdk5.0 学习笔记》良葛格 第五章数组
2.如何理解数组的length?
http://blog.csdn.net/treeroot/archive/2005/01/22/264001.aspx
3.关于java数组的深度思考
http://dev.csdn.net/author/DeepNightTwo/afb7e220bdf5423ba656f84b6a183b44.html


一.为什么需要数组?(《java jdk5.0 学习笔记》良葛格)
例如,现在要整理全班的Java小考成绩,您希望写个小程序,全班共有40名学生,所以必须有40个变量来存储学生的成绩。现在问题来了,根据第3章学过的变量定义方式,难道要定义40个名称不同的变量来存储学生的成绩数据吗?

当然不必这么麻烦,Java提供“数组”(Array)让您可以定义一个以“索引”(Index)作为识别的数据结构。在Java中,可以这么定义一个数组并初始数组内容:

int[] score = {90, 85, 55, 94, 77};

二.什么是数组?
java语言中,数组是一种最简单的复合数据类型。数组是有序数据的集合,数组中的每个元素具有相同的数据类型,可以用一个统一的数组名和下标来唯一地确定数组中的元素。数组有一维数组和多维数组。
(http://www.linux8.net/html/java/2006-3/29/21_59_23_560.html)

array的定义和使用:使用“[]”做为索引运算符(indexing operator).(《TIJ》)

三.java中数组到底是什么?

1)不管在其他语言中是什么,数组在Java中可得看作一个对象,它有一些值得探讨的特性。
(《java jdk5.0 学习笔记》良葛格)

这就意味着与C++中的数组的根本不同,相反,Java中的数组与C++中的STL或Java中的容器类反而更相像一些(只是作为对象,它的方法要比STL中的容器类或者Collection类少很多)。

Java中的数组其实是一个对象,但是确实是一个特殊的对象,实在是太特殊了,以致我们都不好把它多做对象处理。

刚刚开始接触java数组的人都会听到一句类似的话:java是纯面向对象的语言,他的数组也是一个对象。
于是乎,我就按照一个对象的方式来使用数组,心安理得。直到我接触到C的数组后,才发现将数组作为一个类来使用在实现上是多么的“不自然”。
首先我们看一下表面现象,数组创建的时候采用的是如下语句:
MyClass[] arr = new MyClass[9];
而普通类采用的是如下语句:
MyClass obj = new MyClass();
就是说,创建数组的时候不使用小括号传参。使得数组和普通类看起来就有很多不同,因为小括号里的参数是传递给构造方法的,进而让人感觉数组类是没有构造方法的。
(http://dev.csdn.net/author/DeepNightTwo/afb7e220bdf5423ba656f84b6a183b44.html)

2)java中数组是对象的依据:

a)来源:(http://blog.csdn.net/treeroot/archive/2005/01/22/264001.aspx)

我们确定数组的父类是Object,
  new Object[0].getClass().getSuperClass()  是Object.class

数组没有对应的类文件,String对应String.class.但是数组却没有,而且他们的
  类名字很古怪,可以这样获得 new int[2].getClass().getName();
  这是和其他对象最大的不同点,因为数组类是在运行时生成的。

java.lang.reflect.Array是final的,所以数组肯定不是它的子类
  这个类用来动态生成数组或者操作数组(获得长度等).



b)来源:(http://dev.csdn.net/author/DeepNightTwo/afb7e220bdf5423ba656f84b6a183b44.html)

再往深了想,还有很多让人感觉不自然的东西。可以肯定的是,java确实将数组作为了一个类来处理。还是用上面的例子说明:
可以通过以下方法得到MyClass[]的Class实例:arr.getClass()或MyClass[].class。这样,我就可以向数组类里面“窥探”了。
Class clazz = MyClass[].class;
System.out.println(clazz.getConstructors().length);
打印出来的结果是0;证明数组类确实没有构造方法。


再看看数组类的“庐山真面目”:
System.out.println(clazz);
输出是:
[Larraytest.MyClass

对Java Class文件结构稍有了结就知道,这个字符串的意思就是一个元素类型为arraytest.MyClass的一维数组。也就是说,数组类型不是和普通类 一样,以一个全限定路径名+类名来作为自己的唯一标示的,而是以[+一个或者多个L+数组元素类全限定路径+类来最为唯一标示的。这个()也是数组和普通 类的区别。而这个区别似乎在某种程度上说明数组和普通java类在实现上有很大区别。因为java虚拟机(java指令集)在处理数组类和普通类的时候, 肯定会做出区分。我猜想,可能会有专门的java虚拟机指令来处理数组。

分析到这里,我基本上可以肯定:java对数组对象化的操作的支持是指令级的,也就是说java虚拟机有专门针对数组的指令。数组的Class类实例是java虚拟机动态创建动态加载的,其结构与普通java类的Class实例有一些不同。

JDK API中有一个java.lang.reflect.Array类,这个类提供了很多方法(绝大多数是native方法,这在另一个方面证明了java对数组的支持是专用指令支持的,否则用本地方法干嘛^_^),用来弥补我们对数组操作的局限性。
下面这句话用来创建一个一维的、长度为10的、类型为arraytest.MyClass的数组:
arraytest.MyClass[] arr = (arraytest.MyClass[]) Array.newInstance(arraytest.MyClass, 10);

下面这句话用来创建一个二维的、3乘5的、类型为arraytest.MyClass的数组:
int[] arrModel = new int[]{3,5};
Object arrObj = Array.newInstance(Sub.class, arrModel);
当然你可以用一个数组的引用指向上面的二维数组,这里我们用一个Object的引用指向他。
使用的时候,我们也是可以利用Array类提供的方法来实现:

System.out.println(Array.getLength(arrObj);//第一维长度为3
System.out.println(Array.getLength(Array.get(arrObj, 2)));//第二维长度为5,这里如果写3,就会得到你意想之中的java.lang.ArrayIndexOutOfBoundsException

打印结果是如我所想的:
3
5

对于数组的Class类实例,还有一些奇怪的现象:
在 运行代码 java.lang.reflect.Field fieldarr = clazz.getField("length");的时候,会抛出异常:java.lang.NoSuchFieldException: length,这似乎在说数组类没有length这个域,而这个域其实是我们用的最多的一个(也就是说这个域是肯定存在的)。我想关于数组的Class类 实例、数组的实现等,还有很多“猫腻”在里面。

顺便说一句,java数组最多只能是255维的。这个让人看到了C的影子,嘿嘿。

“Java把数组当作一个java类来处理”说起来容易,用起来自然,但是细细想来,还是有很多不简单的地方呀。



c)来源:《java jdk5.0 学习笔记》良葛格 第五章数组

从对数组对象的进一步探讨,可以稍微了解Java对对象处理的一些方法。首先来看看一维数组的引用名称的定义:

int[] arr = null;

在 这个定义中,arr表示一个可以参考引用自一维数组对象的变量名称,但是目前将这个名称参考引用自null,表示还没有指定这个名称参考引用自实际的对 象。在Java中,=运算用于基本数据类型时,是将值复制给变量,但当它用于对象时,则是将对象指定给参考引用名称来参考引用。也可以将同一个对象指定给 两个参考引用名称,当对象的值由其中一个参考引用名称进行操作而变更时,另一个参考引用名称所参考引用到的值也会变动。下面来看看范例5.8的示范。

ü 范例5.8  AdvancedArray.java

public class AdvancedArray {

    public static void main(String[] args) {

        int[] arr1 = {1, 2, 3, 4, 5};

        int[] tmp1 = arr1;

        int[] tmp2 = arr1;

 

        System.out.print("通过tmp1取出数组值:");

        for(int i = 0; i < tmp1.length; i++)

            System.out.print(tmp1[i] + " ");

 

        System.out.print("\n通过tmp2取出数组值:");

        for(int i = 0; i < tmp2.length; i++)

            System.out.print(tmp2[i] + " ");

 

        tmp1[2] = 9;

        System.out.print("\n\n通过tmp1取出数组值:");

        for(int i = 0; i < tmp1.length; i++)

            System.out.print(tmp1[i] + " ");

 

        System.out.print("\n通过tmp2取出数组值:");

        for(int i = 0; i < tmp2.length; i++)

            System.out.print(tmp2[i] + " ");

        System.out.println();

    }

}

执行结果:

 

通过tmp1取出数组值:1 2 3 4 5

通过tmp2取出数组值:1 2 3 4 5

 

通过tmp1取出数组值:1 2 9 4 5

通过tmp2取出数组值:1 2 9 4 5

 

在 这个范例中,通过tmp1名称改变了索引2的元素值,由于tmp2也引用自同一数组对象,所以tmp2取出索引2的元素值是改变后的值。事实上在范例 5.8中,有三个引用名称引用自同一个数组对象,也就是arr1、tmp1与tmp2,所以,如果取出arr1索引2的元素,元素值也会是9。

 

了解到在Java中数组是一个对象,而使用=指定时是将对象指定给数组名来引用,而不是将数组进行复制。如果想将整个数组的值复制给另一个数组该如何作呢?可以使用循环,将整个数组的元素值遍历一遍,并指定给另一个数组相对应的索引位置。范例5.10示范了进行数组复制的方法。

Ü范例5.10  ArrayCopy.java

public class ArrayCopy {

    public static void main(String[] args) {

        int[] arr1 = {1, 2, 3, 4, 5};

        int[] arr2 = new int[5];

 

        for(int i = 0; i < arr1.length; i++)

            arr2[i] = arr1[i];

 

        for(int i = 0; i < arr2.length; i++)

            System.out.print(arr2[i] + " ");

        System.out.println();

    }

}

执行结果:

 

1 2 3 4 5

另一个进行数组复制的方法是使用System类提供的arraycopy()方法。其语法如下:

System.arraycopy(来源, 起始索引, 目的, 起始索引, 复制长度);

范例5.11改写了范例5.10,使用System.arraycopy()进行数组复制,执行结果与范例5.10是相同的。

Ü范例5.11  ArrayCopy2.java

public class ArrayCopy2 {

    public static void main(String[] args) {

        int[] arr1 = {1, 2, 3, 4, 5};

        int[] arr2 = new int[5];

 

        System.arraycopy(arr1, 0, arr2, 0, arr1.length);

 

        for(int i = 0; i < arr2.length; i++)

            System.out.print(arr2[i] + " ");

        System.out.println();

    }

}


四、 Java中的数组作为对象带来的好处
1)越界检查

2)length field:与传统的C++中的数组相比,length字段可以方便的得到数组的大小;但要注意,仅仅可以得到数组的大小,不能得到数组中实际包含多少个元素,因为length 只会告诉我们最多可将多少元素置入那个数组。

3) 初始化:对象数组在创建之初会自动初始化成null,由原始数据类型构成的数组会自动初始化成零(针对数值类型),(Char)0 (针对字符类型)或者false (针对布尔类型)。

4) 数组作为返回值:首先,既然数组是对象,那么就可以把这个对象作为返回值;而且,不必担心那个数组的是否可用只要需要它就会自动存在而且垃圾收集器会在我们完成后自动将其清除

分享到:
评论

相关推荐

    求数组的子数组之和的最大值,转载自:黑梦楠的日志

    在编程语言如Java、Python、C++等中,都可以轻松实现这两种方法。例如,以下是一个使用Python的Kadane's Algorithm实现: ```python def maxSubArray(nums): cur_sum = max_sum = nums[0] for num in nums[1:]: ...

    Java版数据结构课件

    【Java版数据结构课件】...总的来说,这门Java版数据结构课件涵盖了数组的定义、存储方式以及特殊矩阵和广义表的处理,这些都是计算机科学基础课程中的核心内容,对于Java程序员来说,理解和掌握这些知识点是必备技能。

    Java语言基础的理解与笔记

    主要简述Java基础,包括概述,基础语法,流程控制语句,数组,方法和值传递 适合刚开始的新手参考 主要可以使用在计算机刚入门的小伙伴或者回来看一看复习一下简单的基础的 ① 凡本网站注明“来源:本网站、子网站或...

    《Java 程序设计》模拟试题(转载).docx

    Java是一种广泛使用的面向对象的编程语言,其特点包括平台独立性、安全性以及强大的类库支持。在Java程序设计中,我们需要了解几个核心概念和规则,这些在提供的模拟...理解和掌握这些内容对于学习Java编程至关重要。

    Java字节码(.class文件)格式详解((转载)

    Java字节码是Java程序编译后的产物,它以`.class`文件的形式存在,是Java虚拟机(JVM)能够理解和执行的二进制代码。本文将深入解析Java字节码的格式,帮助你理解其背后的运行机制。 1. **Java字节码结构** Java...

    java编程思想习题及答案

    这份资料可能是从www.pigkrtv.com等网站转载而来,旨在帮助学习者深化对Java编程语言的理解,提高编程技能。 在Java编程学习过程中,掌握基本概念、语法以及解决问题的能力至关重要。这份习题集涵盖了以下几个关键...

    抽奖软件java

    抽奖软件在IT行业中是一种常见的应用,它涉及到许多基础和进阶的编程概念。在这个Java教学案例中,...通过学习和理解这个案例,开发者不仅可以掌握GUI编程,还能深入理解线程、流、数据结构以及异常处理等核心概念。

    网上转载JAVA面试基本大全

    这些知识点构成了Java开发者的基础技能,理解和掌握它们对于任何Java面试都至关重要。面试时,面试官可能会深入探讨这些概念的实际应用,要求编写代码示例或者解决实际问题。因此,熟悉这些基础并能灵活运用是成为...

    Java程序员面试的试题集(1_122)帮助初学者的技术问题(转载)

    ### Java程序员面试知识点详解 ...综上所述,理解Java的基本概念、面向对象的特征、异常处理机制、集合框架以及企业级开发技术,对于Java程序员而言至关重要,特别是在准备面试或深入学习Java开发的过程中。

    --JTable的分页显示

    这篇转载的博客文章探讨了如何在`JTable`中实现分页功能。 首先,理解`JTable`的基本结构至关重要。`JTable`是基于`DefaultTableModel`的,它管理表格的数据、列名和行数。为了实现分页,我们需要创建一个自定义的`...

    仿ipone滚轮搭配Dialog使用实例转载

    首先,我们要理解滚轮控件(Wheel View)的工作原理。滚轮是一种可滚动的选择器,用户可以通过上下滚动来选择其中的某一项。在iOS系统中,滚轮常用于日期选择、时间选择等场景。在Android中,我们可以自定义一个滚轮...

    c#语言版数据结构(转载)

    在数据结构领域,已有多种编程语言的相关教材,包括Pascal、C、C++和Java等,这些教材覆盖了广泛的数据结构理论和技术。然而,随着微软推出的C#语言及其.NET Framework的不断发展,这一领域的需求也在逐渐变化。 **...

    Objective-C 入门手册 中文版(Objective-C Beginner's Guide)

    - **Protocols**:类似Java和C#的接口,定义一组方法签名,类可以选择实现这些协议。 3. **内存管理**: - **Retain and Release**:Objective-C使用引用计数来管理内存,`retain`增加对象引用计数,`release`...

Global site tag (gtag.js) - Google Analytics