Java程序设计(Java9版):第4章 简单复合类型

第4章 简单复合类型

4.1 数组

在C语言中,数据类型除了基本数据类型之外,还存在着大量复合数据类型。数组就是一类最简单且非常重要的复合数据类型,数组是具有相同类型变量的顺序存储的集合。几乎所有的程序设计语言都把数组设定为固有的类型,同样Java语言也有数组类型。与C语言一致,Java语言的数组也是通过数组名和下标来表示每个数组单元(也就是一个变量),数组下标从0开始。

在Java语言中,创建基本数据类型的变量与C语言格式一致,直接使用“数据类型 变量名”格式即可,比如“int i”即定义了一个int型变量i。由于创建复合数据类型的变量,相对创建基本数据类型的变量要复杂、计算机系统消耗要大,所以Java语言在创建复合数据类型的变量时要分两步完成。第一步先通过“数据类型 变量名”声明变量,只在栈内存中为变量名分配一个很小的空间,但是并没有开辟具体的数据空间;比如某一复合数据类型声明了变量a,如图2.44所示。第二步,通过new关键字在堆内存中开辟一个复合“数据类型”大小的存储空间,用于存储具体是数据实体;然后将该存储空间的地址赋值到变量名的栈存储空间内。

4.1.1 数组定义

数组是复合数据类型,所以分为数组变量声明与数组创建两步完成。

(1)声明数组名

一维数组的声明格式如下: 元素类型[] 数组名; 其中,“元素类型[]”是数组类型,比如“int[]”就是整数数组类型,这是与C语言不一样的;“数组名”就是数组类型定义的变量,与“数据类型 变量名”声明格式一致,而C语言的数组名则是常量。比如声明“int[]”型数组a,语句如下: int[] a; 实际上还有有一种声明数组的方法,就是大家熟悉的C语言格式,如下: 元素类型 数组名[]; Java保留此格式,可以使用但不建议使用,C#等语言不再支持这种古老格式,只支持第一种格式。

(2)开辟元素空间

通过new操作符在内存中为数组申请存储空间,格式如下:

数组名=new 元素类型[长度];

new是Java关键字,作用类似与C语言的动态存储分配函数(比如malloc函数),可以从内存中为数组申请“长度”个存储空间,然后将这些存储空间的首地址赋值给数组名。注意,这里的地址不同于C语言的地址或指针,Java语言没有指针。 比如开辟5个int型元素类型的空间,如图2.45所示。

a=new int[5];

实际上,可以将数组声明和开辟空间两步合并为:

元素类型[] 数组名=new 元素类型[长度];

此外,Java语言允许使用int型变量来指定数组的长度,C语言是不允许的。 比如:

int size=5;
int a=new int[size];

如果我们再声明一个整型数组b,并将数组a赋值给b,代码如下:

int[] b=a;

如图2.46所示,数组b和数组a共享同一个数组实体。数组实体相当于一个人,而数组名a相当于这个人的姓名,数组名b相当于这个人的别名,两个名字均指向同一个实体人。数据实体只有一个,而该数据实体的名字可以有多个,每个名字只是引用了数据实体。这就是Java语言中的复合数据类型的变量被称为引用变量的原因。

在Java语言,内存是可以分为栈内存和堆内存。栈内存,存储基本类型的数据和引用变量;堆内存存放复合数据类型的数据实体。数组是引用类型,所以数组名存储在栈内存中,而数组元素存储在堆内存中。

4.1.2 数组操作

(1)数组初始化

数组初始化就是为数组的元素分配内存空间,并为每个数组元素指定初始值。数组初始化有静态初始化和动态初始化两种方式。 静态初始化时只需指定每个数组元素的初始值,并由系统决定数组长度,格式如下: 元素类型[] 数组名={值1,值2,…,值n}; 比如:int[] a={1,2,3,4,5,6}; 动态初始化,即是new的工作过程,根据指定的数组长度开辟内存空间,并为每个元素分配初始值。其中,对数组元素赋初值,即是为每个数组单元指定默认值。整型的默认值是0,小数型默认值是0.0,char型默认值是’\u0000’,复合数据类型的初始值是null。

(2)length属性

与C语言的数组不同的是,Java数组提供了length属性,表示数组元素的个数。比如“int a=new int[size];”,a.length的值就是5。通过length属性可以安全访问数组,可以避免访问数组出现越界问题。

(3)访问数组元素

与C语言一致,Java数组下标从0开始。一维数组下标范围:0~数组名.length-1。通过具体的数组下标即可访问数组元素。

例4-1:遍历数组。遍历数组就是访问数组的每一个元素,这是数组最常用的操作,编写程序ArrayTest.java,代码如下。

jshell> int[] a=new int[10];
a ==> int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

jshell> for(int i=0;i<a.length;i++) //输出默认值
   ...>    System.out.print(a[i]+" ");
0 0 0 0 0 0 0 0 0 0 
jshell> for(int i=0;i<a.length;i++) //为每个元素赋值
   ...>    a[i]=i+1;

jshell> for(int i=0;i<a.length;i++)
   ...>    System.out.print(a[i]+" ");
1 2 3 4 5 6 7 8 9 10 
jshell> 

习惯上,人们也将定义数组后,第1次为数组元素显式赋值的过程称为数组初始化。

4.1.3 简单应用

例4-2:前面通过程序Fib.java求解Fibonacci数列过程中,存在一个问题,无法保存这个数列的每一项。可以通过一维数组来保存Fibonacci数列的每一项,编写程序如下。

jshell> int n=12;
n ==> 12

jshell> int[] fib=new int[n];
fib ==> int[12] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

jshell> fib[0]=fib[1]=1;
$13 ==> 1

jshell> for(int i=2;i<fib.length;i++)
   ...>     fib[i]=fib[i-1]+fib[i-2];  //第i项等于前两项之和

jshell> for(int i=0;i<fib.length;i++)
   ...>     System.out.print(fib[i]+" ");
1 1 2 3 5 8 13 21 34 55 89 144 
jshell> 

4.1.4 二维数组

二维数组是一维数组的扩展,可以把二维数组看作特殊的一维数组,其每一个元素是一个一维数组。一维数组和二维数组使用较多,多维数组很少使用,所只讲解到二维数组。二维数组定义格式如下:

数组元素类型[][] 数组名=new 数组元素类型[长度1][长度2];

例4-3:用二维数组很容易解决杨辉三角问题。杨辉三角如下所示:

1
1   1
1   2   1
1   3   3   1
1   4   6   4  1
1   5  10  10  5   1
..   ..   ..   ..  ..   ..  ..

杨辉三角是个二维图形,可以使用二维数组存储。很容易发现杨辉三角的规则:第一列和斜边都为1;其他元素值等于上一行的同列元素与前一列的元素之和,用数组表示为a[i][j]=a[i-1][j]+a[i-1][j-1]。按照这个思路编写程序Young.java:首先定义一个10行10列的二维数组,然后对第1列和对角线赋值1,再按a[i][j]=a[i-1][j]+a[i-1][j-1]公式对其他元素进行赋值。具体代码如下。

jshell> int n=10
n ==> 10

jshell> int[][] y=new int[n][n];//数组维数可以是变量
y ==> int[10][] { int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0,  ... 0, 0, 0, 0, 0, 0, 0, 0 } }

jshell> for(int i=0;i<n;i++) 
   ...>    y[i][0]=y[i][i]=1;//初始化第1列和对角线

jshell> for(int i=2;i<n;i++)
   ...>    for(int j=1;j<i;j++)
   ...>        y[i][j]=y[i-1][j-1]+y[i-1][j];

jshell> for(int i=0;i<n;i++){
   ...>    for(int j=0;j<=i;j++)
   ...>        System.out.printf("%5d",y[i][j]);
   ...>    System.out.println();
   ...> }
    1
    1    1
    1    2    1
    1    3    3    1
    1    4    6    4    1
    1    5   10   10    5    1
    1    6   15   20   15    6    1
    1    7   21   35   35   21    7    1
    1    8   28   56   70   56   28    8    1
    1    9   36   84  126  126   84   36    9    1

jshell> 

4.1.5 Java5的foreach

在VB语言中有foreach循环语句,方便对数据集合遍历,C#语言也继承了foreach循环语句。Java 5增加了for循环功能扩展,实现了foreach循环功能,格式如下:

for( 元素类型  元素变量名:数组名或集合名){
    循环体语句;
}

例4-4:比较普通的for循环与foreach循环。

jshell> String[] str={"Java","C#","PHP","C++"};//字符串数组
str ==> String[4] { "Java", "C#", "PHP", "C++" }

jshell> for(String s:str)
   ...>    System.out.print(s+" ");
Java C# PHP C++ 
jshell> for(int i=0;i<str.length;i++)
   ...>    System.out.print(str[i]+" ");
Java C# PHP C++ 
jshell> 

显然遍历数组时foreach循环更方便。

4.1.6 Java8 增强型工具类Arrays

4.2 字符串

4.2.1 字符串变量

字符串是一类非常重要的数据。C语言是通过字符数组来存储字符串,并以“\0”作为字符串结束标志;对字符串的操作也是通过字符数组或字符指针来实现的;C语言有字符串常量的概念,字符串常量用一对双引号(”“)括起来,但是没有字符串变量的概念。可见C语言没有真正意义上的字符串数据类型,而Java语言中的字符串已经是一个完备的数据类型。Java提供了String类型来处理字符串数据,同C语言一致,字符串常量用一对双引号(”“)括起来。 本节简单认识一下String类型,关于具体的String类型将在第8章详细介绍。 例36:测试字符串类型数据简单用法。先定义一个字符串常量”Hello”,然后赋值给字符串变量s;字符串可以通过“+”运算实现字符串连接,代码如下。

jshell>  String s="Hello";  //定义一个字符串变量
s ==> "Hello"

jshell> System.out.println(s)
Hello

jshell> System.out.printf("%s,World!\n",s);
Hello,World!
$26 ==> java.io.PrintStream@3e6fa38a

jshell> System.out.println(s+",world!")
Hello,world!

jshell> 

4.2.2 遍历字符串

jshell>  String s="Hello";  //定义一个字符串变量
s ==> "Hello"

jshell> for(int i=0;i<s.length();i++)
   ...>    System.out.println(s.charAt(i))
H
e
l
l
o

jshell> 

4.3枚举

C语言中具有枚举类型,Java语言一开始不具有枚举类型,直到Java 5才重新引入枚举类型enum。

4.3.1 枚举定义

所谓“枚举”即是这种类型的变量值只能是若干指定的值之一。枚举类型通过enum关键字定义,格式如下:

enum 枚举名{ 
   枚举常量列表
}

其中,枚举常量名要符合标识符规定,与一般常量不同的是可以将枚举常量名小写。枚举常量之间用逗号分割,例如:

enum Season{//季节
        spring,summer,autumn,winter
}

Season就是一个枚举类型,它有4个常量值,可以通过“枚举类型名.枚举常量名”形式访问枚举常量。 声明一个枚举类型的变量格式与一般声明变量格式相同,例如声明一个上面定义的Season枚举型变量:

Season season;

枚举变量的值只能是枚举常量,比如:

season=Seaon.spring;

可以将一个枚举类型定义在Java源文件中,编译后得到字节码文件。

4.3.2枚举与for循环

枚举类型有一个values()方法,可以返回一个枚举常量数组。Java 5之后,可以使用for遍历枚举数据,语法上与增强的for循环变量数组一致。

例37:通过下面程序EnumTest.java测试枚举类型简单用法,代码如下。

jshell> enum Season{//季节
   ...>      spring,summer,autumn,winter
   ...> }
|  created enum Season

jshell> Season season=Season.spring;//定义一个枚举变量,取值只能是枚举常量之一
season ==> spring

jshell> System.out.println(season);
spring

jshell> for(Season s:Season.values())//遍历输出枚举类型的常量
   ...>    System.out.println(s);
spring
summer
autumn
winter

jshell>

4.3.3枚举与switch

从Java 5开始,允许switch语句的表达式是枚举类型。 例38:下面程序定义了一个Color枚举类型,然后测试switch语句对枚举类型的支持,代码如下。

jshell> enum Color{//颜色
   ...>     red,yellow,blue,white,black
   ...> }
|  created enum Color

jshell> Color c=Color.blue;
c ==> blue

jshell> switch(c){
   ...>      case red:
   ...>           System.out.println("红色");
   ...>           break;
   ...>      case yellow:
   ...>           System.out.println("黄色");
   ...>           break;
   ...>      case blue:
   ...>           System.out.println("蓝色");
   ...>           break;
   ...>      case white:
   ...>           System.out.println("白色");
   ...>           break;
   ...>      case black:
   ...>           System.out.println("黑色");
   ...>           break;
   ...>      default: 
   ...>           System.out.println("其他颜色");
   ...> }
蓝色

jshell> 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏difcareer的技术笔记

GNU C++的符号改编机制介绍[转]前言正文

众所周知,强大的C++相较于C增添了许多功能。这其中就包括类、命名空间和重载这些特性。 对于类来说,不同类中可以定义名字相同的函数和变量,彼此不会相互干扰。命...

644
来自专栏null的专栏

python基础知识——字符串

1、字符串的格式化 python将若干值插入到带有“%”标记的字符串中,实现动态地输出字符串。 格式: "%s" % str "%s%s" % (str_1, ...

3054
来自专栏个人随笔

房上的猫:数组

一.数组:  1.定义:   (1)数组就是一个变量,用于将相同数据类型的数据储存在内存中   (2)数组中的每一个数据元素都属于统一数据类型  2.基本要素:...

3419
来自专栏TungHsu

这或许是对小白最友好的python入门了吧——15,嵌套

有些时候我们的数据可能会很复杂,单独的字典列表等可能无法满足我们的需求,这个时候我们就需要将字典列表等融合在一起,这个叫做嵌套。 (一)字典列表 我们上一期说的...

3364
来自专栏流媒体

C++类型转换

允许将任何指针类型转换为其它的指针类型;听起来很强大,但是也很不靠谱。它主要用于将一种数据类型从一种类型转换为另一种类型。它可以将一个指针转换成一个整数,也可以...

582
来自专栏机器学习实践二三事

Python基础----数据变量和变量

整数 Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1,100,-8080,0,等等。 计算机由于使用...

1865
来自专栏有趣的Python

6-Java基础语法-数组之一维数组

局部变量和数组的默认值问题: 局部变量是没有默认值的,如果没有初始化,是内存中的随机值。而数组是有默认值的0的,因为数组本身是对象。

953
来自专栏吾爱乐享

java之学习math类的方法概述

1042
来自专栏Golang语言社区

Golang语言社区--【基础知识】范围规则

在任何编程程序的作用域,其中一个定义的变量可以有它的存在,超出该变量的区域就不能访问。有三个地方变量可以在Go编程语言声明如下: 内部函数或这就是所谓的局部变量...

31514
来自专栏机器学习和数学

[编程经验] Python正则表达式

Hello,大家好。又见面了,今天给大家介绍一下,正则表达式在Python中是如何使用的。这样说的原因是正则表达式并不是Python所独有的,而是自成体系,在很...

2494

扫码关注云+社区