一、IDEA开发工具
1.1 了解JAVA在IDEA中的项目结构
project(项目)下是module(模块),然后依次是package(包)和class(类),如图:
1.2 一些IDEA常用快捷键及问题解决
-
常用快捷键
-
问题描述:如何在ideaz中导入电脑文件的其他模块?
如果需要从某个文件里将模块导入进我们的IDEA ,需要先打开File中的Project Structure选项:
选择你想要导入的模块(是包含src文件的上一级是模块文件):
导入到IDEA以后会发现System全是报红,无法运行代码,此时是因为刚导入模块进来时没有进行SDK(JDK)的匹配,需要重新选择一些JDK,如图:
重新点开File中的Project Structure选项:
完成后点击OK就可以正常运行导入的模块里的代码了。
二、数组
2.1 定义格式与初始化
定义格式:
- 数据类型[ ] 数组名
- 数据类型 数组名[ ]
初始化:
- [ 动态初始化]:int[ ] arr=new int[ ];
- [ 静态初始化]:int[ ] arr= { };
int[ ] arr=new int[ ]={ };
2.2 数组元素访问及默认值
元素访问:数组名[索引];
默认值:
2.3 内存分配
内存是计算机中的重要原件,临时存储区域,作用是运行程序。
我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。
–Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。
-
Java内存分配-一个数组内存图
-
Java内存分配-多个数组
2.4 数组操作的常见问题
-
[索引越界异常 ]
数组长度为3,索引范围是0~2,但是我们却访问了一个3的索引。
程序运行后,将会抛出Array Index OutOf Bounds Exception 数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。 -
解决方案
将错误的索引修改为正确的索引范围即可。
-
[空指针异常 ]
arr = null 这行代码,意味着变量arr将不会在保存数组的内存地址,也就不允许再操作数组了,因此运行的时候会抛出 Null Pointer Exception 空指针异常。
-
解决方案
给数组一个真正的堆内存空间引用即可。
2.5 注意事项及操作范例
注意事项:
数组的优缺点:
(一)优点:
1、按照索引查询元素速度快;
2、能存储大量数据;
3、数组定义简单,而且访问很方便;
4、可以随机访问其中的元素。(随机存储方式)
(二)缺点:
1、根据内容查找元素速度慢;
2、数组的大小一经确定不能改变,不适合动态存储(一旦初始化以后,其长度就不可修改);
3、增加、删除元素效率慢(数组中提供的方法非常限,对于添加、删除、插入数据等操作,非常不便;
不能随意更改长度,且一个数组只能有一种数据类型。
4、数组的空间必须是连续的,这就造成数组在内存中分配空间时必须找到一块连续的内存空间。所以数组不可能定义的太大,因为内存中不可能有那么多大的连续的内存空间,而解决这个问题的方法就是使用链表。
数组和链表:
链表:是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。
使用多个不连续的内存空间去存储数据, 可以节省内存资源(只有需要存储数据时,才去划分新的空间),对数据的增删比较方便。
- [问题描述 ] 数组是否具备增删查操作的能力:
增删功能需要创建一个新数组,因为这两个功能改变了原数组的长度
对于查找:
链表只能用元素值通过头指针与尾指针来进行查找(从头到尾遍历查找);而数组可以用索引和元素值进行查找,因此选择数组进行查找会比较高效;
对于增删:
因为链表是一个结点分为两个区域,一个区域存放数据一个区域存放下一个结点的地址,在增删时只需要改变相邻两个结点的地址值,通过指针就可以实现;而数组就必须得增加新的数组来存放。
范例1
升景坊单间短期出租4个月,550元/月(水电煤公摊,网费35元/月),空调、卫生间、厨房齐全。 屋内均是IT行业人士,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。以下是联系信息!
public class ArrayTest {
public static void main(String[] args) {
int[] arr = new int[]{8,2,1,0,3};
int[] index = new int[]{2,0,3,2,4,0,1,3,2,3,3};
String tel = "";
for(int i = 0;i < index.length;i++){
tel += arr[index[i]];
}
System.out.println("联系方式:" + tel);
}
}
范例2
给定一个整型数组,数组成员10个,求该数组中第二大的数的下标。
//数据如图:{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};--0,1,2,3,4,5,6,7,8,9
int[] arr = {1,2,3,4,5,6,7,8,9,0};
int max=arr[0];
int second=arr[0];
int indexS=0;//定义一个下标的索引
for (int i = 0; i < arr.length; i++) {//找到数组的最大值
if(max<arr[i]){
max=arr[i];
}
}
for (int i = 0; i < arr.length; i++) {//在已知最大值的条件下找第二大的值
if(arr[i]!=max){
if(second<arr[i]){
second=arr[i];
indexS=i;
}
}
}
System.out.println(max);
System.out.println(second);
System.out.println("下标是:"+indexS);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
三、二维数组
3.1 概述与初始化
概述 : 二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器。
结论:
二维数组的本质还是一维数组,只不过数组中的元素不是具体的元素值,而是一个新的数组而已。
二维数组数组的值(大数组内)默认为NULL。
一维数组数组的值(小数组内)默认为0。
动态初始化格式::
数据类型[][] 变量名 = new 数据类型[m][n];
m表示这个二维数组,可以存放多少个一维数组,
n表示每一个一维数组,可以存放多少个元素。
静态初始化格式:
完整格式 :
数据类型[][] 变量名 = new 数据类型[][]{ {元素1, 元素2…} , {元素1, 元素2…}
简化格式 :
数据类型[][] 变量名 = { {元素1, 元素2…} , {元素1, 元素2…} …};
3.2 与一维数组的区别
二维数组数组的值(大数组内)默认为NULL。
一维数组数组的值(小数组内)默认为0。
3.3 二维数组访问元素的细节问题
问题 : 二维数组中存储的是一维数组, 那能不能存入 [提前创建好的一维数组] 呢 ?
答案:可以
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[2][3] = 100;
arr[0] = arr1;
arr[1] = arr2;
arr[2] = arr3;
System.out.println(arr[1][2]);
System.out.println(arr[2][3]);
}
结论:
如果二维数组中 第二维数组 的长度不相同,我们可以采用先不指定第二维的长度来初始化数组,可以提前初始化好长度不同的数组,值给二维数组中对应的位置即可。
3.4 操作范例
需求 :
某公司季度和月份统计的数据如下:单位(万元)
第一季度:22,66,44
第二季度:77,33,88
第三季度:25,45,65
第四季度:11,66,99
步骤 :
- 定义求和变量,准备记录最终累加结果
- 使用二维数组来存储数据,每个季度是一个一维数组,再将4个一维数组装起来
- 遍历二维数组,获取所有元素,累加求和
- 输出最终结果
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++){
//这里注意别超出数组的索引值(要注意i与j的取值范围)
sum += arr[i][j];
}
}
// 4. 输出最终结果
System.out.println(sum);
}
改动:将每个季度的分别求和,并打印求和结果
public static void main(String[] args) {
int[][] arr=new int[][]{{22,66,44},{77,33,88},{25,45,65},{11,66,99}};
int sum=0;
int sumJ=0;
for (int i = 0; i < arr.length; i++) {
int[] arrA=arr[i];//定义一个新的一维数组arrA用来接收二维数组arr中第一维数组
sumJ=getJiduSum(arrA);//将新的一维数组放入getJiduSum方法中进行求和运算
System.out.println("第"+(i+1)+"季度:"+sumJ);
for (int j = 0; j < arr[i].length; j++) {
sum=arr[i][j]+sum;
}
}
System.out.println("==================");
System.out.println("总和:"+sum);
}
public static int getJiduSum(int arrA[]) {
int sum=0;
for (int i = 0; i < arrA.length; i++) {
sum=sum+arrA[i];
}
return sum;
}
四、方法
4.1 概述及定义和调用
方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集
- 注意:
- 方法必须先创建才可以使用,该过程成为方法定义
- 方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用
4.2 形参和实参
形参变量:
只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。
即形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。
实参变量:
可以是常量、变量、表达式、函数等,无论实参是什么类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
(PS:)
对于基本数据类型来说形参的值的变化不影响实参
而对于引用数据类型则相反。
- 方法参数传递基本类型
public class Test1 {
/*
方法参数传递为基本数据类型 :
传入方法中的, 是具体的数值.
*/
public static void main(String[] args) {
int number = 100;
System.out.println("调用change方法前:" + number);//输出100
change(number);
System.out.println("调用change方法后:" + number);//输出的number还是100
//(方法运行时那个基本数据变量(形参)是得到改变的,但是方法运行结束后,被修改的变量随着方法一同出栈以后,此时栈内只剩(原来没有被修改的变量)实参的数据)
}
public static void change(int number) {
number = 200;
}
}
- 结论:
- 基本数据类型的参数,形式参数的改变,不影响实际参数
- 结论依据:
- 每个方法在栈内存中,都会有独立的栈空间,方法运行结束后就会弹栈消失
- 方法参数传递引用类型
public class Test2 {
/*
方法参数传递为引用数据类型 :
传入方法中的, 是内存地址.
*/
public static void main(String[] args) {
int[] arr = {10, 20, 30};
System.out.println("调用change方法前:" + arr[1]);
change(arr);
System.out.println("调用change方法后:" + arr[1]);
}
public static void change(int[] arr) {
arr[1] = 200;
}
}
结论:
- 对于引用类型的参数,形式参数的改变,影响实际参数的值
- 方法参数传递为基本数据类型 : 传入方法中的是具体的数值;
- 方法参数转递为引用数据类型:传入方法中的是内存地址(对某一个堆空间的引用关系)
- 总结: j a v a 中参数的传递都是传值
- 结论依据:
- 引用数据类型的传参,传入的是地址值,内存中会造成两个引用指向同一个内存的效果,所以即使方法弹栈,堆内存中的数据也已经是改变后的结果
4.3 方法的重载
4.3.1重载的定义及构成重载的条件
方法重载概念:
方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载。
重载的条件:
- 多个方法在同一个类中
- 多个方法具有相同的方法名
- 参数不相同:
数量不同
形参的数据类型不同
参数顺序不同 (一般不建议用)
4.3 注意事项及操作范例
注意事项
-
方法不能嵌套定义
-
方法类型为void时,表示无返回值,可以省略return,也可以单独的书写return,此时return语句后面不能跟数据或代码;
-
方法有返回值类型时,return 语句必须有,并且需要带数据
范例1
- 需求:设计一个方法,该方法能够同时获取数组的最大值和最小值
- 注意: return语句, 只能带回一个结果.
public static void main(String[] args) {
int[] arr = {11,55,33,22,44};
//(1)
int[] maxAndMin = getMaxAndMin(arr);//接收getMaxAndMin()方法的返回值
//因为方法是一个数组类型,返回值也是数组类型,所以在main方法中需要一个相同类型的数组去接收getMaxAndMin()方法的返回值。
System.out.println("数组的最小值为:"+maxAndMin[0]);
System.out.println("数组的最大值为:"+maxAndMin[1]);
System.out.println();
//(2)
//int[] arr0=getMaxAndMin(arr);定义什么数值的名称与getMaxAndMin()返回值里的可以不同,类比形参和实参的理解
//System.out.println("数组的最小值为:"+arr0[0]);
//System.out.println("数组的最大值为:"+arr0[1]);
}
//定义的方法可以定义成数组的类型,返回值也为一个数组
//实现同一方法同时获取数组的最大值和最小值
public static int[] getMaxAndMin(int[] arr){
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
}
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if(min > arr[i]){
min = arr[i];
}
}
int[] maxAndMin = {min, max};//用一个新的数组去存储最大值和最小值,使其最大值最小值能同时被打印出来
return maxAndMin;
}
范例2
定义equals方法,比较数组内容是否完全一致。
代码实现,效果如图所示:
数组1:{1,2,3,6,7,8}和数组2:{1,2,3,6,7,8}是完全一致的
提示:长度一致,内容一致,定义为内容完全一致。
//法一:
public static void main(String[] args) {
int[] arr1={1,2,3,6,7,8};
int[] arr2={1,2,3,6,7,8};
boolean aa=equals(arr1,arr2);
if(aa==true){
System.out.println("长度一致,内容一致,定义为内容完全一致");
}else {
System.out.println("两个数组不一致");
}
}
public static boolean equals(int arr1[],int arr2[]) {
for (int i = 0; i < arr1.length; i++) {
if (arr1.length!= arr2.length) {
return false;
}else if(arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
//法二:利用全局变量
public class MethodDome2 {
static boolean same;
public static void main(String[] args) {
int[] arr1={1,2,3,6,7,8};
int[] arr2={6,7,5,4,3,2};
boolean aa=equals(arr1,arr2);
if(aa==true){
System.out.println("长度一致,内容一致,定义为内容完全一致");
}else {
System.out.println("两个数组不一致");
}
}
public static boolean equals(int arr1[],int arr2[]) {
for (int i = 0; i < arr1.length; i++) {
if (arr1.length!= arr2.length) {
same=false;
}else if(arr1[i] == arr2[i]) {
same=true;
}
}
return same;
}
}
五、Debug
5.1 操作流程及使用
Debug是供程序员使用的程序调试工具,它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序。
Debug介绍与操作流程
- 如何加断点
- 选择要设置断点的代码行,在行号的区域后面单击鼠标左键即可
- 如何运行加了断点的程序
- 在代码区域右键Debug执行
- 看哪里
- 看Debugger窗口
- 看Console窗口
- 点哪里
- 点Step Into (F7)这个箭头,也可以直接按F7
- 如何删除断点
- 选择要删除的断点,单击鼠标左键即可
- 如果是多个断点,可以每一个再点击一次。也可以一次性全部删除
六、位运算
位移运算符:
有关位运算的介绍可以参照这篇博客:
https://blog.csdn.net/hzf0701/article/details/117359478
在这里只说一下异或这一方面:
^ 异或可以用来进行数据交换,并且比重新创建temp临时存放数据这个方法要更高效,因为异或属于位运算。
计算机中的数在内存中都是以二进制形式进行存储的,而位运算就是直接对整数在内存中的二进制位进行操作,因此其执行效率非常高,在程序中尽量使用位运算进行操作,这会大大提高程序的性能。
^ 异或 运算符的特点:一个数, 被另外一个数, 异或两次, 该数本身不变。
七、ArrayList(集合)
7.1 ArrayList的构造方法和添加方法
另:ArrayList< E> :可调整大小的数组实现。
< E>: 是一种特殊的数据类型,泛型。
泛型:限制集合中元素的数据类型(即:要想集合中只出现XX类型,使用它来进行限制);
包括自定义的类也能进行限制(例:自己编写一个student类,限制为ArrayList 后,进行初始化时的参数必须只能属于student类中的数据类型)
怎么用呢?
:在出现E的地方我们使用引用数据类型替换即可。
7.2使用范例
ArrayList的构造方法:
ArrayList的添加方法:
7.3 集合注意事项及和数组的区别
集合就是一个放数据容器,集合当中存储的都是java对象的内存地址(或者说集合中存储的是引用。),它主要包括Collection和Map集合。
1. 集合只能存放对象,Java中每一种基本数据类型都有对应的引用类型。例如在集合中存储一个int型数据时,要先自动转换成Integer类后再存入;
2. 集合存放的是对对象的引用,对象本身还是存放在堆内存中;
3. 集合可以存放不同类型、不限数量的数据类型,并且长度可变。
集合和数组的区别:
共同点:都是存储数据的容器
不同点:数组的容量是固定的,集合的容量是可变的
但是集合的底层最本质的也还是数组。