1. 概述

1.1 java语言的三个版本

JavaSE: Java 语言的(标准版),用于桌面应用的开发,是其他两个版本的基础

JavaME: Java 语言的(小型版),用于嵌入式消费类电子设备

JavaEE: Java 语言的(企业版),用于 Web 方向的网站开发

1.2 Java语言跨平台原理

Java编译器将Java源程序编译成与平台无关的字节码文件(class文件),然后由Java虚拟机(JVM)对字节码文件解释执行。

Java跨平台原理

1.3 JRE和JDK

JVM(Java Virtual Machine),Java虚拟机

JRE(Java Runtime Environment),Java运行环境,包含了JVM和Java的核心类库(Java API)

JDK(Java Development Kit)称为Java开发工具,包含了JRE和开发工具

总结:我们只需安装JDK即可,它包含了java的运行环境和虚拟机。

image-20220212185728089

1.3.1 JDK的安装目录介绍

目录名称 说明
bin 该路径下存放了JDK的各种工具命令。javac和java就放在这个目录。
conf 该路径下存放了JDK的相关配置文件。
include 该路径下存放了一些平台特定的头文件。
jmods 该路径下存放了JDK的各种模块。
legal 该路径下存放了JDK各模块的授权文档。
lib 该路径下存放了JDK工具的一些补充JAR包。

1.4 HelloWorld案例的编译和运行

打开命令行窗口,将目录切换至java文件所在目录,编译java文件生成class文件,运行class文件。

编译:javac 文件名.java

范例:javac HelloWorld.java

运行:java 类名

范例:java HelloWorld

1.5 关键字

关键字是指被java语言赋予了特殊含义的单词。

关键字的特点:

​ 关键字的字母全部小写。

​ 常用的代码编辑器对关键字都有高亮显示,比如现在我们能看到的public、class、static等。

1.6 常量

常量:在程序运行过程中,其值不可以发生改变的量。

Java中的常量分类:

字符串常量 用双引号括起来的多个字符(可以包含0个、一个或多个),例如”a”、”abc”、”中国”等

整数常量 整数,例如:-10、0、88等

小数常量 小数,例如:-5.5、1.0、88.88等

字符常量 用单引号括起来的一个字符,例如:’a’、’5’、’B’、’中’等

布尔常量 布尔值,表示真假,只有两个值true和false

空常量 一个特殊的值,空值,值为null

除空常量外,其他常量均可使用输出语句直接输出。

1.7 变量

1.7.1 变量的定义

变量:在程序运行过程中,其值可以发生改变的量。

从本质上讲,变量是内存中的一小块区域,其值可以在一定范围内变化。

变量的定义格式:

1
2
3
数据类型 变量名 = 初始化值; // 声明变量并赋值
int age = 18;
System.out.println(age);

或者(扩展)

1
2
3
4
5
6
// 先声明,后赋值(使用前赋值即可)
数据类型 变量名;
变量名 = 初始化值;
double money;
money = 55.5;
System.out.println(money);

还可以(扩展)

在同一行定义多个同一种数据类型的变量,中间使用逗号隔开。但不建议使用这种方式,降低程序的可读性。

1
2
3
4
5
6
7
8
9
int a = 10, b = 20; // 定义int类型的变量a和b,中间使用逗号隔开
System.out.println(a);
System.out.println(b);

int c,d; // 声明int类型的变量c和d,中间使用逗号隔开
c = 30;
d = 40;
System.out.println(c);
System.out.println(d);

1.7.2 变量的修改

1
2
3
int a = 10;
a = 30; //修改变量的值
System.out.println(a);

变量前面不加数据类型时,表示修改已存在的变量的值。

1.7.3 变量的注意事项

  1. 在同一对花括号中,变量名不能重复。
  2. 变量在使用之前,必须初始化(赋值)。
  3. 定义long类型的变量时,需要在整数的后面加L(大小写均可,建议大写)。因为整数默认是int类型,整数太大可能超出int范围。
  4. 定义float类型的变量时,需要在小数的后面加F(大小写均可,建议大写)。因为浮点数的默认类型是double, double的取值范围是大于float的,类型不兼容。

1.8 数据类型

Java是一个强类型语言,Java中的数据必须明确数据类型。在Java中的数据类型包括基本数据类型和引用数据类型两种。

Java中的基本数据类型:

数据类型 关键字 内存占用 取值范围
整数类型 byte 1 -128~127
short 2 -32768~32767
int(默认) 4 -2的31次方到2的31次方-1
long 8 -2的63次方到2的63次方-1
浮点类型 float 4 负数:-3.402823E+38到-1.401298E-45 正数: 1.401298E-45到3.402823E+38
double(默认) 8 负数:-1.797693E+308到-4.9000000E-324 正数:4.9000000E-324 到1.797693E+308
字符类型 char 2 0-65535
布尔类型 boolean 1 true,false

说明:

​ e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方。

​ 在java中整数默认是int类型,浮点数默认是double类型。

1.9 标识符

标识符是用户编程时使用的名字,用于给类、方法、变量、常量等命名。

1.9.1 组成规则:

​ 由字母、数字、下划线“_”、美元符号“$”组成,第一个字符不能是数字。

​ 不能使用java中的关键字作为标识符。

​ 标识符对大小写敏感(区分大小写)。

1.9.2 命名约定:

1.9.2.1 小驼峰式命名:变量名、方法名

​ 首字母小写,从第二个单词开始每个单词的首字母大写。

​ 例如:userName

1.9.2.2 大驼峰式命名:类名

​ 每个单词的首字母都大写。

​ 例如:Student

2.类型转换

在Java中,一些数据类型之间是可以相互转换的。分为两种情况:自动类型转换和强制类型转换。

2.1 隐式转换(自动类型转换)

​ 把一个表示数据范围小的数值或者变量赋值给另一个表示数据范围大的变量。这种转换方式是自动的,直接书写即可。例如:

1
2
double num = 10; // 将int类型的10直接赋值给double类型
System.out.println(num); // 输出10.0

​ 类型从小到大关系图:

图片1

说明:

  1. 整数默认是int类型,byte、short和char类型数据参与运算均会自动转换为int类型。
1
2
3
4
5
6
7
8
byte b1 = 10;
byte b2 = 20;
byte b3 = b1 + b2;
// 第三行代码会报错,b1和b2会自动转换为int类型,计算结果为int,int赋值给byte需要强制类型转换。
// 修改为:
int num = b1 + b2;
// 或者:
byte b3 = (byte) (b1 + b2);
  1. boolean类型不能与其他基本数据类型相互转换。

2.2 强制转换

​ 把一个表示数据范围大的数值或者变量赋值给另一个表示数据范围小的变量。

​ 强制类型转换格式:目标数据类型 变量名 = (目标数据类型)值或者变量;

​ 例如:

1
2
3
double num1 = 5.5;
int num2 = (int) num1; // 将double类型的num1强制转换为int类型
System.out.println(num2); // 输出5(小数位直接舍弃)

2.3 类型转换案例

案例代码:

1
2
3
4
byte a = 3;
byte b = 4;
byte c = a + b; //错误。因为两个byte变量相加,会先提升为int类型
byte d = 3 + 4; //正确。常量优化机制

常量优化机制:

​ 在编译时,整数常量的计算会直接算出结果,并且会自动判断该结果是否在byte取值范围内,

在:编译通过
不在:编译失败

3.运算符

3.1 算数运算符

符号 作用 说明
+ 和值
- 差值
* 与“×”相同
/ 与“÷”相同
% 取余 获取的是两个数据做除法的余数

注意:

  1. /和%的区别:两个数据做除法,/取结果的商,%取结果的余数。

  2. 整数操作只能得到整数,要想得到小数,必须有浮点数参与运算。

1
2
3
4
int a = 10;
int b = 3;
System.out.println(a / b); // 输出结果3
System.out.println(a % b); // 输出结果1

3.1.1 字符的“+”操作

char类型参与算术运算,使用的是计算机底层对应的十进制数值。需要我们记住三个字符对应的数值:

‘a’ – 97 a-z是连续的,所以’b’对应的数值是98,’c’是99,依次递加

‘A’ – 65 A-Z是连续的,所以’B’对应的数值是66,’C’是67,依次递加

‘0’ – 48 0-9是连续的,所以’1’对应的数值是49,’2’是50,依次递加

1
2
3
4
5
6
7
8
9
// 可以通过使用字符与整数做算术运算,得出字符对应的数值是多少
char ch1 = 'a';
System.out.println(ch1 + 1); // 输出98,97 + 1 = 98

char ch2 = 'A';
System.out.println(ch2 + 1); // 输出66,65 + 1 = 66

char ch3 = '0';
System.out.println(ch3 + 1); // 输出49,48 + 1 = 49

算术表达式中包含不同的基本数据类型的值的时候,整个算术表达式的类型会自动进行提升。

提升规则:

byte类型,short类型和char类型将被提升到int类型,不管是否有其他类型参与运算。

整个表达式的类型自动提升到与表达式中最高等级的操作数相同的类型

​ 等级顺序:byte,short,char –> int –> long –> float –> double

例如:

1
2
3
4
5
6
7
8
9
byte b1 = 10;
byte b2 = 20;
// byte b3 = b1 + b2; // 该行报错,因为byte类型参与算术运算会自动提示为int,int赋值给byte可能损失精度
int i3 = b1 + b2; // 应该使用int接收
byte b3 = (byte) (b1 + b2); // 或者将结果强制转换为byte类型
-------------------------------
int num1 = 10;
double num2 = 20.0;
double num3 = num1 + num2; // 使用double接收,因为num1会自动提升为double类型

3.1.2 字符串的“+”操作

当“+”操作中出现字符串时,这个”+”是字符串连接符,而不是算术运算。

1
System.out.println("itheima"+ 666); // 输出:itheima666

在”+”操作中,如果出现了字符串,就是连接运算符,否则就是算术运算。当连续进行“+”操作时,从左到右逐个执行。

1
2
3
4
System.out.println(1 + 99 + "年黑马");            // 输出:100年黑马
System.out.println(1 + 2 + "itheima" + 3 + 4); // 输出:3itheima34
// 可以使用小括号改变运算的优先级
System.out.println(1 + 2 + "itheima" + (3 + 4)); // 输出:3itheima7

3.2 自增自减运算符

符号 作用 说明
++ 自增 变量的值加1
自减 变量的值减1

注意事项:

​ ++和– 既可以放在变量的后边,也可以放在变量的前边。

​ 单独使用的时候, ++和– 无论是放在变量的前边还是后边,结果是一样的。

​ 放在后面:先运算,后自加(减)。

​ 放在前面:先自加(减),后运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int i = 10;
i++; // 单独使用
System.out.println("i:" + i); // i:11

int j = 10;
++j; // 单独使用
System.out.println("j:" + j); // j:11

int x = 10;
int y = x++; // 赋值运算,++在后边,所以是使用x原来的值赋值给y,x本身自增1
System.out.println("x:" + x + ", y:" + y); // x:11,y:10

int m = 10;
int n = ++m; // 赋值运算,++在前边,所以是使用m自增后的值赋值给n,m本身自增1
System.out.println("m:" + m + ", m:" + m); // m:11,m:11

3.3 赋值运算符

赋值运算符的作用是将一个表达式的值赋给左边,左边必须是可修改的,不能是常量。

符号 作用 说明
= 赋值 a=10,将10赋值给变量a
+= 加后赋值 a+=b,将a+b的值给a
-= 减后赋值 a-=b,将a-b的值给a
*= 乘后赋值 a*=b,将a×b的值给a
/= 除后赋值 a/=b,将a÷b的商给a
%= 取余后赋值 a%=b,将a÷b的余数给a

注意:

扩展的赋值运算符==隐含了强制类型转换==。

1
2
3
4
short s = 10;
s = s + 10; // 此行代码报出,因为运算中s提升为int类型,运算结果int赋值给short可能损失精度

s += 10; // 此行代码没有问题,隐含了强制类型转换,相当于 s = (short) (s + 10);

3.4 关系运算符

关系运算符有6种关系,分别为小于、小于等于、大于、等于、大于等于、不等于。

符号 说明
== a==b,判断a和b的值是否相等,成立为true,不成立为false
!= a!=b,判断a和b的值是否不相等,成立为true,不成立为false
> a>b,判断a是否大于b,成立为true,不成立为false
>= a>=b,判断a是否大于等于b,成立为true,不成立为false
< a<b,判断a是否小于b,成立为true,不成立为false
<= a<=b,判断a是否小于等于b,成立为true,不成立为false

3.5 逻辑运算符

逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断的结果是 true 或 false。

符号 作用 说明
& 逻辑与 a&b,a和b都是true,结果为true,否则为false
| 逻辑或 a|b,a和b都是false,结果为false,否则为true
^ 逻辑异或 a^b,a和b结果不同为true,相同为false
! 逻辑非 !a,结果和a的结果正好相反

3.6 短路逻辑运算符

符号 作用 说明
&& 短路与 作用和&相同,但是有短路效果
|| 短路或 作用和|相同,但是有短路效果

在逻辑与运算中,只要有一个表达式的值为false,那么结果就可以判定为false了,没有必要将所有表达式的值都计算出来,短路与操作就有这样的效果,可以提高效率。同理在逻辑或运算中,一旦发现值为true,右边的表达式将不再参与运算。

  • 逻辑与&,无论左边真假,右边都要执行。

  • 短路与&&,如果左边为真,右边执行;如果左边为假,右边不执行。

  • 逻辑或|,无论左边真假,右边都要执行。

  • 短路或||,如果左边为假,右边执行;如果左边为真,右边不执行。

1
2
3
4
5
6
7
8
9
int x = 3;
int y = 4;
System.out.println((x++ > 4) & (y++ > 5)); // 两个表达都会运算
System.out.println(x); // 4
System.out.println(y); // 5

System.out.println((x++ > 4) && (y++ > 5)); // 左边已经可以确定结果为false,右边不参与运算
System.out.println(x); // 4
System.out.println(y); // 4

3.7 三元运算符

三元运算符语法格式:

1
关系表达式 ? 表达式1 : 表达式2;

解释:问号前面的位置是判断的条件,判断结果为boolean型,为true时调用表达式1,为false时调用表达式2。其逻辑为:如果条件表达式成立或者满足则执行表达式1,否则执行第二个。

举例:

1
2
3
int a = 10;
int b = 20;
int c = a > b ? a : b; // 判断 a>b 是否为真,如果为真取a的值,如果为假,取b的值

4. 流程控制语句

4.1 顺序结构

顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。

顺序结构执行流程图:

image-20220212205710165

4.2 分支结构

4.2.1 if语句格式1

1
2
3
4
格式:
if (关系表达式) {
语句体;
}

执行流程:

①首先计算关系表达式的值

②如果关系表达式的值为true就执行语句体

③如果关系表达式的值为false就不执行语句体

④继续执行后面的语句内容

image-20220212205853564

4.2.2 if语句格式2

1
2
3
4
5
6
格式:
if (关系表达式) {
语句体1;
} else {
语句体2;
}

执行流程:

①首先计算关系表达式的值

②如果关系表达式的值为true就执行语句体1

③如果关系表达式的值为false就执行语句体2

④继续执行后面的语句内容

image-20220212210008323

4.2.3 if语句格式3

1
2
3
4
5
6
7
8
9
10
格式:
if (关系表达式1) {
语句体1;
} else if (关系表达式2) {
语句体2;
}

else {
语句体n+1;
}

执行流程:

①首先计算关系表达式1的值

②如果值为true就执行语句体1;如果值为false就计算关系表达式2的值

③如果值为true就执行语句体2;如果值为false就计算关系表达式3的值

④…

⑤如果没有任何关系表达式为true,就执行语句体n+1。

图片5

4.2 循环结构

4.2.1 switch语句

  • 格式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    switch (表达式) {
    case 1:
    语句体1;
    break;
    case 2:
    语句体2;
    break;
    ...
    default:
    语句体n+1;
    break;
    }
  • 执行流程:

    • 首先计算出表达式的值
    • 其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
    • 最后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分,然后程序结束掉。

注意: 如果switch语句中,case省略了break语句, 就会开始case穿透

  • 需求 : 键盘录入星期数,输出工作日、休息日 (1-5)工作日,(6-7)休息日
  • 示例代码:
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
/*
case穿透是如何产生的?

如果switch语句中,case省略了break语句, 就会开始case穿透.

现象:
当开始case穿透,后续的case就不会具有匹配效果,内部的语句都会执行
直到看见break,或者将整体switch语句执行完毕,才会结束。
*/
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入星期数:");
int week = sc.nextInt();

switch(week){
case 1:
case 2:
case 3:
case 4:
case 5:
System.out.println("工作日");
break;
case 6:
case 7:
System.out.println("休息日");
break;
default:
System.out.println("您的输入有误");
break;
}
}
}

4.2.2 for循环

  • 循环:

    循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体语句,当反复 执行这个循环体时,需要在合适的时候把循环判断条件修改为false,从而结束循环,否则循环将一直执行下去,形 成死循环。

  • for循环格式:

1
2
3
for (初始化语句;条件判断语句;条件控制语句) {
循环体语句;
}
  • 格式解释:

    • 初始化语句: 用于表示循环开启时的起始状态,简单说就是循环开始的时候什么样
    • 条件判断语句:用于表示循环反复执行的条件,简单说就是判断循环是否能一直执行下去
    • 循环体语句: 用于表示循环反复执行的内容,简单说就是循环反复执行的事情
    • 条件控制语句:用于表示循环执行中每次变化的内容,简单说就是控制循环是否能执行下去
  • 执行流程:

    ①执行初始化语句

    ②执行条件判断语句,看其结果是true还是false

    ​ 如果是false,循环结束

    ​ 如果是true,继续执行

    ③执行循环体语句

    ④执行条件控制语句

    ⑤回到②继续

4.2.3 while循环

  • while循环完整格式:

    1
    2
    3
    4
    5
    初始化语句;
    while (条件判断语句) {
    循环体语句;
    条件控制语句;
    }
  • while循环执行流程:

    ①执行初始化语句

    ②执行条件判断语句,看其结果是true还是false

    ​ 如果是false,循环结束

    ​ 如果是true,继续执行

    ③执行循环体语句

    ④执行条件控制语句

    ⑤回到②继续

4.2.4 do……while循环

  • 完整格式:

    1
    2
    3
    4
    5
    初始化语句;
    do {
    循环体语句;
    条件控制语句;
    }while(条件判断语句);
  • 执行流程:

    ① 执行初始化语句

    ② 执行循环体语句

    ③ 执行条件控制语句

    ④ 执行条件判断语句,看其结果是true还是false

    如果是false,循环结束

    如果是true,继续执行

    ⑤ 回到②继续

4.2.5 三种循环的区别

  • 三种循环的区别
    • for循环和while循环先判断条件是否成立,然后决定是否执行循环体(先判断后执行)
    • do…while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断)
  • for循环和while的区别
    • 条件控制语句所控制的自增变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到了
    • 条件控制语句所控制的自增变量,对于while循环来说不归属其语法结构中,在while循环结束后,该变量还可以继续使用

4.2.6 死循环

  • 死循环格式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    for死循环格式 :
    for(;;){

    }

    while死循环格式 :

    while(true){

    }

    do..while死循环格式 :

    do{

    }while(true);

4.2.7 跳转控制语句

  • 跳转控制语句(break)
    • 跳出循环,结束循环
  • 跳转控制语句(continue)
    • 跳过本次循环,继续下次循环
  • 注意: continue只能在循环中进行使用!

5.Random

5.1 Random产生随机数(掌握)

  • 概述:

    • Random类似Scanner,也是Java提供好的API,内部提供了产生随机数的功能
  • 使用步骤:

    1. 导入包

      import java.util.Random;

    2. 创建对象

      Random r = new Random();

    3. 产生随机数

      int num = r.nextInt(10);

      解释:产生的随机数是0-9中随机的一个

  • 示例代码:

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
import java.util.Random;

public class Demo1Random {
/*
Random : 产生随机数

1. 导包 : import java.util.Random;
导包的动作必须出现在类定义的上面

2. 创建对象 : Random r = new Random();
上面这个格式里面,r 是变量名,可以变,其他的都不允许变

3. 获取随机数 : int number = r.nextInt(10); //获取数据的范围:[0,10) 包括0,不包括10
上面这个格式里面,number是变量名,可以变,数字10可以变。其他的都不允许变

需求: 产生随机数1-10之间的
*/
public static void main(String[] args){
// 2. 创建对象
Random r = new Random();

for(int i = 1; i <= 10; i++){
// 3. 获取随机数
int num = r.nextInt(10) + 1; // 1-10
System.out.println(num);
}
}
}

6.数组

6.1 数组介绍

​ 数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致。

6.2 数组的定义格式

  • 第一种格式

​ 数据类型[] 数组名

​ 示例:

1
2
3
int[] arr;        
double[] arr;
char[] arr;
  • 第二种格式

​ 数据类型 数组名[]

​ 示例:

1
2
3
int arr[];
double arr[];
char arr[];

6.3 动态初始化

数组动态初始化就是只给定数组的长度,由系统给出默认初始化值

6.3.1 动态初始化格式

1
数据类型[] 数组名 = new 数据类型[数组长度];
1
int[] arr = new int[3];

6.3.2 示例代码 :

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
package com.itheima.array;

public class Demo2Array {
/*
数组的动态初始化:
在初始化的时候, 需要手动指定数组的长度, 系统会为数组容器分配初始值.

动态初始化格式:
数据类型[] 数组名 = new 数据类型[数组的长度];

注意:
打印数组变量的时候, 会打印出数组的内存地址

[I@10f87f48 :

@ : 分隔符
[ : 当前的空间是一个数组类型
I : 当前数组容器中所存储的数据类型
10f87f48 : 十六进制内存地址

0 1 2 3 4 5 6 7 8 9 a b c d e f
*/
public static void main(String[] args) {
// 数据类型[] 数组名 = new 数据类型[数组的长度];
// 通过new关键字创建了一个int类型的数组容器, 该容器可以存储5个int类型的整数, 该容器被arr数组变量所记录
int[] arr = new int[5];
// [I@10f87f48
System.out.println(arr);

byte[] bArr = new byte[3];
// [B@b4c966a
System.out.println(bArr);

}
}

6.4 数组的静态初始化

​ 在创建数组时,直接将元素确定

6.4.1 静态初始化格式

  • 完整版格式

    1
    数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...};
  • 简化版格式

    1
    数据类型[] 数组名 = {元素1,元素2,...};

6.4.2 示例代码

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
package com.itheima.array2;

public class Demo1Array {
/*
数组静态初始化 : 初始化时指定每个数组元素的初始值,由系统决定数组长度

完整格式:
数据类型[] 数组名 = new 数据类型[]{数据1,数据2,数据3...};
简化格式:
数据类型[] 数组名 = {数据1,数据2,数据3...};
*/
public static void main(String[] args) {
// 数据类型[] 数组名 = new 数据类型[]{数据1,数据2,数据3...};
int[] arr = new int[]{11,22,33};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);

// 数据类型[] 数组名 = {数据1,数据2,数据3...};
int[] arr2 = {44,55,66};
System.out.println(arr2);
System.out.println(arr2[0]);
System.out.println(arr2[1]);
System.out.println(arr2[2]);

}
}

6.5 内存分配

  • 一个数组内存图

1591007817165

  • 两个数组内存图

1591007925899

  • 多个数组指向相同内存图

1591007957052

7.方法

7.1 无参数方法定义和调用

  • 定义格式:

    1
    2
    3
    public static void 方法名 (   ) {
    // 方法体;
    }
  • 范例:

    1
    2
    3
    public static void method (    ) {
    // 方法体;
    }
  • 调用格式:

    1
    方法名();
  • 范例:

    1
    method();
  • 注意:

    • 方法必须先定义,后调用,否则程序将报错
    • 每个方法在被调用执行的时候,都会进入栈内存,并且拥有自己独立的内存空间,方法内部代码调用完毕之后,会从栈内存中弹栈消失。

7.2 带参数方法定义和调用

  • 定义格式:

    参数:由数据类型和变量名组成 - 数据类型 变量名

    参数范例:int a

    1
    2
    3
    4
    5
    6
    7
    public static void 方法名 (参数1) {
    方法体;
    }

    public static void 方法名 (参数1, 参数2, 参数3...) {
    方法体;
    }
  • 范例:

    1
    2
    3
    4
    5
    6
    public static void isEvenNumber(int number){
    ...
    }
    public static void getMax(int num1, int num2){
    ...
    }
  • 注意:

    1
    2
    3
    方法定义时,参数中的数据类型与变量名都不能缺少,缺少任意一个程序将报错

    方法定义时,多个参数之间使用逗号( ,)分隔
  • 调用格式:

    1
    2
    3
    方法名(参数);

    方法名(参数1,参数2);
  • 范例:

    1
    2
    3
    isEvenNumber(10);

    getMax(10,20);

    方法调用时,参数的数量与类型必须与方法定义中的设置相匹配,否则程序将报错

形参:方法定义中的参数

​ 等同于变量定义格式,例如:int number

实参:方法调用中的参数

​ 等同于使用变量或常量,例如: 10 number

7.3 带返回值方法定义和调用

  • 定义格式

    1
    2
    3
    public static 数据类型 方法名 ( 参数 ) { 
    return 数据 ;
    }
  • 范例

    1
    2
    3
    4
    5
    6
    public static boolean isEvenNumber( int number ) {           
    return true ;
    }
    public static int getMax( int a, int b ) {
    return 100 ;
    }
  • 注意:

    ​ 方法定义时return后面的返回值与方法定义上的数据类型要匹配,否则程序将报错

  • 调用格式

    1
    2
    方法名 ( 参数 ) ;
    数据类型 变量名 = 方法名 ( 参数 ) ;
  • 范例

    1
    2
    isEvenNumber ( 5 ) ;
    boolean flag = isEvenNumber ( 5 );

方法的返回值通常会使用变量接收,否则该返回值将无意义

7.4 方法的注意事项

  • 方法不能嵌套定义

    • 示例代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public class MethodDemo {
      public static void main(String[] args) {

      }

      public static void methodOne() {
      public static void methodTwo() {
      // 这里会引发编译错误!!!
      }
      }
      }
  • void表示无返回值,可以省略return,也可以单独的书写return,后面不加数据

    • 示例代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      public class MethodDemo {
      public static void main(String[] args) {

      }
      public static void methodTwo() {
      //return 100; 编译错误,因为没有具体返回值类型
      return;
      //System.out.println(100); return语句后面不能跟数据或代码
      }
      }

7.5 方法重载(同方法,不同参)

  • 方法重载概念

    方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载

    • 多个方法在同一个类中
    • 多个方法具有==相同的方法名==
    • 多个方法的==参数不相同==,类型不同或者数量不同
  • 注意:

    • 重载仅对应方法的定义,与方法的调用无关,调用方式参照标准格式
    • 重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关,换句话说不能通过返回值来判定两个方法是否相互构成重载
  • 正确范例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class MethodDemo {
    public static void fn(int a) {
    //方法体
    }
    public static int fn(double a) {
    //方法体
    }
    }

    public class MethodDemo {
    public static float fn(int a) {
    //方法体
    }
    public static int fn(int a , int b) {
    //方法体
    }
    }
  • 错误范例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class MethodDemo {
    public static void fn(int a) {
    //方法体
    }
    public static int fn(int a) { /*错误原因:重载与返回值无关*/
    //方法体
    }
    }

    public class MethodDemo01 {
    public static void fn(int a) {
    //方法体
    }
    }
    public class MethodDemo02 {
    public static int fn(double a) { /*错误原因:这是两个类的两个fn方法*/
    //方法体
    }
    }

7.6 方法的参数传递

7.6.1 传递基本类型

  • 测试代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.itheima.param;

    public class Test1 {
    /*
    方法参数传递为基本数据类型 :

    传入方法中的, 是具体的数值.
    */
    public static void main(String[] args) {
    int number = 100;
    System.out.println("调用change方法前:" + number);
    change(number);
    System.out.println("调用change方法后:" + number);
    }

    public static void change(int number) {
    number = 200;
    }
    }


  • 结论:

    • 基本数据类型的参数,形式参数的改变,不影响实际参数
  • 结论依据:

    • 每个方法在栈内存中,都会有独立的栈空间,方法运行结束后就会弹栈消失

7.6.2 传递引用类型

  • 测试代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.itheima.param;

    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;
    }
    }
  • 结论:

    • 引用类型的参数,形式参数的改变,影响实际参数的值
  • 结论依据:

    • 引用数据类型的传参,传入的是地址值,内存中会造成两个引用指向同一个内存的效果,所以即使方法弹栈,堆内存中的数据也已经是改变后的结果

8.进制

    十进制:Java中,数值默认都是10进制,不需要加任何修饰。
    二进制:数值前面以0b开头,b大小写都可以。
    八进制:数值前面以0开头。
    十六进制:数值前面以0x开头,x大小写都可以。

    注意: 书写的时候, 虽然加入了进制的标识, 但打印在控制台展示的都是十进制数据。

8.1 十进制到任意进制的转换

  • 十进制——>二进制

1590936221838

  • 十进制——>十六进制

1590936342865

结论:十进制到任意进制的转换

公式:除基取余使用源数据,不断的除以基数(几进制,基数就是几)得到余数,直到商为0,再将余数倒着 拼起来即可

8.2 原码、补码、反码

**原码 **:就是二进制定点表示法,即最高位为符号位,【0】表示正,【1】表示负,其余位表示数值的大小。

1590936726746

若符号为为0,则原、反、补一样;

若符号为为1,则,符号为不变,最后面的1以及后面的位保持不变,其余为取反;

8.3 位运算

先将十进制数转成二进制后再进行运算。在二进制位运算中,1表示true,0表示false。

8.3.1 位运算符介绍 :

1590937235620

8.3.2 示例代码

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
package com.itheima.demo;

public class Demo2 {
/*
位运算:

位运算符指的是二进制位的运算,先将十进制数转成二进制后再进行运算。
在二进制位运算中,1表示true,0表示false。

& 位与 : 遇false则false, 遇0则0

00000000 00000000 00000000 00000110 // 6的二进制
& 00000000 00000000 00000000 00000010 // 2的二进制
-----------------------------------------
00000000 00000000 00000000 00000010 // 结果: 2

| 位或 : 遇true则true, 遇1则1

^ 位异或 : 相同为false, 不同为true

~ 取反 : 全部取反, 0变1, 1变0 (也包括符号位)

00000000 00000000 00000000 00000110 // 6的二进制补码
~ 11111111 11111111 11111111 11111001

- 1 // -1求反码
------------------------------------
11111111 11111111 11111111 11111000 // 反码推原码

10000000 00000000 00000000 00000111 // -7
*/
public static void main(String[] args) {
System.out.println(6 & 2);
System.out.println(~6);
}
}
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
package com.itheima.demo;

public class Demo3 {
/*
位移运算符:

<< 有符号左移运算,二进制位向左移动, 左边符号位丢弃, 右边补齐0
运算规律: 向左移动几位, 就是乘以2的几次幂

12 << 2

(0)0000000 00000000 00000000 000011000 // 12的二进制

-----------------------------------------------------------------------------
>> 有符号右移运算,二进制位向右移动, 使用符号位进行补位
运算规律: 向右移动几位, 就是除以2的几次幂

000000000 00000000 00000000 0000001(1) // 3的二进制

-----------------------------------------------------------------------------

>>> 无符号右移运算符, 无论符号位是0还是1,都补0

010000000 00000000 00000000 00000110 // -6的二进制

*/
public static void main(String[] args) {
System.out.println(12 << 1); // 24
System.out.println(12 << 2); // 48

}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.itheima.demo;

public class Demo4 {
/*
^ 运算符的特点

一个数, 被另外一个数, 异或两次, 该数本身不变
*/
public static void main(String[] args) {
System.out.println(10 ^ 5 ^ 10);
}
}

9.二维数组概述

概述 : 二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器

9.1 二维数组动态初始化

1
2
3
4
动态初始化格式:
数据类型[][] 变量名 = new 数据类型[m][n];
m表示这个二维数组,可以存放多少个一维数组
n表示每一个一维数组,可以存放多少个元素
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
package com.itheima.demo;

public class Demo1Array {
/*
动态初始化格式:

数据类型[][] 变量名 = new 数据类型[m][n];
m表示这个二维数组,可以存放多少个一维数组
n表示每一个一维数组,可以存放多少个元素
*/
public static void main(String[] args) {
// 数据类型[][] 变量名 = new 数据类型[m][n];
int[][] arr = new int[3][3];
/*
[[I@10f87f48

@ : 分隔符
10f87f48 : 十六进制内存地址
I : 数组中存储的数据类型
[[ : 几个中括号就代表的是几维数组
*/
System.out.println(arr);

/*
二维数组存储一维数组的时候, 存储的是一维数组的内存地址
*/
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);

System.out.println(arr[0][0]);
System.out.println(arr[1][1]);
System.out.println(arr[2][2]);

// 向二维数组中存储元素
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;

// 从二维数组中取出元素并打印
System.out.println(arr[0][0]);
System.out.println(arr[0][1]);
System.out.println(arr[0][2]);
System.out.println(arr[1][0]);
System.out.println(arr[1][1]);
System.out.println(arr[1][2]);
System.out.println(arr[2][0]);
System.out.println(arr[2][1]);
System.out.println(arr[2][2]);
}
}

9.2 二维数组访问元素的细节问题

问题 : 二维数组中存储的是一维数组, 那能不能存入 [提前创建好的一维数组] 呢 ?

答 : 可以的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.itheima.demo;

public class Demo2Array {
/*
问题: 二维数组中存储的是一维数组, 那能不能存入 [提前创建好的一维数组] 呢 ?
答 : 可以的
*/
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]);
}
}

9.3 二维数组静态初始化

 完整格式 : 数据类型[][] 变量名 = new 数据类型[][]{ {元素1, 元素2...} , {元素1, 元素2...} 
 
 简化格式 :  数据类型[][] 变量名 = { {元素1, 元素2...} , {元素1, 元素2...} ...};

代码实现 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itheima.demo;

public class Demo3Array {
/*
完整格式:数据类型[][] 变量名 = new 数据类型[][]{ {元素1, 元素2...} , {元素1, 元素2...} ...};

简化格式: 数据类型[][] 变量名 = { {元素1, 元素2...} , {元素1, 元素2...} ...};
*/
public static void main(String[] args) {
int[] arr1 = {11,22,33};
int[] arr2 = {44,55,66};

int[][] arr = {{11,22,33}, {44,55,66}};
System.out.println(arr[0][2]);

int[][] array = {arr1,arr2};
System.out.println(array[0][2]);
}
}

10.递归

递归的介绍:

  • 以编程的角度来看,递归指的是方法定义中调用方法本身的现象
  • 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
  • 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算

递归的基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//案例需求:	用递归求5的阶乘,并把结果在控制台输出
public class DiGuiDemo01 {
public static void main(String[] args) {
//调用方法
int result = jc(5);
//输出结果
System.out.println("5的阶乘是:" + result);
}

//定义一个方法,用于递归求阶乘,参数为一个int类型的变量
public static int jc(int n) {
//在方法内部判断该变量的值是否是1
if(n == 1) {
//是:返回1
return 1;
} else {
//不是:返回n*(n-1)!
return n*jc(n-1);
}
}
}

内存图:

递归内存图

递归的注意事项:

  • 递归一定要有出口。否则内存溢出
  • 递归虽然有出口,但是递归的次数也不宜过多。否则内存溢出