IDEA的概述和安装
IDEA 概述
IDEA 全称 IntelliJ IDEA , 是用于 Java 语言开发的集成环境,它是业界公认的目前用于 Java 程序开发最好的工具。
集成环境 :把代码编写,编译,执行,调试等多种功能综合到一起的开发工具。
(图1
)
IDEA中项目结构
project(项目、工程)
module(模块)
package(包)
class(类)
层级关系:project - module - package - class
IDEA常用快捷键
快捷键
作用
psvm / main + 回车
生成main方法
sout + 回车
生成输出语句
Alt + 回车
代码修正提示
Ctrl + Alt + L
格式化代码
Ctrl + /
批量加入单行注释,再按一次就是取消
Ctrl + shift + /
批量加入多行注释,再按一次就是取消
alt + 1
打开/隐藏工程目录结构
alt + 4
打开/隐藏控制台
Ctrl + d
向下复制一行
Ctrl + x
剪切当前行
Ctrl + y
删除当前行
Ctrl+ z
撤销
Ctrl + shift + z
重做(取消撤销)
Ctrl + n
查找类
Ctrl + shift + n
查找文件
Alt + shift + ↑
上移当前行
Alt + shift + ↓
下移当前行
fori / 数组名字.fori
快捷生成for循环
Ctrl + n
搜索类
选中变量, shift+f6
将所有叫这个名字的变量改名
Ctrl + alt + v / 方法.var
生成方法
Ctrl + alt + m
抽取方法
选中代码块使用Ctrl + alt + t
try …catch…
tab → tab → enter
构造方法什么都不选
shift按住不送 + 下键
构造方法/set/get方法全选
Ctrl + b / ctrl + 鼠标左键
查看类的源码
Alt + 7
类的结构大纲
Ctrl + alt + 空格
补全 ArrayList<String>list = new ArrayList<>();
中的 ArrayList<>()
部分
Ctrl + f12
列出当前类的所有方法
ctrl + p
提示( )内参数的类型
shift + f6
更换包名
ctrl + shift + c
获得文件的全路径名
win + e
打开文件夹
win + r → services.msc
服务列表
alt + 鼠标左键, 竖着选
在IDEA中整列的编辑
选中 ctrl + f
进行词的替换
Ctrl + O
重写方法
Ctrl + y
删除一行
Ctrl + shift + f
搜索代码
shift + shift
搜素类
Shift + esc
搜索框
F9
debug测试时,进行放行
Ctrl + h
看某个类的实现类
Ctrl + shift + enter
快速补全
Crtl + F5
快速重启当前项目
Ctrl + E
打开最近编辑过的文件
Ctrl + i
类似于alt + enter, 实现接口的方法
选中接口的名字, ctrl + shift + t
创建测试的方法
选中类名单击右键,选择Diagrams,再选择Show Diagram…
查看类的关系
在[Show Diagram]的基础上,右键选择 Show Implementations
查看当前类的子类
在[Show Diagram]的基础上,右键选择 Show Parents
查看自己的父类
在[Show Diagram]的基础上,右键选择 Show Categories-Method
查看细节
在[Show Diagram]的基础上,右键选择 Layout
换个布局
在[Show Diagram]的基础上,右键选择 Jump to Source
查看源码
Ctrl + H
查看类的层次结构关系图
IDEA操作项目和模块
创建新模块
(图2
)
删除模块
Remove Module: 只是从列表中临时删除, 硬盘中还存在
(图3
)
导入模块
(图4
)
IDEA打开关闭项目-类名包名修改
打开项目
(图5
)
关闭项目
(图6
)
修改类名、包名
(图7
)
数组介绍
数组的定义
数组是 相同 类型数据的 有序 集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个 元素 可以通过一个索引(下标)来访问它们。数组的四个基本特点:
长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
其元素的类型必须是相同类型,不允许出现混合类型。
数组类型可以是任何数据类型,包括基本类型和引用类型。
数组变量属于引用类型,数组也是对象 。
建议
数组变量属于引用类型,数组也是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java 中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。
数组的定义格式
格式一:数据类型[ ] 变量名 (推荐使用这种方式)
范例:int[ ] array
格式二:数据类型 变量名[ ]
范例:int array[ ]
注意事项
(1) 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
(2) 声明一个数组的时候, 并没有数组真正被创建。
(3) 构造一个数组,必须指定长度。
1
2
3
//这里虽然是定义了一个数组,但也仅仅只是一个数组类型的[变量],变量没有进行初始化,就直接使用了,这就是错误原因。
int [] arr ;
System . out . println ( arr ); // 报错
创建基本类型一维数组
1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main ( String [] args ){
int [] s = null ; //声明数组
s = new int [ 10 ] ; //给数组分配空间
for ( int i = 0 ; i < 10 ; i ++ ){
s [ i ] = 2 * i + 1 ; //给数组元素赋值
System . out . println ( s [ i ] );
}
}
}
在 java 底层 int 也是对象,s = new int[10] 调用了 int 构造器,只是我们没必要去看
数组也是对象,数组中的元素相当于对象中的属性
(图8
)
数组在堆中,因数组中的元素相当于对象中的属性,所以在堆中创建一个对象,给这个对象分配 10 个空间,只要不给属性赋值,系统就会默认初始化值,所以,int[ ] 对象的属性都被系统设置默认初始化值为 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Man {
private int age ;
private int id ;
public Man ( int id , int age ){
super ();
this . age = age ;
this . id = id ;
}
}
public class AppMain {
public static void main ( String [] args ){
Man [] mans ; //声明引用类型数组;
mans = new Man [ 10 ] ; //给引用类型数组分配空间:
Man m1 = new Man ( 1 , 11 );
Man m2 = new Man ( 2 , 22 );
mans [ 0 ] = m1 ; //给引用类型数组元素赋值:
mans [ 1 ] = m2 ; //给引用类型数组元素赋值:
}
}
Mans 局部变量,放在 main 方法的栈帧中,m1 m2 就是正常的对象创建操作
(图9
)
数组的遍历, 长度用 ***.length
表示
1
2
3
4
5
6
7
8
for ( int i = 0 ; i < arr1 . length ; i ++ ){
arr1 [ i ] = i * 2 + 1 ;
}
for ( int i = 0 ; i < arr1 . length ; i ++ ){
//数组长度是5,索引范围:[0,Length-1]
System . out . println ( arr1 [ i ] );
}
数组初始化
Java 中的数组必须先初始化,然后才能使用
所谓初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
静态初始化
静态初始化:初始化时,就可以指定数组要存储的元素,系统还会自动计算出该数组长度
格式:数据类型[ ] 变量名 = new 数据类型[ ]{ 数据1,数据2,数据3,…};
范例:int [ ] arr = new int[ ] {1,2,3};
简化格式:数据类型[ ] 变量名 = { 数据1,数据2,数据3,…};
范例:int [ ] arr = {1,2,3};
1
2
int [] a = { 1 , 2 , 3 }; //静态初始化基本类型数组
Man [] mans = { new Man ( 1 , 1 ), new Man ( 2 , 2 )}; // 静态初始化引用类型数组 ;
Int[] a = {1, 2, 3} = new int[]{1, 2, 3}; //new int[ ]省略了, 我们只是简化了new int[ ]书写, ,它仍然存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main ( String [] args ){
//静态初始化需要在声明后直接初始化
Man [] mans = {
new Man ( 10 , "高小一" ),
new Man ( 20 , "高小二" ),
new Man ( 30 , "高小三" ),
new Man ( 40 , "高小四" ),
new Man ( 50 , "高小五" )
};
for ( int i = 0 ; i < mans . length ; i ++ ){
System . out . println ( mans [ i ] . getName ());
}
}
相当于 mans[0] = new Man(10, “高小一”);
操作的都是对象地址 , 也可以写成下边的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main ( String [] args ){
Man m = new Man ( 10 , "高小一" );
//静态初始化需要在声明后直接初始化
Man [] mans = {
m ,
new Man ( 20 , "高小二" ),
new Man ( 30 , "高小三" ),
new Man ( 40 , "高小四" ),
new Man ( 50 , "高小五" )
};
mans [ 0 ] = m ;
}
第二种遍历方式:增强 for 循环
1
2
3
4
5
6
7
8
for ( int i = 0 ; i < mans . length ; i ++ ){
System . out . println ( mans [ i ] . getName ());
}
//增强for循环
for ( Man man : mans ){
System . out . println ( man );
}
1
2
3
4
5
6
7
8
9
for ( int i = 0 ; i < mans . length ; i ++ ){
Man man = mans [ i ] ;
System . out . println ( man );
}
//增强for循环
for ( Man man : mans ){
System . out . println ( man );
}
动态初始化
动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
1
2
3
int [] a1 = new int [ 2 ] ; //动态初始化数组,先分配空间;
a1 [ 0 ] = 1 ; //给数组元素赋值;
a1 [ 1 ] = 2 ; // 给数组元素赋值 ;
数组内存地址值的含义
1
2
3
4
5
int [] arr = new int [ 5 ] ;
System . out . println ( arr ); //[I@10f87f48
byte [] bArr new = byte [ 3 ] ;
System . out . println ( bArr ); //[ B @b4c966a
[I@10f87f48
[ : 当前的空间是一个数组类型
@ : 分隔符
I : 当前数组容器中所存储的数据类型
10f87f48 : 十六进制内存地址
数组的默认初始化
数组是对象, 数组的元素相当于对象的属性, 遵守对象默认初始化的规则
数组是引用类型,他的元素相当于类的实例变量,因此数组已经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化
1
2
3
int a2 [] = new int [ 2 ] ; //默认值:0,0
boolean [] b = new boolean [ 2 ] ; //默认值:false,false
String [] s = new String [ 2 ] ; // 默认值 : null , null
两种初始化的区别对比
动态初始化:手动 指定数组长度 ,由系统给出默认初始化值。
静态初始化:手动 指定数组元素 ,系统会根据元素个数,计算出数组的长度
使用场景
动态初始化:只明确元素个数,不明确具体数值,推荐使用动态初始化
例:使用数组容器来存储键盘录入的5个整数
静态初始化:需求中已经明确了要操作的具体数据,直接静态初始化即可
例:将一班的学生成绩存入数组中 11, 22, 33
特点
数组是相同类型数据的有序集合。
数组的四个基本特点:
(1)长度是确定的。数组一旦被创建,它的大小就是不可以改变的
(2)其元素的类型
是相同类型,不允许出现混合类型。
(3)数组类型可以是任何数据类型,包括基本类型和引用类型。
(4)数组变量属于引用类型,数组也是对象。
案例
我在编程考试中,java 得分 60 分,python 得分 70 分,大数据 80 分,人工智能 90 分。请使用一个数组将这些分数进行存储。并分别使用三种初始化方式进行初始化。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public class Score {
private String name ;
private int fenShu ; //分数
public Score ( String name , int fenShu ){
this . name = name ;
this . fenShu = fenShu ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public int getFenShu () {
return fenShu ;
}
public void setFenShu ( int fenShu ) {
this . fenShu = fenShu ;
}
}
class Test {
public static void main ( String [] args ) {
/*
静态初始化,需要在声明后,直接初始化
*/
Score [] s = { new Score ( "java" , 60 ),
new Score ( "python" , 70 ),
new Score ( "大数据" , 80 ),
new Score ( "人工智能" , 90 )};
for ( int i = 0 ; i < s . length ; i ++ ){
System . out . println ( s [ i ] . getName ());
}
/*
动态初始化
*/
Score [] c = new Score [ 4 ] ;
c [ 0 ] = new Score ( "java" , 60 );
c [ 1 ] = new Score ( "python" , 70 );
c [ 2 ] = new Score ( "大数据" , 80 );
c [ 3 ] = new Score ( "人工智能" , 90 );
for ( int i = 0 ; i < c . length ; i ++ ){
System . out . println ( s [ i ] . getName () + "\t" + s [ i ] . getFenShu ());
}
/*
默认初始化
*/
Score [] score = new Score [ 4 ] ;
for ( int i = 0 ; i < score . length ; i ++ ){
System . out . println ( score [ i ] );
}
}
}
运行结果
java
python
大数据
人工智能
java 60
python 70
大数据 80
人工智能 90
null
null
null
null
数组内存图
Java中内存分配
栈内存:方法运行时,进入的内存,局部变量都存放于这块内存当中
堆内存:new 出来的内容都会进入堆内存,并且会存在地址值
方法区:字节码文件(.class 文件)加载时进入的内存
本地方法栈:调用操作系统相关资源
寄存器:交给 CPU 去使用
数组内存图
(图10
)
多数组内存图
(图11
)
数组的高级操作
数组的二分法查找
定义两个变量,表示要查找的范围。默认 min=0, max=最大索引
循环查找,但是 min <= max
计算出 mid 的值
判断 mid 位置的元素是否为要查找的元素,如果是直接返回对应索引
如果要查找的值在 mid 的左半边,那么 min 值不变,ma=mid-1, 继续下次循环查找
如果要查找的值在 mid 的右半边,那么 max 值不变,min=mid+1, 继续下次循环查找
当 min>max 时,表示要查找的元素在数组中不存在,返回 -1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private static int binarySearchForIndex ( int [] arr , int number ){
//1,定义查找的范围
int min = 0 ;
int max = arr . length - 1 ;
//2.循环查找 min<=max
while ( min <= max ){
//3.计算出中间位置mid
int mid = ( min + max ) >> 1 ;
//mid指向的元素 > number
if ( arr [ mid ] > number ){
//表示要查找的元素在左边,
max = mid - 1 ;
} else if ( arr [ mid ] < number ){
//mid指向的元素<number
//表示要查找的元素在右边。
min = mid + 1 ;
} else {
//mid指向的元素==number
return mid ;
}
}
//如果min大于了max就表示元素不存在,返回-1.
return - 1 ;
}
数组的冒泡排序
排序:将一组数据按照固定的规则进行排列
冒泡排序:相邻的数据两两比较,小的放前面,大的放后面
如果有 n 个数据进行排序, 总共需要比较 n-1 次
每一次比较完毕, 下一次的比较就会少一个数据参与
相邻的元素两两比较,大的放右边,小的放左边,找到最大值。
第一次循环结束,最大值已经找到,在数组的最右边。
下一次只要在剩余的元素找最大值就可以了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main ( String [] args ){
int [] arr = { 3 , 5 , 2 , 1 , 4 };
//1 2 3 4 5
//外层循环控制的是次数比数组的长度少一次
for ( int i = 0 ; i < arr . length - 1 ; i ++ ){
//内存循环就是实际循环比较的
//-1:是为了让数组不要越界
//-i:每一轮结束之后,我们就会少比一个数字。
for ( int j = 0 ; j < arr . length - 1 - i ; j ++ ){
if ( arr [ j ] > arr [ j + 1 ] ){
int temp = arr [ j ] ;
arr [ j ] = arr [ j - 1 ] ;
arr [ j - 1 ] = temp ;
}
}
}
}
每一轮都可以少比较一个数比较四轮
也就是:n 个数比较 n-1 轮, 每一轮比较 (n-1-i) 次数
数组遍历
数组遍历:将数组中所有的数据取出来
数组元素下标的合法区间:[0,length-1]。我们可以通过下标来遍历数组中的元素,遍历时可以读取元素的值或者修改元素的值。
使用循环初始化和遍历数组
1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
public static void main ( String [] args ){
int [] a = new int [ 4 ] ;
//初始化数组元素的值
for ( int i = 0 ; i < a . length ; i ++ ){
a [ 0 ] = 100 * i ;
}
//读取元素的值
for ( int i = 0 ; i < a . length ; i ++ ){
System . out . println ( a [ i ] );
}
}
增强for循环(for-each循环)
专门读取元素的值, 不能调用元素的值
增强 for循环 (for-each) 是 JDK1.5 新增加的功能, 专门用于读取数组或集合中所有的元素,即对数组进行遍历。
技巧
for(ElementType element: arrayName){};
1
2
3
4
5
6
7
8
public class Test {
public static void main ( String [] args ){
String [] ss = { "aa" , "bbb" , "ccc" , "ddd" );
for ( String temp : ss ){
System . out . println ( temp );
}
}
}
注意事项
for-each 增强 for 循环在遍历数组过程中不能修改数组中某元素的值
for-each 仅适用于遍历,不涉及有关索引(下标)的操作。
数组的拷贝
System 类里也包含了一个 static void arraycopy(object src, int srcpos, object dest, int destpos, int length)
方法,该方法可以将 src 数组里的元素值赋给 dest 数组的元素,其中 srcpos 指定从 src 数组的第几个元素开始赋值,length 参数指定将 src 数组的多少个元素赋给 dest 数组的元素。
arraycopy()
dest:destination [n.目的地;终点][adj.作为目的地的(旅馆、商店、饭店等)]
src:原数组
srcpos = src + position:原位置 (从原数组的什么位置开始)
dest:目标数组
destpos = dest + position:目标位置 (从目标数组的什么位置开始存放)
1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main ( String [] args ){
String [] s = ( "阿里" , "京东" , "搜狐" , "网易" );
String [] sBak = new String [ 6 ] ;
System . arraycopy ( s , 0 , sBak , 0 , s . length );
for ( int i = 0 ; i < sBak . length ; i ++ ){
System . outprint ( sBak [ i ]+ "\t" );
}
}
}
补充: System.currentTimeMillis();
获取 1970年1月1日 0时0分0秒到当前时间所经历过的毫秒值
数组反转
需求:已知一个数组 arr = {19, 28, 37, 46, 50}; 用程序实现把数组中的元素值交换,交换后的数组 arr = {50, 46, 37, 28, 19}; 并在控制台输出交换后的数组元素。
(图18
)
分析:交换的代码不止一次,可以使用循环进行
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main ( String [] args ){
int [] arr = { 19 , 28 , 37 , 46 , 50 };
//1.定义两个变量,start和end来表示开始和结束的指针。
//int start = 0;
//int end = arr.length -1;
//2.确定交换条件start<end允许交换
for ( int start = 0 , int end = arr . length - 1 ; start < end ; start ++ , end -- ){
//3.循环中编写交换逻辑代码
int temp = arr [ start ] ;
arr [ start ] = arr [ end ] ;
arr [ end ] = temp ;
}
}
java.utilArrays类(工具类)
JDK 提供的 java.util.Arrays 类,包含了常用的数组操作,方便我们日常开发。Arrays 类包含了:排序,查找,填充,打印数组内容的相关的方法。
方法名
说明
public static String toString (int[ ] a)
返回指定数组的内容的字符串表示形式
public static void sort (int[ ] a)
按照数字顺序排列指定的数组 (从小到大)
public static int binarySearch (int[ ] a, int key)
利用二分查找返回指定元素的索引
此处的 Arrays.toString( ) 方法是 Arrays 类的静态方法,不是前面讲的 Object 的 toString( ) 方法。
binarySearch
1
2
3
int [] arr = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 };
int index = Arrays . binarysearch ( arr , 10 );
System . out . println ( index );
使用 Arrays 类中的 binarySearch 的要求
数组必须有序
如果要查找的元素存在,那么返回的是这个元素实际的索引
如果要查找的元素不存在,那么返回的是(-插入点 - 1 )
插入点:如果这个元素在数组中,他应该在哪个索引上,
举例说明:
[-插入点-1]
例如: Arrays.binarySearch(arr, 11); // 结果是 -11
这是因为如果 11 这个元素存在, 那么他的索引是 10, 也就是 -10-1 = -11
思考: 为什么要 [-1], 直接返回 [- 插入点] 不就好了吗?
这是因为, 如果是 Arrays.binarySearch(arr, 0); //此时, 我们要查找的元素是 0, 那么它的插入点也是 0, 如果不减 1, 那么值就是 -0, 也就是 0, 他的意思是 0 这个元素在数组中的 0 号索引, 会引起歧义, 这是不正确的
fill (包头不包尾) :使用 Arrays 类对数组进行填充
1
2
3
4
5
6
7
8
9
10
import java.util.Arrays ;
public class Test {
public static void main ( String [] args ){
int [] a = { 1 , 2 , 323 , 23 , 543 , 12 , 59 };
System . out . println ( Arrays . toString ( a ));
Arrays . fill ( a , 2 , 4 , 100 ); //将2到4索引的元素替换为100:
System . out . println ( Arrays . toString ( a ));
}
}
(图12
)
多维数组
多维数组可以看成以数组为元素的数组 。可以有二维,三维,甚至更多维数组,但是实际开发中用的非常少。最多到二维数组 (学习容器后,一般使用容器,二维数组用的都很少)。
数组类型可以是任何类型,那么数组中的元素能不能是数组类型?
数组类型可以是任意类型。数组的元素:int、Man、String、int[ ]
1
2
3
4
5
6
7
8
9
10
11
//二维数组的声明
public class Test {
public static void main ( String [] args ){
//Java中多维数组的声明和初始化应按从低维到高维的顺序进行
int [][] a = new int [ 3 ][] ;
a [ 0 ] = new int [ 2 ] ;
a [ 1 ] = new int [ 4 ] ;
a [ 2 ] = new int [ 3 ] ;
//int a1[][] = new int[][4];//非法
}
}
在堆中创建一个 int数组类型
对象,对象中的元素是引用类型 (默认初始化 null)
而 a[0]=new int[2];
是在堆中创建一个对象,对象中的元素是 int 类型 (默认初始化 0)
(图13
)
数组的元素是数组
二维数组的属性是一维数组对象
a[0][1]
:a[0]
找到 0x21
,a[0][1]
找到 0x21
里的第二个元素
二维数组概述
什么是二维数组
数组类型可以是任何类型, 那么? 数组中的元素能不能是数组类型
二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器
二维数组可以看成以数组为元素的数组
为什么要有二维数组?
某公司季度,和月份统计的数据如下:单位(万元)
第一季度:22,66,44
第二季度:77,33,88
第三季度:25,45,65
第四季度:11,66,99
1
2
3
4
5
6
7
8
public static void main ( String [] args ){
//Java中多维数组的声明和初始化应按从低维到高维的顺序进行
int [][] a = new int [ 3 ][] ;
a [ 0 ] = new int [ 2 ] ;
a [ 1 ] = new int [ 4 ] ;
a [ 2 ] = new int [ 3 ] ;
//int a1[][] = new int[][4]是非法的
}
(图15
)
在堆中创建一个 int数组类型 对象,对象中的元素是数组, 属于引用类型(默认初始化 null)
而 a[0]=new int[2]; 是在堆中创建一个对象,对象中的元素是 int 类型(默认初始化 0)
数组的元素是数组, 二维数组的属性是一维数组对象
a[0][1]
: a[0] 找到 0x21,a[0][1] 找到 0x21 里的第二个元素
二维数组定义格式
格式1:数据类型[ ][ ] 变量名;
范例:int[ ][ ] arr;
格式2:数据类型 变量名[ ][ ];
范例:int arr[ ][ ];
格式3:数据类型[ ] 变量名[ ];
范例:int[ ] arr[ ];
二维数组动态初始化
二维数组动态初始化
格式:数据类型[ ][ ] 变量名 = new 数据类型[m][n] ;
m 表示这个二维数组,可以存放多少个一维数组
n 表示每一个一维数组,可以存放多少个元素
1
2
3
4
5
6
7
8
public static void main ( String [] args ){
int [][] a = new int [ 3 ][] ;
//a[0] = {1,2,5}; //错误,没有声明类型就初始化
a [ 0 ] = new int [] { 1 , 2 };
a [ 1 ] = new int [] { 2 , 2 };
a [ 2 ] = new int [] { 2 , 2 , 3 , 4 };
System . out . println ( a [ 2 ][ 3 ] );
}
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
32
33
34
35
36
public static void main ( String [] args ){
//数据类型[][] 变量名 = new 数据类型[m][n];
int [][] arr = new int [ 3 ][ 3 ] ;
/*
[[I@10f87f48
@:分隔符
10f87f48:十六进制内存地址
I:数组中存储的数据类型
[[:几个中括号就代表的是几维数组
*/
System . out . println ( arr ); //[[I@18f87f48
/*
二维数组存储一维数组的时候, 存储的是一维数组的内存地址
*/
System . out . println ( arr [ 0 ] ); //[I@b4c966a
System . out . println ( arr [ 1 ] ); //[I@2f4d3709
System . out . println ( arr [ 2 ] ); //[I@4e50df2e
System . out . println ( arr [ 0 ][ 0 ] ); //0
System . out . println ( arr [ 1 ][ 1 ] ); //0
System . out . println ( arr [ 2 ][ 2 ] ); //0
//向二维数组中存储元素
arr [ 0 ][ 0 ] = 11 ;
arr [ 0 ][ 1 ] = 22 ;
arr [ 0 ][ 2 ] = 33 ;
arr [ 1 ][ 0 ] = 11 ;
arr [ 1 ][ 1 ] = 22 ;
arr [ 1 ][ 2 ] = 33 ;
arr [ 2 ][ 0 ] = 11 ;
arr [ 2 ][ 1 ] = 22 ;
arr [ 2 ][ 2 ] = 33 ;
}
二维数组访问元素的细节问题
问题:二维数组中存储的是一维数组,那能不能存入 [提前创建好的一维数组]
呢?
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
32
public static void main ( String [] args )
int [] arr1 = { 11 , 22 , 33 };
int [] arr2 = { 44 , 55 , 66 };
int [] arr3 = { 77 , 88 , 99 , 100 }; //<---看这里
int [][] arr = new int [ 3 ][ 3 ] ;
arr [ 0 ] = arr1 ;
arr [ 1 ] = arr2 ;
arr [ 2 ] = arr3 ;
System . out . println ( arr [ 1 ][ 2 ] ); //66
System . out . println ( arr [ 2 ][ 3 ] ); //100
}
提前创建好数组 , 直接添加
------------------------------------
public static void main ( String [] args )
int [] arr1 = { 11 , 22 , 33 };
int [] arr2 = { 44 , 55 , 66 };
int [] arr3 = { 77 , 88 , 99 };
int [][] arr = new int [ 3 ][ 3 ] ;
arr [ 2 ][ 3 ] = 100 ; //<---看这里
arr [ 0 ] = arr1 ;
arr [ 1 ] = arr2 ;
arr [ 2 ] = arr3 ;
System . out . println ( arr [ 1 ][ 2 ] );
System . out . println ( arr [ 2 ][ 3 ] ); //ArrayIndexOutofBoundsException
}
我们发现提前创建数组的方式, 100 可以存进去, 通过传统方式 100 存不进去
(图16
)
传统方式的动态初始化 , 在创建的时候, 就会把这三个一维数组创建好, 并且里边的索引也都是固定的, 你非要去访问一个不存在的索引, 肯定会出现问题
(图17
)
arr 记录的内存地址是 999, arr[2] = smallarray; 直接用 smallArray 的内存地址替换了arr[2] 的内存地址, 发生了内存地址的替换, 所以 arr[2][3] 是可以找到的
二维数组静态初始化
格式:数据类型[ ][ ] 变量名 = new 数据类型[ ][ ]{ {元素1,元素2.},{元素1,元素2.}.…} ;
范例:int[ ][ ] arr = new int[ ][ ]{ {11,22}, {33,44} } ;
简化格式:数据类型[ ][ ] 变量名 = {{元素1,元素2.},{元素1,元素2.…}…} ;
范例:int[ ][ ] arr = {{11, 22}, {33, 44}} ;
1
2
3
4
5
6
public class Test {
public static void main ( String [] args ){
int [][] a = {{ 1 , 2 , 3 },{ 3 , 4 },{ 3 , 5 , 6 , 7 }};
System . out . println ( a [ 2 ][ 3 ] );
}
}
(图14
)
二维数组静态初始化, 可不可以先创建数组, 再往里面放呢?
没问题
1
2
3
4
5
6
public static void main ( String [] args ){
int [] arr1 = { 11 , 22 , 33 };
int [] arr2 = { 44 , 55 , 66 };
int [][] array = { arr1 , arr2 };
}
二维数组常见操作
获取数组长度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Test {
public static void main ( String [ args ){
int [][] a = new int [ 3 ][] ;
//a[0]=[1,2,5}//错误,没有声明类型就初始化
a [ 0 ] = new int [] { 1 , 2 };
a [ 1 ] = new int [] { 2 , 2 };
a [ 2 ] = new int [] { 2 , 2 , 3 , 4 };
System . out . println ( a [ 2 ][ 3 ] );
//获取的二维数组第一维数组的长度。
System . out . println ( a . length );
//获取第二维第一个数组长度。
System . out . println ( a [ 0 ] . length );
}
}
维数组遍历
已知一个二维数组arr = {{11, 22, 33}, {33, 44, 55}}; 遍历该数组,取出所有元素并打印
1
2
3
4
5
6
7
8
9
10
public static void main ( String [] args ){
int [][] arr = {{ 11 , 22 , 33 }, { 33 , 44 , 55 }};
//1.遍历二维数组,取出里面每一个一维数组
for ( int i = 0 ; i < arr . length ; i ++ ){
//System.out.println(arr[i]);
for ( int j = 0 ; j < arr [ i ] . length ; j ++ )
System . out . println ( arr [ i ][ j ] );
}
}
}
二维数组求和
某公司季度,和月份统计的数据如下:单位(万元)
第一季度:22,66,44
第二季度:77,33,88
第三季度:25,45,65
第四季度:11,66,99
1
2
3
4
5
6
7
8
9
10
11
12
public static void main ( String [] args ){
//1.定义求和变量,准备记录最终累加结果
int sum = 0 ;
//2.使用二维数组来存储数据,每个季度是一个一维数组,再4个一维数组装起来
int [][] arr = {{ 22 , 66 , 44 },{ 77 , 33 , 88 },{ 25 , 45 , 65 },{ 11 , 66 , 99 }};
//3.遍历二维数组,获取所有元素,累加求和
for ( int i = 0 ; i < arr . length ; i ++ ){
for ( int j = 0 ; j < arr [ i ] . length ; j ++ ){
sum += arr [ i ][ j ] ;
}
}
}
使用二维数组保存表格数据
表格数据模型是计算机世界最普遍的模型,可以这么说,大家在互联网上看到的所有数据本质上都是 “表格”,无非是表格之间互相套用。【二维数组存一次,一维数组+对象存一次】
ID
姓名
年龄
职能
入职日期
1001
高小六
18
讲师
2019-2-14
1002
高小七
19
助教
2019-10-10
1003
高小八
20
班主任
2019-5-5
我们观察表格,发现每一行可以使用一个一维数组存储:
1
2
3
Object [] a1 = { 1001 , "高小六" , 18 , "讲师" , "2019-2-14" };
Object [] a2 = { 1002 , "高小七" , 19 , "助教" , "2019-10-10" };
Object [] a3 = { 1003 , "高小八" , 20 , "班主任" , "2019-5-5" };
注意事项
此处基本数据类型 “1001”,本质不是 Object 对象。JAVA 编译器会自动把基本数据类型 “自动装箱” 成包装类对象,学了包装类后就懂了。
这样我们只需要再定义一个二维数组,将上面 3 个数组放入即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.Arrays ;
public class Test {
public static void main ( String [] args ) {
Object [] a1 = { 1001 , "高小六" , 18 , "讲师" , "2019-2-14" };
Object [] a2 = { 1002 , "高小七" , 19 , "助教" , "2019-10-10" };
Object [] a3 = { 1003 , "高小八" , 20 , "班主任" , "2019-5-5" };
Object [][] emps = new Object [ 3 ][] ;
emps [ 0 ] = a1 ;
emps [ 1 ] = a2 ;
emps [ 2 ] = a3 ;
System . out . println ( Arrays . toString ( emps [ 0 ] ));
System . out . println ( Arrays . toString ( emps [ 1 ] ));
System . out . println ( Arrays . toString ( emps [ 2 ] ));
}
}
执行结果
1
2
3
[1001,高小六,18,讲师,2019-2-14]
[1001,高小七,19,助教,2019-10-10]
[1001,高小八,20,班主任,2019-5-5]
上面也可以写作
1
2
3
for ( int i = 0 ; i < emps . length ; i ++ ){
System . out . println ( Arrays . toString ( emps [ i ] ));
}
还可以写作
1
2
3
4
5
6
7
//使用嵌套循环打印二维数组(打印表格数据)
for ( int i = 0 ; i < emps . length ; i ++ ){
for ( int j = 0 ; j < emps [ i ] . length ; j ++ ){
System . out . print ( emps [ i ][ j ]+ "\t" );
}
System . out . println ();
}