Java学习(一)– Java基础

https://www.bilibili.com/video/BV1fh411y7R8/?spm_id_from=333.999.0.0&vd_source=594d36a0860080a36fe599e0b84e5fb2

一、Java概述

1.1 Java特性

  1. Java 语言是面向对象的(oop)

  2. Java 语言是健壮的。Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证

  3. Java 语言是跨平台性的。(即: 一个编译好的 .class 文件可以在多个系统下运行,这种特性称为跨平台)

    Java的跨平台性

  4. Java 语言是解释型的

    解释性语言:javascript, PHP, Java 编译性语言: c / c++

    区别是:解释性语言,编译后的代码,不能直接被机器执行,需要解释器来执行, 编译性语言, 编译后的代码, 可以直接被机器执行: c /c++


1.2 Java运行机制及过程

1.2.1 跨平台性

跨平台性

1.2.2 Java虚拟机 – JVM

JVM Java Virtual Machine

  1. JVM 是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指令,管理数据、内存、寄存器,包含在 JDK
  2. 对于不同的平台,有不同的虚拟机
  3. Java 虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行”

不同平台的不同虚拟机

1.2.3 Java开发工具包 – JDK

JDK Java Development Kit

  1. JDK = JRE + Java 的开发工具集(例如 Javac, Java 编译工具等)
  2. JDK 是提供给 Java 开发人员使用的,其中包含了 java 的开发工具,也包括了 JRE。所以安装了 JDK,就不用在单独安装 JRE 了

1.2.4 Java运行环境 – JRE

JRE Java Runtime Environment

  1. JRE = JVM + Java SE 标准类库 ( Java 的核心类库 )

  2. 包括 Java 虚拟机 ( JVM Java Virtual Machine ) 和 Java 程序所需的核心类库等,

    如果想要运行一个开发好的 Java 程序,计算机中只需要安装 JRE 即可


1.3 JDK的下载安装

本博客不包含此目的, 请自行百度


1.4 Java 快速入门

键入 main + Enter 快速生成 public static void main(String[] args) {}

1
2
3
4
5
6
7
8
//一个源文件中最多只能有一个 public 类, 其他类个数不限
//编译后, 每一个类都对应一个 .class 文件
public class Main {
// main 方法也可以写在非 public 类中
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

1.4.1 开发步骤

  1. 将 Java 代码编写到扩展名为 .java 的文件中
  2. 通过 javac 命令对该 java 文件进行编译,生成 .class 文件
  3. 通过 java 命令对生成的 class 文件进行运行

1.4.2 运行原理

运行原理

1.4.3 执行流程

执行流程

1.4.4 细节说明

  1. Java 源文件扩展名为 .java, 源文件基本组成部分是类 (class)
  2. Java 程序入口是 main() 方法, 书写格式固定: public static void main(String[] args) {}
  3. Java 严格区分大小写
  4. 每个语句以 ; 结束
  5. 注意大括号 {}
  6. 一个源文件中只能有 1 个 public 类, 其他类个数不限
  7. 如果源文件中有一个 public 类, 则源文件名要与 public 类名相同
  8. 可以将 main 方法写在 非 public 类 中, 运行非 public 类, 入口见就是非 public 类中的 main 方法

1.5 快速学会 Java

快速学会Java


1.6 Java 转义字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
public static void main(String[] args) {
//\t :一个制表位,实现对齐的功能
System.out.println("北京\t 天津\t 上海");
// \n :换行符
System.out.println("jack\nsmith\nmary");
// \\ :一个\ \\
System.out.println("C:\\Windows\\System32\\cmd.exe");
// \" :一个"
System.out.println("老韩说:\"要好好学习 java,有前途\"");
// \' :一个'
System.out.println("老韩说:\'要好好学习 java,有前途\'");
// \r :一个回车
System.out.println("韩顺平教育\r 北京");
}
}

1.7 Java 注释

键入 /** + Enter 快速生成文档注释

键入 sout 快速生成 System.out.println();

文档注释不能随便写, 只能使用 Javadoc标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author 月华.
* @version 1.0
*/
public class Main {
//编写一个 main 方法
public static void main(String[] args) {
//单行注释
//选中,然后输入 tab 整体右移
//选中,然后输入 shift+tab 整体左移
/* 多行注释
多行注释里面不允许有多行注释嵌套
*/
int n1 = 10;
int n2 = 30;
//求和
int sum = n1 + n2;
//输出结果
System.out.println("结果=" + sum);
}
}

Javadoc标签:

标签 描述 示例
@author 标识一个类的作者 @author description
@deprecated 指名一个过期的类或成员 @deprecated description
{@docRoot} 指明当前文档根目录的路径 Directory Path
@exception 标志一个类抛出的异常 @exception exception-name explanation
{@inheritDoc} 从直接父类继承的注释 Inherits a comment from the immediate surperclass.
{@link} 插入一个到另一个主题的链接 {@link name text}
{@linkplain} 插入一个到另一个主题的链接,但是该链接显示纯文本字体 Inserts an in-line link to another topic.
@param 说明一个方法的参数 @param parameter-name explanation
@return 说明返回值类型 @return explanation
@see 指定一个到另一个主题的链接 @see anchor
@serial 说明一个序列化属性 @serial description
@serialData 说明通过writeObject( ) 和 writeExternal( )方法写的数据 @serialData description
@serialField 说明一个ObjectStreamField组件 @serialField name type description
@since 标记当引入一个特定的变化时 @since release
@throws 和 @exception标签一样. The @throws tag has the same meaning as the @exception tag.
{@value} 显示常量的值,该常量必须是static属性。 Displays the value of a constant, which must be a static field.
@version 指定类的版本 @version info

1.8 DOC 命令

1.8.1 DOC 基本原理

DOC基本原理

1.8.2 相对路径 & 绝对路径

相对路径 & 绝对路径

1.8.3 常用 DOC 命令

  • dir : 查看当前目录有什么内容
  • cd : 切换目录、盘符、上一级、根目录 – cd /D c: cd d:\abc\test cd .. cd \
  • tree : 查看目录树
  • cls : 清屏
  • exit : 退出 DOS
  • md : 创建目录
  • rd : 删除目录
  • copy : 拷贝文件
  • del : 删除文件
  • echo : 输入内容到文件
  • move : 剪切

二、变量

2.1 底层原理

在内存中开辟一个地址, 将变量放在此地址, 地址指向变量的值

变量基本原理


2.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
public class Main {
public static void main(String[] args) {
//记录人的信息
int age = 30;
double score = 88.9;
char gender = '男';
String name = "king";
//输出信息, 快捷键
System.out.println("人的信息如下:");
System.out.println(name);
System.out.println(age);
System.out.println(score);
System.out.println(gender);

//变量必须先声明,后使用, 即有顺序
int a = 50;//int
System.out.println(a);//50
//该区域的数据/值可以在同一类型范围内不断变化
//a = "jack"; //错
a = 88; //对
System.out.println(a);//88
//变量在同一个作用域内不能重名
//int a = 77;//错误
}
}

class Dog {
public static void main(String[] args) {
int a = 666;//对
}
}

2.3 程序中的 +

  1. 当左右两边都是数值类型, 做加法运算
  2. 当左右两边有一个是字符串, 做拼接运算
  3. 运算顺序: 从左到右
1
2
3
4
5
6
7
8
public class Main {
public static void main(String[] args) {
System.out.println(100 + 98); //198
System.out.println("100" + 98); //10098
System.out.println(100 + 3 + "hello"); //103hello
System.out.println("hello" + 100 + 3); //hello1003
}
}

2.4 基本数据类型

整数类型

  • byte[1]
  • short[2]
  • int[4]
  • long[8]

浮点型

  • float[4]
  • double[8]

字符型

  • char[2]

布尔型

  • boolean[1]

2.5 整数类型

  • Java 整数类型有固定的范围和字段长度, 不受 OS 影响, 保证 Java 的可移植性
  • Java 中整型常量默认为 int, 声明 long 时后面加 lL
  • 一般声明 int, 除非太大才用 long
  • 1 byte = 8 bit
类型 占用存储空间 范围
byte [字节] 1 字节 -128 ~127
short [短整型] 2 字节 -(2^15) ~ 2^15 - 1
-32768 ~ 32767
int [整型] 4 字节 -2^31 ~ 2^31 - 1
-2147483648 ~ 2147483647
long [长整型] 8 字节 -2^63 ~ 2^63 - 1
1
2
3
4
5
6
7
8
public class Main {
public static void main(String[] args) {
//Java 的整型常量(具体值)默认为 int 型,声明 long 型常量须后加‘l’或‘L’
int n1 = 1;//4 个字节
//int n2 = 1L;//不对
long n3 = 1L;//对
}
}

2.6 浮点类型

  • 关于浮点数在机器中存放形式的简单说明, 浮点数 = 符号位 + 指数位 + 尾数位
  • 尾数部分可能丢失,造成精度损失 (小数都是近似值)
  • Java 浮点类型也有固定的范围和字段长, 不受 OS 影响
  • Java 浮点型常量默认为 double, 声明 float 需要在后面加 fF
类型 占用存储空间 范围
float [单精度] 4 字节 -3.403E38 ~ 3.403E38
double [双精度] 8 字节 -1.798E308 ~ 1.798E308
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
public class Main {
public static void main(String[] args) {
//Java 的浮点型常量(具体值)默认为 double 型,声明 float 型常量,须后加‘f’或‘F'
// float num1 = 1.1; //错
float num2 = 1.1F; //对
double num3 = 1.1; //对
double num4 = 1.1f; //对

//十进制数形式:如:5.12 512.0f .512 (必须有小数点)
double num5 = .123; //等价 0.123
System.out.println(num5);

//科学计数法形式:如:5.12e2 [5.12 * 10 的 2 次方 ] 5.12E-2 [5.12 * 10 的 -2 次方]
System.out.println(5.12e2);//512.0
System.out.println(5.12E-2);//0.0512

//通常情况下,应该使用 double 型,因为它比 float 型更精确。
//[举例说明]double num9 = 2.1234567851;float num10 = 2.1234567851F;
double num9 = 2.1234567851;
float num10 = 2.1234567851F;
System.out.println(num9); //2.1234567851
System.out.println(num10); //2.1234567

//浮点数使用陷阱: 2.7 和 8.1 / 3 比较
double num11 = 2.7;
double num12 = 8.1 / 3; //2.7?
System.out.println(num11);//2.7
System.out.println(num12);//接近 2.7 的一个小数,而不是 2.7
//得到一个重要的使用点: 当我们对运算结果是小数的进行相等判断是,要小心
//应该是以两个数的差值的绝对值,在某个精度范围类判断
if( num11 == num12) {
System.out.println("num11 == num12 相等"); //未输出
}
//正确的写法
//Math.abs()表示取绝对值
if(Math.abs(num11 - num12) < 0.000001 ) {
System.out.println("差值非常小,到我的规定精度,认为相等...");
}
System.out.println(Math.abs(num11 - num12));
//细节:如果是直接查询得的的小数或者直接赋值,是可以判断相等
double num13 = 2.7;
double num14 = 2.7;
if( num13 == num14) {
System.out.println("num13 == num14 相等"); //输出
}
}
}

2.7 字符类型

字符类型可以表示单个字符,字符类型是 charchar 是两个字节(可以存放汉字),多个字符我们用字符串 String

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
public class Main {
public static void main(String[] args) {
//字符常量是用 '' 单引号引起来的

//在 java 中,char 的本质是一个整数,在默认输出时,是 unicode 码对应的字符
//要输出对应的数字,可以(int)字符
char c1 = 97;
System.out.println(c1); // a
char c2 = 'a'; //输出'a' 对应的 数字
System.out.println((int)c2);
char c3 = '韩';
System.out.println((int)c3);//38889
char c4 = 38889;
System.out.println(c4);//韩

//char 类型是可以进行运算的,相当于一个整数,因为它都对应有 Unicode 码. System.out.println('a' + 10);//107
char c5 = 'b' + 1;//98+1==> 99
System.out.println((int)c5); //99
System.out.println(c5); //99->对应的字符->编码表 ASCII(规定好的)=>c
/*
在内存中:
存储: 'a' ===> 97 ===> 二进制(110001) ===> 存储
读取: 二进制(110001) ===> 97 ===> 'a' ===> 显示
*/

//Java中允许使用转义字符作为字符
char c6 = '\t';
}
}

2.8 布尔类型

  • 只允许 truefalse , 不允许使用 0 或 非0 来取代 (与 C语言 不一样)
  • boolean 类型占 1 个字节
1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
public static void main(String[] args) {
//演示判断成绩是否通过的案例
//定义一个布尔变量
boolean isPass = true;//
if(isPass == true) {
System.out.println("考试通过,恭喜");
} else {
System.out.println("考试没有通过,下次努力");
}
}
}

2.9 字符编码表

ASCII 一个字节表示, 共 128 个字符, 实际可以用 256 个, 只用了 128 个

  • 缺点: 不能表示所有字符

ASCII控制字符

ASCII可显示字符

Unicode 使用两个字节表示字符, 汉子与字母都是两个字节, 兼容 ASCII 码

  • 优点: 没有乱码问题, 世界上所有符号都有编码
  • 缺点: 浪费空间

uft-8 Unicoude 的改进, 字母使用 1 个字节, 汉字使用 3 个字节

  • 优点: 大小可变, 使用 1-6个字节表示一个符号, 根据不同的符号而变化字节长度

2.10 Java API 文档

Java类的组织形式


2.11 基本数据类型自动转换

  • 进行赋值或运算时, 精度小的类型会自动转为精度大的类型

自动类型转换

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
public class Main {
public static void main(String[] args) {
//细节 1: 有多种类型的数据混合运算时,
//系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算
int n1 = 10; //ok
//float d1 = n1 + 1.1;//错 n1 + 1.1 => 结果类型是 double
//double d1 = n1 + 1.1;//对 n1 + 1.1 => 结果类型是 double
float d1 = n1 + 1.1F;//对 n1 + 1.1 => 结果类型是 float

//细节 2: 当我们把精度(容量)大 的数据类型赋值给精度(容量)小 的数据类型时,
//就会报错,反之就会进行自动类型转换。
//int n2 = 1.1;//错误 double -> int

//细节 3: (byte, short) 和 char 之间可以计算, 但是不会相互自动转换
// char c1 = b1; //错误, 原因 byte 不能自动转成 char

//(1)当把具体数赋给 byte 时,先判断该数是否在 byte 范围内,如果是就可以
byte b1 = 10; //对 , -128 ~ 127
// int n2 = 1; //n2 是 int
//(2)如果是变量赋值,判断类型
// byte b2 = n2; //错


//细节 4: byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型
byte b2 = 1;
byte b3 = 2;
short s1 = 1;
//short s2 = b2 + s1;//错, b2 + s1 => int
int s2 = b2 + s1;//对, b2 + s1 => int
//byte b4 = b2 + b3; //错误: b2 + b3 => int

//细节5: boolean 不参与转换
boolean pass = true;
//int num100 = pass;// boolean 不参与类型的自动转换

//细节6: 自动提升原则: 表达式结果的类型自动提升为 操作数中最大的类型
//看一道题
byte b4 = 1;
short s3 = 100;
int num200 = 1;
float num300 = 1.1F;
double num500 = b4 + s3 + num200 + num300; //float -> double
}
}

2.12 基本数据类型自动转换

  • 自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型

    使用时要加上强制转换符 ( ),但可能造成精度降低或溢出,格外要注意

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
public static void main(String[] args) {
//当数据大小 从 大->小, 就需要强制转换

//细节1: 强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
//int x = (int)10*3.5+6*1.5;//编译错误: double -> int
int x = (int)(10*3.5+6*1.5);// (int)44.0 -> 44
System.out.println(x);//44
char c1 = 100; //ok
int m = 100; //ok

//细节2: char类型可以保存int的常量值, 但是不能保存int的变量值, 需要强转
//char c2 = m; //错误
char c3 = (char)m; //ok
System.out.println(c3);//100 对应的字符, d 字符

//细节3: byte和short, char类型在运算时, 当做int类型处理
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
判断是否能够通过编译
1. short s = 12; //ok
s= s-9; //错误int -> short
2. byteb = 10; //ok
b = b+11; //错误int-> byte
b = (byte)(b+11); //正确,使用强转
3. char c = 'a'; //ok
int i = 16; //ok
floatd = .314F; //ok
double result = c + i + d; //ok float- > double
4. byte b = 16; //ok
short s = 14; //ok
short t = S + b; //错误int -> short

2.13 基本数据类型和 String 类型的转换

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
public class Main {
public static void main(String[] args) {
//基本数据类型->String
int n1 = 100;
float f1 = 1.1F;
double d1 = 4.5;
boolean b1 = true;
String s1 = n1 + "";
String s2 = f1 + "";
String s3 = d1 + "";
String s4 = b1 + "";
System.out.println(s1 + " " + s2 + " " + s3 + " " + s4);

//String->对应的基本数据类型
String s5 = "123";
//会在 OOP 讲对象和方法的时候回详细
//解读 使用 基本数据类型对应的包装类,的相应方法,得到基本数据类型
int num1 = Integer.parseInt(s5);
double num2 = Double.parseDouble(s5);
float num3 = Float.parseFloat(s5);
long num4 = Long.parseLong(s5);
byte num5 = Byte.parseByte(s5);
boolean b = Boolean.parseBoolean("true");
short num6 = Short.parseShort(s5);
System.out.println("===================");
System.out.println(num1);//123
System.out.println(num2);//123.0
System.out.println(num3);//123.0
System.out.println(num4);//123
System.out.println(num5);//123
System.out.println(num6);//123
System.out.println(b);//true

//怎么把字符串转成字符 char --> 其含义是把字符串的 第一个字符 转成 char (只有第一个字符这一个字符)
//解读 s5.charAt(0) 得到 s5 字符串的第一个字符 '1'
System.out.println(s5.charAt(0));

//在将 String 类型转成 基本数据类型时,要确保 String 能转成有效的数据类型,
// 比如 我们可以把 "123" , 转成一个整数,但是不能把 "hello" 转成一个整数
String str = "hello";
//转成 int
int n10 = Integer.parseInt(str); //抛出异常,程序就会终止
System.out.println(n1);
}
}

三、运算符

3.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
25
26
27
28
29
30
31
32
33
34
35
36
public class Main {
public static void main(String[] args) {

// /使用
System.out.println(10 / 4); //从数学来看是 2.5, java 中 2
System.out.println(10.0 / 4); //java 是 2.5
// 注释快捷键 ctrl + /, 再次输入 ctrl + / 取消注释
double d = 10 / 4;//java 中 10 / 4 = 2, 2=>2.0
System.out.println(d);// 是 2.0

// % 取模 ,取余
// 在 % 的本质 看一个公式!!!! a % b = a - a / b * b !!!!
// -10 % 3 => -10 - (-10) / 3 * 3 = -10 + 9 = -1
// 10 % -3 = 10 - 10 / (-3) * (-3) = 10 - 9 = 1
// -10 % -3 = (-10) - (-10) / (-3) * (-3) = -10 + 9 = -1
System.out.println(10 % 3); //1
System.out.println(-10 % 3); // -1
System.out.println(10 % -3); //1
System.out.println(-10 % -3);//-1

//++的使用
int i = 10;
i++;//自增 等价于 i = i + 1; => i = 11
++i;//自增 等价于 i = i + 1; => i = 12
System.out.println("i=" + i);//12
/*
作为表达式使用
前++:++i 先自增后赋值
后++:i++先赋值后自增
*/
int j = 8;
//int k = ++j; //等价 j=j+1;k=j;
int k = j++; // 等价 k =j;j=j+1;
System.out.println("k=" + k + "j=" + j);//8 9
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Main {
public static void main(String[] args) {

// 下面这段是重点
int i1 = 1;//i->1
i1 = i++; //规则使用临时变量: (1) temp=i;(2) i=i+1;(3)i=temp;
System.out.println(i1); // 1

int i2 = 1;
i2 = ++i2; //规则使用临时变量: (1) i=i+1;(2) temp=i;(3)i=temp;
System.out.println(i2); //2

// 测试输出
int i3 = 10;
int i4 = 20;
int i = i3++;
System.out.print("i=" + i);//10
System.out.println("i2=" + i4);//20
i = --i4;
System.out.print("i=" + i);//19
System.out.println("i2=" + i4);//19
}
}
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
public class Main {
public static void main(String[] args) {
//1.需求:
//假如还有 59 天放假,问:合 xx 个星期零 xx 天
//2.思路分析
//(1) 使用 int 变量 days 保存 天数
//(2) 一个星期是 7 天 星期数 weeks: days / 7 零 xx 天 leftDays days % 7
//(3) 输出
//3.走代码
int days = 25911;
int weeks = days / 7;
int leftDays = days % 7;
System.out.println(days + "天 合" + weeks + "星期零" + leftDays + "天");

//1.需求
//定义一个变量保存华氏温度,华氏温度转换摄氏温度的公式为
//:5/9*(华氏温度-100),请求出华氏温度对应的摄氏温度
//2 思路分析
//(1) 先定义一个 double huaShi 变量保存 华氏温度
//(2) 根据给出的公式,进行计算即可 5/9*(华氏温度-100)
// 考虑数学公式和 java 语言的特性
//(3) 将得到的结果保存到 double sheShi
//3 走代码
double huaShi = 1234.6;
double sheShi = 5.0 / 9 * (huaShi - 100); //注意是 5.0
System.out.println("华氏温度" + huaShi + " 对应的摄氏温度=" + sheShi);
}
}

3.2 关系(比较)运算符

  1. 关系运算符的结果都是 boolean 型,也就是要么是 true,要么是 false
  2. 关系表达式 经常用在 if 结构的条件中或循环结构的条件中

关系运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
public static void main(String[] args) {
int a = 9;
int b = 8;
//关系运算符组成的表达式,我们称为关系表达式。 a > b
System.out.println(a > b); //T
System.out.println(a >= b); //T
System.out.println(a <= b); //F
System.out.println(a < b);//F
//比较运算符"=="不能误写成"="
System.out.println(a == b); //F
System.out.println(a != b); //T
boolean flag = a > b; //T
System.out.println("flag=" + flag);
}
}

3.3 逻辑运算符

用于连接多个条件(多个关系表达式),最终的结果也是一个 boolean 值。

逻辑运算符

  1. a&b : & 叫逻辑与: 规则:当 a 和 b 同时为 true ,则结果为 true, 否则为 false

  2. a&&b : && 叫短路与:规则:当 a 和 b 同时为 true ,则结果为 true,否则为 false

  3. a|b : | 叫逻辑或, 规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false

  4. a||b : || 叫短路或,规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false

  5. !a : 叫取反,或者非运算。当 a 为 true, 则结果为 false; 当 a 为 false 是,结果为 true

  6. a^b: 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false

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
public class Main {
public static void main(String[] args) {
//&&短路与 和 & 案例演示
int age = 50;
if(age > 20 && age < 90) {
System.out.println("ok100");
}
//&逻辑与使用
if(age > 20 & age < 90) {
System.out.println("ok200");
}
//区别
int a = 4;
int b = 9;
//对于&&短路与而言,如果第一个条件为 false ,后面的条件不再判断
//对于&逻辑与而言,如果第一个条件为 false ,后面的条件仍然会判断
if(a < 1 & ++b < 50) {
System.out.println("ok300");
}
System.out.println("a=" + a + " b=" + b);// 4 10
// &&短路与:如果第一个条件为 false,则第二个条件不会判断,最终结果为 false,效率高
// & 逻辑与:不管第一个条件是否为 false,第二个条件都要判断,效率低
// 开发中, 使用的基本是使用短路与&&, 效率高

// ||短路或 和 |逻辑或 案例演示
// || 规则: 两个条件中只要有一个成立,结果为 true,否则为 false
// | 规则: 两个条件中只要有一个成立,结果为 true,否则为 false
int age = 50;
if(age > 20 || age < 30) {
System.out.println("ok100");
}
// &逻辑与使用
if(age > 20 | age < 30) {
System.out.println("ok200");
}
//看看区别
//(1)||短路或:如果第一个条件为 true,
//则第二个条件不会判断,最终结果为 true,效率高
//(2)| 逻辑或:不管第一个条件是否为 true,第二个条件都要判断,效率低
int a = 4;
int b = 9;
if( a > 1 || ++b > 4) { // 可以换成 | 测试
System.out.println("ok300");
}
System.out.println("a=" + a + " b=" + b); //4 10

// ! 取反操作演示
//! 操作是取反 T->F , F -> T
System.out.println(60 > 20); //T
System.out.println(!(60 > 20)); //F
//a^b: 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false
boolean b = (10 > 1) ^ ( 3 > 5);
System.out.println("b=" + b);//T

// a^b: 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false
System.out.println( (4 < 1) ^ (6 > 3) ); // true
}
}

3.4 赋值运算符

  • 基本赋值运算符 =
  • 复合赋值运算符 += ,-= ,*= , /= ,%=
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Main {
public static void main(String[] args) {
// 运算顺序从右往左 int num = a + b + c;
// 赋值运算符的左边 只能是变量; 右边 可以是变量、表达式、常量值
int num = 20; int num2= 78 * 34 - 10; int num3 = a;
// 复合赋值运算符等价于下面的效果
// 比如:a+=3;等价于 a=a+3; 其他类推
// 复合赋值运算符会进行类型转换。
int n1 = 10;
n1 += 4;// n1 = n1 + 4;
System.out.println(n1); // 14
n1 /= 3;// n1 = n1 / 3;//4
System.out.println(n1); // 4
//复合赋值运算符会进行类型转换
byte b = 3;
// byte b = 2; b+=3; b++;
b += 2; // 等价 b = (byte)(b + 2);
b++; // b = (byte)(b+1);
}
}

3.5 三元运算符

条件表达式 ? 表达式 1: 表达式 2

  1. 如果条件表达式为 true,运算后的结果是表达式 1;

  2. 如果条件表达式为 false,运算后的结果是表达式 2;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main {
public static void main(String[] args) {
int a = 10;
int b = 99;
// 解读
// 1. a > b 为 false
// 2. 返回 b--, 先返回 b 的值,然后在 b-1
// 3. 返回的结果是 99
int result = a > b ? a++ : b--;
System.out.println("result=" + result);
System.out.println("a=" + a);
System.out.println("b=" + b);

//表达式 1 和表达式 2 要为可以赋给接收变量的类型
//(或可以自动转换/或者强制转换)
int c = 3;
int d = 8;
int e = c > d ? (int)1.1 : (int)3.4;//可以的
double f = c > d ? c : d + 3;//可以的,满足 int -> double
}
}
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
public class Main {
public static void main(String[] args) {
//案例:实现三个数的最大值
int n1 = 553;
int n2 = 33;
int n3 = 123;
//思路
//1. 先得到 n1 和 n2 中最大数 , 保存到 max1
//2. 然后再 求出 max1 和 n3 中的最大数,保存到 max2
int max1 = n1 > n2 ? n1 : n2;
int max2 = max1 > n3 ? max1 : n3;
System.out.println("最大数=" + max2);

//使用一条语句实现, 推荐使用上面方法
//提示: 后面我们可以使用更好方法,比如排序
// int max = (n1 > n2 ? n1 : n2) > n3 ?
// (n1 > n2 ? n1 : n2) : n3;
// System.out.println("最大数=" + max);
int abcclass = 10;
int n = 40;
int N = 50;
System.out.println("n=" + n);//40
System.out.println("N=" + N);//50
// abc 和 aBc 是两个不同变量
int abc = 100;
int aBc = 200;
//int a b = 300;
//int a-b=10;
int goto1 = 10;
}
}

3.6 运算符优先级

  • 只有单目运算符、赋值运算符是从右向左运算的

运算符优先级


3.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
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
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//演示接受用户的输入
//步骤
//Scanner 类 表示 简单文本扫描器,在 java.util 包
//1. 引入/导入 Scanner 类所在的包
//2. 创建 Scanner 对象 , new 创建一个对象,体会
// myScanner 就是 Scanner 类的对象
Scanner myScanner = new Scanner(System.in);
//3. 接收用户输入了, 使用 相关的方法
System.out.println("请输入名字");
//当程序执行到 next 方法时,会等待用户输入~~~
String name = myScanner.next(); //接收用户输入字符串
System.out.println("请输入年龄");
int age = myScanner.nextInt(); //接收用户输入 int
System.out.println("请输入薪水");
double sal = myScanner.nextDouble(); //接收用户输入 double
System.out.println("人的信息如下:");
System.out.println("名字=" + name + " 年龄=" + age + " 薪水=" + sal);

/*
nextLine()用法总结:
1、以回车符作为结束标识符,获取到的是回车符前输入的所有字符串(包括空格)。
2、读取结束后,该方法会将我们的鼠标定位在我们输入数据的那一行的下一行。
*/
String str = myScanner.nextLine(); //接收用户输入字符串, 以 回车符 作为结束符
/*
next()用法总结:
1. 一定要读取到有效字符后才可以结束输入。
2. 对输入的有效字符之前所遇到的空白,会自动将其去除。
3. 只有输入的有效字符后才将其后面输入的空白作为结束符。
4. next()不能得到带有空格的字符串。
5. 读取结束后,该方法会将我们的鼠标定位在我们输入数据的那一行。
*/
String str = myScanner.next(); //接收用户输入字符串, 以 空格符 作为结束符
/*
先使用nextLine()再使用next()、nextInt()等没问题,
但是先使用next()和nextInt()等之后就不可以再紧跟nextLine()使用。(这一点很重要!!!)

这是因为next()等这些方法读取结束后会紧跟一个回车符,
而nextLine会直接读取到这个回车符,
这就导致出现我们还没有来得及输入我们想要输入的数据,
nextLine就以为我们已经输入完了这样的情况!

解决办法也很简单:我们直接在next()使用后加两个nextLine()就OK了,
这样第一个nextLine()就会当一个‘替死鬼’,
第二个nextLine()我们就可以输入自己想要输入的数据啦!
*/

String str = myScanner.next().charAt(0);
byte a1= myScanner.nextByte(); //接收用户输入 byte
short a2= myScanner.nextShort(); //接收用户输入 short
int a3 = myScanner.nextInt(); //接收用户输入 int
long a4 = myScanner.nextLong(); //接收用户输入 long
float a5 = myScanner.nextFloat(); //接收用户输入 float
double a6 = myScanner.nextDouble(); //接收用户输入 double
boolean a7 = myScanner.nextBoolean(); //接收用户输入 boolean


//使用完Scanner后,一定要记得将它关闭!
//因为使用Scanner本质上是打开了一个IO流,如果不关闭的话,它将会一直占用系统资源。
sc.close();
//但是一旦关闭后,就算在sc.close()这行代码后你再重新new Scanner(System.in),
//那也不能重新再打开一个扫描器了,程序会报错
//所以一定要在用不到扫描器之后再关闭,即把sc.close()代码放到最后。
}
}

3.8 进制

  • 二进制:0,1 ,满 2 进 1.以 0b 或 0B 开头。
  • 十进制:0-9 ,满 10 进 1。
  • 八进制:0-7 ,满 8 进 1. 以数字 0 开头表示。
  • 十六进制:0-9 及 A(10)-F(15),满 16 进 1. 以 0x 0X 开头表示。此处的 A-F 不区分大小写

3.8.1 各种进制转十进制

  • 二 转 十

从最低位 (右边) 开始, 将每个位上的数提取出来, 乘以 2 的 (位数 - 1)次方, 然后求和

  • 八 转 十

从最低位 (右边) 开始, 将每个位上的数提取出来, 乘以 8 的 (位数 - 1)次方, 然后求和

  • 十六 转 十

从最低位 (右边) 开始, 将每个位上的数提取出来, 乘以 16 的 (位数 - 1)次方, 然后求和

3.8.2 十进制转各种进制

短除

  • 十 转 二

将该数不断除以 2, 直到商为 0 为止, 然后将每步得到的余数倒过来, 就是对应二进制

  • 十 转 八

将该数不断除以 8, 直到商为 0 为止, 然后将每步得到的余数倒过来, 就是对应八进制

  • 十 转 十六

将该数不断除以 16, 直到商为 0 为止, 然后将每步得到的余数倒过来, 就是对应十六进制

3.8.3 二进制转各种进制

  • 二 转 八

从低位开始,将二进制数每 3 位一组,转成对应的八进制数即可

  • 二 转 十六

从低位开始,将二进制数每 4 位一组,转成对应的十六进制数即可

3.8.4 各种进制转二进制

  • 八 转 二

将八进制数每 1 位,转成对应的一个 3 位的二进制数即可

  • 十六 转 二

将十六进制数每 1 位,转成对应的 4 位的一个二进制数即可


3.9 原码、反码、补码

对于有符号的而言:

  1. 二进制的最高位是符号位: 0表示正数,1表示负数
  2. 正数的原码,反码,补码都一样 (三码合一)
  3. 负数的反码 = 它的原码符号位不变,其它位取反(0->1,1->0)
  4. 负数的补码 = 它的反码 + 1,负数的反码 = 负数的补码 - 1
  5. 0的反码,补码都是0
  6. java没有无符号数,换言之,java中的数都是有符号的
  7. 在计算机运算的时候,都是以补码的方式来运算的.
  8. 当我们看运算结果的时候,要看他的原码 (重点)

3.10 位运算符

  • 按位与 &: 两位全为 1 , 结果为 1 , 否则为 0
  • 按位或 |: 两位有一个为 1 , 结果为 1 , 否则为 0
  • 按位异或 ^: 两位一个为 0 , 一个为 1 , 结果为 1 , 否则为 0
  • 按位取反 ~: 0->1 ,1->0
  • 算术右移 >>:低位溢出, 符号位不变, 并用符号位补溢出的高位
  • 算术左移 <<: 符号位不变, 低位补 0
  • 逻辑右移 / 无符号右移 >>>: 低位溢出,高位补 0
  • 特别说明:没有 <<< 符号

四、程序控制结构

4.1 顺序控制

从上到下执行, 变量采取前向引用的格式

前向引用


4.2 分支控制

  • 如果判断的具体数值不多,而且符合 byte、 short 、int、 char, enum[枚举], String 这 6 种类型。虽然两个语句都可以使用,建议使用 swtich 语句
  • 其他情况:对区间判断,对结果为 boolean 类型判断,使用 if,if 的使用范围更广

4.2.1 if-else

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
// 单分支 if
import java.util.Scanner;//导入
public class If01 {

//编写一个main方法
public static void main(String[] args) {
//编写一个程序,可以输入人的年龄,如果该同志的年龄大于18岁,
//则输出 "你年龄大于18,要对自己的行为负责,送入监狱"
//
//思路分析
//1. 接收输入的年龄, 应该定义一个Scanner 对象
//2. 把年龄保存到一个变量 int age
//3. 使用 if 判断,输出对应信息

//应该定义一个Scanner 对象
Scanner myScanner = new Scanner(System.in);
System.out.println("请输入年龄");
//把年龄保存到一个变量 int age
int age = myScanner.nextInt();
//使用 if 判断,输出对应信息
if(age > 18) {
System.out.println("你年龄大于18,要对自己的行为负责,送入监狱");
}

System.out.println("程序继续...");


}
}
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
// 双分支 if-else
import java.util.Scanner;//导入
public class If02 {

//编写一个main方法
public static void main(String[] args) {
//编写一个程序,可以输入人的年龄,如果该同志的年龄大于18岁,
//则输出 "你年龄大于18,要对
//自己的行为负责, 送入监狱"。否则 ,输出"你的年龄不大这次放过你了."

//
//思路分析
//1. 接收输入的年龄, 应该定义一个Scanner 对象
//2. 把年龄保存到一个变量 int age
//3. 使用 if-else 判断,输出对应信息

//应该定义一个Scanner 对象
Scanner myScanner = new Scanner(System.in);
System.out.println("请输入年龄");
//把年龄保存到一个变量 int age
int age = myScanner.nextInt();
//使用 if-else 判断,输出对应信息
if(age > 18) {
System.out.println("你年龄大于18,要对自己的行为负责,送入监狱");
} else {//双分支
System.out.println("你的年龄不大这次放过你了");
}

System.out.println("程序继续...");


}
}
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
// 单分支和双分支的练习
//
public class IfExercise01 {

//编写一个main方法
public static void main(String[] args) {

//编写程序,声明2个double型变量并赋值。
//判断第一个数大于10.0,且第2个数小于20.0,打印两数之和

//思路分析

double d1 = 33.5;
double d2 = 2.6;
if(d1 > 10.0 && d2 < 20.0) {
System.out.println("两个数和=" + (d1 + d2));
}

//【课后自己练】定义两个变量int,判断二者的和,
//是否能被3又能被5整除,打印提示信息
//
//思路分析
//1. 定义两个变量int num1, num2
//2. 定义一个变量 int sum = num1 + num2;
//3. sum % 3 , 5 后 等于0 说明可以整除
//4. 使用 if - else 来提示对应信息
//走代码
int num1 = 10;
int num2 = 1;
int sum = num1 + num2;
if(sum % 3 == 0 && sum % 5 == 0) {
System.out.println("和可以被3又能被5整除");
} else {
System.out.println("和不能被3和5整除..");
}

//判断一个年份是否是闰年,闰年的条件是符合下面二者之一:
//(1)年份能被4整除,但不能被100整除;(2)能被400整除
//
//思路分析
//1. 定义 int year 保存年
//2. 年份能被4整除,但不能被100整除,
// => year % 4 == 0 && year % 100 != 0
//3. 能被400整除 => year % 400 == 0
//4. 上面的 2 和 3 是 或的关系
//代码实现
int year = 2028;
if( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ) {
System.out.println(year + " 是 闰年");
} else {
System.out.println(year + " 不是 闰年");
}
}
}
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
// 多分支 if-else if-else
import java.util.Scanner;
public class If03 {

//编写一个main方法
public static void main(String[] args) {
/*
输入保国同志的芝麻信用分:
如果:
信用分为100分时,输出 信用极好;
信用分为(80,99]时,输出 信用优秀;
信用分为[60,80]时,输出 信用一般;
其它情况 ,输出 信用 不及格
请从键盘输入保国的芝麻信用分,并加以判断
假定信用分数为int
*/

Scanner myScanner = new Scanner(System.in);
//接收用户输入
System.out.println("请输入信用分(1-100):");
//请思考:如果小伙伴输入的不是整数,而是hello..
//==>这里我们后面可以使用异常处理机制搞定-》老师点一下
int grade = myScanner.nextInt();

//先对输入的信用分,进行一个范围的有效判断 1-100, 否则提示输入错误

if(grade >=1 && grade <= 100) {
//因为有4种情况,所以使用多分支
if(grade == 100) {
System.out.println("信用极好");
} else if (grade > 80 && grade <= 99) { //信用分为(80,99]时,输出 信用优秀;
System.out.println("信用优秀");
} else if (grade >= 60 && grade <= 80) {//信用分为[60,80]时,输出 信用一般
System.out.println("信用一般");
} else {//其它情况 ,输出 信用 不及格
System.out.println("信用不及格");
}

} else {
System.out.println("信用分需要在1-100,请重新输入:)");
}

}
}
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
// 嵌套分支 (最好不要超过 3 层, 不然可读性不好)
import java.util.Scanner;
public class NestedIf {

//编写一个main方法
public static void main(String[] args) {
/*
参加歌手比赛,如果初赛成绩大于8.0进入决赛,
否则提示淘汰。并且根据性别提示进入男子组或女子组。
输入成绩和性别,进行判断和输出信息。
[NestedIf.java]

提示: double score; char gender;
接收字符: char gender = scanner.next().charAt(0)

*/
//思路分析
//1. 创建Scanner对象,接收用户输入
//2. 接收 成绩保存到 double score
//3. 使用 if-else 判断 如果初赛成绩大于8.0进入决赛,否则提示淘汰
//4. 如果进入到 决赛,再接收 char gender, 使用 if-else 输出信息
//代码实现 => 思路 --> java代码

Scanner myScanner = new Scanner(System.in);
System.out.println("请输入该歌手的成绩");
double score = myScanner.nextDouble();
if( score > 8.0 ) {
System.out.println("请输入性别");
char gender = myScanner.next().charAt(0);
if( gender == '男' ) {
System.out.println("进入男子组");
} else if(gender == '女') {
System.out.println("进入女子组");
} else {
System.out.println("你的性别有误,不能参加决赛~");
}
} else {
System.out.println("sorry ,你被淘汰了~");
}
}
}

4.2.2 switch

  1. switch 表达式的数据类型要与 case 后的常量类型一致, 或者是可以进行隐式转换 (表达式类型转常量类型) 的类型, 不然怎么比较
  2. switch 表达式的返回值必须是 byte, short, int, char, enum, String
  3. case 后的值必须是常量, 不能是变量
  4. default 可选, 但是必须加上
  5. 如果没有在 case 分支后写 break, 就会从当前分支一直执行到底, 除非中途碰到 break
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

import java.util.Scanner;
public class Switch01 {

//编写一个main方法
public static void main(String[] args) {
/*
案例:Switch01.java
请编写一个程序,该程序可以接收一个字符,比如:a,b,c,d,e,f,g
a表示星期一,b表示星期二 …
根据用户的输入显示相应的信息.要求使用 switch 语句完成

思路分析
1. 接收一个字符 , 创建Scanner对象
2. 使用switch 来完成匹配,并输出对应信息
代码

*/
Scanner myScanner = new Scanner(System.in);
System.out.println("请输入一个字符(a-g)");
char c1 = myScanner.next().charAt(0);//
//在java中,只要是有值返回,就是一个表达式
switch(c1) {
case 'a' :
System.out.println("今天星期一,猴子穿新衣");
break;
case 'b' :
System.out.println("今天星期二,猴子当小二");
break;
case 'c' :
System.out.println("今天星期三,猴子爬雪山..");
break;
//.....
default:
System.out.println("你输入的字符不正确,没有匹配的");

}

System.out.println("退出了switch ,继续执行程序");
}
}
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

public class SwitchDetail {

//编写一个main方法
public static void main(String[] args) {

//细节1
//表达式数据类型,应和case 后的常量类型一致,
//或者是可以自动转成可以相互比较的类型,比如输入的是字符,而常量是 int

//细节2
//switch(表达式)中表达式的返回值必须是:
//(byte,short,int,char,enum[枚举],String)

//细节3
//case子句中的值必须是常量(1,'a')或者是常量表达式,而不能是变量
//
//细节4
//default子句是可选的,当没有匹配的case时,执行default
//如果没有default 子句,有没有匹配任何常量,则没有输出
//
//细节5
//break语句用来在执行完一个case分支后使程序跳出switch语句块;
//如果没有写break,程序会顺序执行到switch结尾,除非执行到break
char c = 'b';
char c2 = 'c';
switch(c) {
case 'a' :
System.out.println("ok1");
break;
case 'b' :
System.out.println("ok2");
break;
default :
System.out.println("ok3");
}

System.out.println("退出了switch,继续执行..");
}
}
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

import java.util.Scanner;
public class SwitchExercise {

//编写一个main方法
public static void main(String[] args) {

//使用 switch 把小写类型的
//char型转为大写(键盘输入)。只转换 a->A, b->B, c, d, e.
//其它的输出 "other"。

//创建Scanner对象
// Scanner myScanner = new Scanner(System.in);
// System.out.println("请输入a-e");
// char c1 = myScanner.next().charAt(0);
// switch(c1) {
// case 'a' :
// System.out.println("A");
// break;
// case 'b' :
// System.out.println("B");
// break;
// case 'c' :
// System.out.println("C");
// break;
// case 'd' :
// System.out.println("D");
// break;
// case 'e' :
// System.out.println("E");
// break;
// default :
// System.out.println("你的输入有误~");

// }

//对学生成绩大于60分的,输出"合格"。低于60分的,
//输出"不合格"。(注:输入的成绩不能大于100), 提示 成绩/60
//思路分析
//1. 这道题,可以使用 分支来完成, 但是要求使用switch
//2. 这里我们需要进行一个转换, 编程思路 :
// 如果成绩在 [60,100] , (int)(成绩/60) = 1
// 如果成绩在 [0,60) , (int)(成绩/60) = 0

//代码实现

double score = 1.1;

//使用if-else 保证输入的成绩有有效的 0-100
//看了当老师的分析和代码演示后,自己一定要独立完成(不看老韩代码,也能写)
if( score >= 0 && score <= 100) {
switch ((int)(score / 60)) {
case 0 :
System.out.println("不合格");
break;
case 1 :
System.out.println("合格");
break;
// default :
// System.out.println("输入有误");
}
} else {
System.out.println("输入的成绩在0-100");
}

//根据用于指定月份,
//打印该月份所属的季节。
//3,4,5 春季 6,7,8 夏季 9,10,11 秋季 12, 1, 2 冬季
//[课堂练习, 提示 使用穿透 ]
//
//思路分析
//1. 创建Scanner对象, 接收用户输入
//2. 使用 int month 接收
//3. 使用switch 来匹配 ,使用穿透来完成,比较简洁

Scanner myScanner = new Scanner(System.in);
System.out.println("输入月份");
int month = myScanner.nextInt();
switch(month) {
case 3:
case 4:
case 5:
System.out.println("这是春季");
break;
case 6:
case 7:
case 8:
System.out.println("这是夏季");
break;
case 9:
case 10:
case 11:
System.out.println("这是秋季");
break;
case 1:
case 2:
case 12:
System.out.println("这是冬季");
break;
default :
System.out.println("你输入的月份不对(1-12)");
}


}
}

4.3 循环控制

4.3.1 for

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
public class ForDetail {

//编写一个main方法
public static void main(String[] args) {

//for(;循环判断条件;)
//中的初始化和变量迭代可以写到其它地方,但是两边的分号不能省略

// 使用for循环控制
// int i = 1;//循环变量初始化
// for( ; i <= 10 ; ) {
// System.out.println("hello,韩顺平教育" + i);
// i++;
// }

// System.out.println("i=" + i);//11 ok


// int j = 1;
// //补充
// for(;;) { //表示一个无限循环,死循环
// System.out.println("ok~" + (j++));
// }

//循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,
//循环变量迭代也可以有多条变量迭代语句,中间用逗号隔开
int count = 3;
for (int i = 0,j = 0; i < count; i++, j += 2) {
System.out.println("i=" + i + " j=" + j);
}

}
}
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


public class ForExercise {

//编写一个main方法
public static void main(String[] args) {
//打印1~100之间所有是9的倍数的整数,统计个数 及 总和.[化繁为简,先死后活]
//老韩的两个编程思想(技巧)
//1. 化繁为简 : 即将复杂的需求,拆解成简单的需求,逐步完成
//2. 先死后活 : 先考虑固定的值,然后转成可以灵活变化的值
//
//思路分析
//打印1~100之间所有是9的倍数的整数,统计个数 及 总和
//化繁为简
//(1) 完成 输出 1-100的值
//(2) 在输出的过程中,进行过滤,只输出9的倍数 i % 9 ==0
//(3) 统计个数 定义一个变量 int count = 0; 当 条件满足时 count++;
//(4) 总和 , 定义一个变量 int sum = 0; 当条件满足时累积 sum += i;
//先死后活
//(1) 为了适应更好的需求,把范围的开始的值和结束的值,做出变量
//(2) 还可以更进一步 9 倍数也做成变量 int t = 9;

int count = 0; //统计9的倍数个数 变量
int sum = 0; //总和
int start = 10;
int end = 200;
int t = 5; // 倍数
for(int i = start; i <= end; i++) {
if( i % t == 0) {
System.out.println("i=" + i);
count++;
sum += i;//累积
}
}

System.out.println("count=" + count);
System.out.println("sum=" + sum);

}
}

4.3.2 while

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

public class WhileExercise {

//编写一个main方法
public static void main(String[] args) {

// 打印1—100之间所有能被3整除的数
// 化繁为简, 先死后活

int i = 1;
int endNum = 100;
while( i <= endNum) {
if( i % 3 == 0) {
System.out.println("i=" + i);
}

i++;//变量自增
}

// 打印40—200之间所有的偶数
// 化繁为简, 先死后活(利于思考)
//
System.out.println("========");
int j = 40; //变量初始化
while ( j <= 200) {
//判断
if( j % 2 == 0) {
System.out.println("j=" + j);
}
j++;//循环变量的迭代
}

}
}

4.3.3 do-while

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
public class DoWhileExercise01 { 

//编写一个main方法
public static void main(String[] args) {
//统计1---200之间能被5整除但不能被3整除的 个数
//化繁为简
//(1) 使用do-while输出 1-200
//(2) 过滤 能被5整除但不能被3整除的数 %
//(3) 统计满足条件的个数 int count = 0;
//先死后活
//(1) 范围的值 1-200 你可以做出变量
//(2) 能被5整除但不能被3整除的 , 5 和 3 可以改成变量
int i = 1;
int count = 0; //统计满足条件的个数
do {
if( i % 5 == 0 && i % 3 != 0 ) {
System.out.println("i=" + i);
count++;
}
i++;
}while(i <= 200); // 后面的分号不能落

System.out.println("count=" + count);
}
}
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
import java.util.Scanner;
public class DoWhileExercise02 {

//编写一个main方法
public static void main(String[] args) {

//如果李三不还钱,则老韩将一直使出五连鞭,直到李三说还钱为
//[System.out.println("老韩问:还钱吗?y/n")] do...while ..
//
//化繁为简
//(1) 不停的问还钱吗?
//(2) 使用char answer 接收回答, 定义一个Scanner对象
//(3) 在do-while 的while 判断如果是 y 就不在循环
//一定自己动脑筋..
Scanner myScanner = new Scanner(System.in);
char answer = ' ';
do {
System.out.println("老韩使出五连鞭~");
System.out.println("老韩问:还钱吗?y/n");
answer = myScanner.next().charAt(0);
System.out.println("他的回答是" + answer);
}while(answer != 'y');//判断条件很关键

System.out.println("李三还钱了");
}
}

4.4 多重循环控制

最多不要超过 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

import java.util.Scanner;
public class MulForExercise01 {

//编写一个main方法
public static void main(String[] args) {
//统计3个班成绩情况,每个班有5名同学,
//求出各个班的平均分和所有班级的平均分[学生的成绩从键盘输入]。
//统计三个班及格人数,每个班有5名同学。
//
//思路分析:
//化繁为简
//(1) 先计算一个班 , 5个学生的成绩和平均分 , 使用for
//1.1 创建 Scanner 对象然后,接收用户输入
//1.2 得到该班级的平均分 , 定义一个 doubel sum 把该班级5个学生的成绩累积

//(2) 统计3个班(每个班5个学生) 平均分
//(3) 所有班级的平均分
//3.1 定义一个变量,double totalScore 累积所有学生的成绩
//3.2 当多重循环结束后,totalScore / (3 * 5)
//(4) 统计三个班及格人数
//4.1 定义变量 int passNum = 0; 当有一个学生成绩>=60, passNum++
//4.2 如果 >= 60 passNum++
//(5) 可以优化[效率,可读性, 结构]

//创建 Scanner 对象
Scanner myScanner = new Scanner(System.in);
double totalScore = 0; //累积所有学生的成绩
int passNum = 0;//累积 及格人数
int classNum = 3; //班级个数
int stuNum = 5;//学生个数
for( int i = 1; i <= classNum; i++) {//i 表示班级

double sum = 0; //一个班级的总分
for( int j = 1; j <= stuNum; j++) {//j 表示学生
System.out.println("请数第"+i+"个班的第"+j+"个学生的成绩");
double score = myScanner.nextDouble();
//当有一个学生成绩>=60, passNum++
if(score >= 60) {
passNum++;
}
sum += score; //累积
System.out.println("成绩为" + score);
}
//因为sum 是 5个学生的总成绩
System.out.println("sum=" + sum + " 平均分=" + (sum / stuNum));
//把 sum 累积到 totalScore
totalScore += sum;

}
System.out.println("三个班总分="+ totalScore
+ " 平均分=" + totalScore / (classNum*stuNum));
System.out.println("及格人数=" + passNum);

}
}

4.5 打印金字塔

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
public class Stars { 

//编写一个main方法
public static void main(String[] args) {

/*

*
* *
* *
********

思路分析
化繁为简
1. 先打印一个矩形
*****
*****
*****
*****
*****
2. 打印半个金字塔

* //第1层 有 1个*
** //第2层 有 2个*
*** //第3层 有 3个*
**** //第4层 有 4个*
***** //第5层 有 5个*

3. 打印整个金字塔
* //第1层 有 1个* 2 * 1 -1 有4=(总层数-1)个空格
*** //第2层 有 3个* 2 * 2 -1 有3=(总层数-2)个空格
***** //第3层 有 5个* 2 * 3 -1 有2=(总层数-3)个空格
******* //第4层 有 7个* 2 * 4 -1 有1=(总层数-4)个空格
********* //第5层 有 9个* 2 * 5 -1 有0=(总层数-5)个空格

4. 打印空心的金字塔 [最难的]
* //第1层 有 1个* 当前行的第一个位置是*,最后一个位置也是*
* * //第2层 有 2个* 当前行的第一个位置是*,最后一个位置也是*
* * //第3层 有 2个* 当前行的第一个位置是*,最后一个位置也是*
* * //第4层 有 2个* 当前行的第一个位置是*,最后一个位置也是*
********* //第5层 有 9个* 全部输出*

先死后活
5 层数做成变量 int totalLevel = 5;


*/
int totalLevel = 20; //层数
for(int i = 1; i <= totalLevel; i++) { //i 表示层数

//在输出*之前,还有输出 对应空格 = 总层数-当前层
for(int k = 1; k <= totalLevel - i; k++ ) {
System.out.print(" ");
}

//控制打印每层的*个数
for(int j = 1;j <= 2 * i - 1;j++) {
//当前行的第一个位置是*,最后一个位置也是*, 最后一层全部 *
if(j == 1 || j == 2 * i - 1 || i == totalLevel) {
System.out.print("*");
} else { //其他情况输出空格
System.out.print(" ");
}
}
//每打印完一层的*后,就换行 println本身会换行
System.out.println("");
}
}
}

4.6 跳转控制语句

4.6.1 break

要知道标签是什么东西, 编程的时候一般不写, 但是要知道

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


public class BreakDetail {

//编写一个main方法
public static void main(String[] args) {

abc1: // 标签
for(int j = 0; j < 4; j++){//外层for
abc2: // 标签
for(int i = 0; i < 10; i++){//内层for
if(i == 2){
//break ;//等价 break abc2
break abc1 ; // 退出哪个标签下的循环
}
System.out.println("i = " + i);
}
}

}
}
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
import java.util.Scanner;
public class BreakExercise02 {

//编写一个main方法
public static void main(String[] args) {

//实现登录验证,有3次机会,如果用户名为"丁真" ,密码"666"提示登录成功,
//否则提示还有几次机会,请使用for+break完成
//
// 思路分析
// 1. 创建Scanner对象接收用户输入
// 2. 定义 String name ; String passwd; 保存用户名和密码
// 3. 最多循环3次[登录3次],如果 满足条件就提前退出
// 4. 定义一般变量 int chance 记录还有几次登录机会
//
// 代码实现

Scanner myScanner = new Scanner(System.in);
String name = "";
String passwd = "";
int chance = 3; //登录一次 ,就减少一次
for( int i = 1; i <= 3; i++) {//3次登录机会
System.out.println("请输入名字");
name = myScanner.next();
System.out.println("请输入密码");
passwd = myScanner.next();
//比较输入的名字和密码是否正确
//补充说明字符串 的内容 比较 使用的 方法 equals
if("丁真".equals(name) && "666".equals(passwd)) {
System.out.println("恭喜你,登录成功~");
break;
}

//登录的机会就减少一次
chance--;
System.out.println("你还有" + chance + "次登录机会");

}


}
}

4.6.2 continue

也有标签这个东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

public class ContinueDetail {

//编写一个main方法
public static void main(String[] args) {

label1:
for(int j = 0; j < 2; j++){
label2:
for(int i = 0; i < 10; i++){
if(i == 2){
//看看分别输出什么值,并分析
//continue ; //等价于 continue label2
//continue label2;//等价 continue;
continue label1; //输出 2次[0,1]
}
System.out.println("i = " + i);//输出2次[0,1,3,4,5,6,7,8,9]
}
}

}
}

4.6.3 return

方法中的 return 表示退出方法

main 函数中的 return 表示结束程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Return01 { 

//编写一个main方法
public static void main(String[] args) {

for(int i=1;i<=5;i++){

if(i==3) {
System.out.println("韩顺平教育 "+i);
return; //当return用在方法时,表示跳出方法,如果使用在main,表示退出程序

}
System.out.println("Hello World!");
}
System.out.println("go on..");

}
}

五、数组、排序和查找

5.1 数组

5.1.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
25
26
27
28
29
30
31
32
33
34
import java.util.Scanner;
public class Array02 {

//编写一个main方法
public static void main(String[] args) {
//演示 数据类型 数组名[]=new 数据类型[大小]
//循环输入5个成绩,保存到double数组,并输出

//步骤
//1. 创建一个 double 数组,大小 5
//静态初始化就是直接在数组中定义数组内容
//(1) 第一种动态分配方式
//double scores[] = new double[5];
//(2) 第2种动态分配方式, 先声明数组,再 new 分配空间
double scores[] ; //声明数组, 这时 scores 是 null
scores = new double[5]; // 分配内存空间,可以存放数据


//2. 循环输入
// scores.length 表示数组的大小/长度
//
Scanner myScanner = new Scanner(System.in);
for( int i = 0; i < scores.length; i++) {
System.out.println("请输入第"+ (i+1) +"个元素的值");
scores[i] = myScanner.nextDouble();
}

//输出,遍历数组
System.out.println("==数组的元素/值的情况如下:===");
for( int i = 0; i < scores.length; i++) {
System.out.println("第"+ (i+1) +"个元素的值=" + scores[i]);
}
}
}
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 class ArrayDetail {

//编写一个main方法
public static void main(String[] args) {
//1. 数组是多个相同类型数据的组合,实现对这些数据的统一管理

//int[] arr1 = {1, 2, 3, 60,"hello"};//String ->int
double[] arr2 = {1.1, 2.2, 3.3, 60.6, 100};//int ->double

//2. 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用
String[] arr3 = {"北京","jack","milan"};

//3. 数组创建后,如果没有赋值,有默认值
//int 0,short 0, byte 0, long 0,
//float 0.0,double 0.0,char \u0000,
//boolean false,String null
//
short[] arr4 = new short[3];
System.out.println("=====数组arr4=====");
for(int i = 0; i < arr4.length; i++) {
System.out.println(arr4[i]);
}
//4. 使用数组的步骤 1. 声明数组并开辟空间 2 给数组各个元素赋值 3 使用数组
//5. 数组的下标是从 0 开始的

//6. 数组下标必须在指定范围内使用,否则报:下标越界异常,比如
//int [] arr=new int[5]; 则有效下标为 0-4
//即数组的下标/索引 最小 0 最大 数组长度-1(4)
int [] arr = new int[5];
//System.out.println(arr[5]);//数组越界

//7. 数组属引用类型,数组型数据是对象(object)

}
}

5.1.2 数组赋值机制 (※)

没有 new 过 (初始化) 的数组没有独立空间, 只是声明了而已

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

public class ArrayAssign {

//编写一个main方法
public static void main(String[] args) {

//基本数据类型赋值, 赋值方式为值拷贝
//n2的变化,不会影响到n1的值
int n1 = 10;
int n2 = n1;

n2 = 80;
System.out.println("n1=" + n1);//10
System.out.println("n2=" + n2);//80

//数组在默认情况下是引用传递,赋的值是地址,赋值方式为引用赋值
//是一个地址 , arr2变化会影响到 arr1
int[] arr1 = {1, 2, 3};
int[] arr2 = arr1;//把 arr1赋给 arr2
arr2[0] = 10;

//看看arr1的值
System.out.println("====arr1的元素====");
for(int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);//10, 2, 3
}

System.out.println("====arr2的元素====");
for(int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);//10, 2, 3
}

}
}

数组内存图

5.1.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 class ArrayCopy { 

//编写一个main方法
public static void main(String[] args) {

//将 int[] arr1 = {10,20,30}; 拷贝到 arr2数组,
//要求数据空间是独立的.

int[] arr1 = {10,20,30};

//创建一个新的数组arr2,开辟新的数据空间
//大小 arr1.length;
int[] arr2 = new int[arr1.length];

//遍历 arr1 ,把每个元素拷贝到arr2对应的元素位置
for(int i = 0; i < arr1.length; i++) {
arr2[i] = arr1[i];
}

//老师修改 arr2, 不会对arr1有影响.
arr2[0] = 100;

//输出arr1
System.out.println("====arr1的元素====");
for(int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);//10,20,30
}

//
System.out.println("====arr2的元素====");
for(int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);//
}

}
}

5.1.4 数组翻转

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
// 方式 1:通过找规律反转
public class ArrayReverse {

//编写一个main方法
public static void main(String[] args) {

//定义数组
int[] arr = {11, 22, 33, 44, 55, 66};
//规律
//1. 把 arr[0] 和 arr[5] 进行交换 {66,22,33,44,55,11}
//2. 把 arr[1] 和 arr[4] 进行交换 {66,55,33,44,22,11}
//3. 把 arr[2] 和 arr[3] 进行交换 {66,55,44,33,22,11}
//4. 一共要交换 3 次 = arr.length / 2
//5. 每次交换时,对应的下标 是 arr[i] 和 arr[arr.length - 1 -i]
//代码
//优化
int temp = 0;
int len = arr.length; //计算数组的长度
for( int i = 0; i < len / 2; i++) {
temp = arr[len - 1 - i];//保存
arr[len - 1 - i] = arr[i];
arr[i] = temp;
}

System.out.println("===翻转后数组===");
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");//66,55,44,33,22,11
}
}
}
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
// 方式 2:使用逆序赋值方式

public class ArrayReverse02 {

//编写一个main方法
public static void main(String[] args) {

//定义数组
int[] arr = {11, 22, 33, 44, 55, 66};
//使用逆序赋值方式
//1. 先创建一个新的数组 arr2 ,大小 arr.length
//2. 逆序遍历 arr ,将 每个元素拷贝到 arr2的元素中(顺序拷贝)
//3. 建议增加一个循环变量 j -> 0 -> 5
int[] arr2 = new int[arr.length];
//逆序遍历 arr
for(int i = arr.length - 1, j = 0; i >= 0; i--, j++) {
arr2[j] = arr[i];
}
//4. 当for循环结束,arr2就是一个逆序的数组 {66, 55, 44,33, 22, 11}
//5. 让 arr 指向 arr2数据空间, 此时 arr原来的数据空间就没有变量引用
// 会被当做垃圾,销毁
arr = arr2;
System.out.println("====arr的元素情况=====");
//6. 输出 arr 看看
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}

}
}

5.1.5 数组扩容

新建一个数组之后扩容, 再将原数组名指向新的数组, 原数组空间被垃圾回收机制回收销毁

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
import java.util.Scanner;
public class ArrayAdd02 {

//编写一个main方法
public static void main(String[] args) {
/*
要求:实现动态的给数组添加元素效果,实现对数组扩容。ArrayAdd.java
1.原始数组使用静态分配 int[] arr = {1,2,3}
2.增加的元素4,直接放在数组的最后 arr = {1,2,3,4}
3.用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n

思路分析
1. 定义初始数组 int[] arr = {1,2,3}//下标0-2
2. 定义一个新的数组 int[] arrNew = new int[arr.length+1];
3. 遍历 arr 数组,依次将arr的元素拷贝到 arrNew数组
4. 将 4 赋给 arrNew[arrNew.length - 1] = 4;把4赋给arrNew最后一个元素
5. 让 arr 指向 arrNew ; arr = arrNew; 那么 原来arr数组就被销毁
6. 创建一个 Scanner可以接受用户输入
7. 因为用户什么时候退出,不确定,老师使用 do-while + break来控制
*/

Scanner myScanner = new Scanner(System.in);
//初始化数组
int[] arr = {1,2,3};

do {
int[] arrNew = new int[arr.length + 1];
//遍历 arr 数组,依次将arr的元素拷贝到 arrNew数组
for(int i = 0; i < arr.length; i++) {
arrNew[i] = arr[i];
}
System.out.println("请输入你要添加的元素");
int addNum = myScanner.nextInt();
//把addNum赋给arrNew最后一个元素
arrNew[arrNew.length - 1] = addNum;
//让 arr 指向 arrNew,
arr = arrNew;
//输出arr 看看效果
System.out.println("====arr扩容后元素情况====");
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
//问用户是否继续
System.out.println("是否继续添加 y/n");
char key = myScanner.next().charAt(0);
if( key == 'n') { //如果输入n ,就结束
break;
}
}while(true);

System.out.println("你退出了添加...");
}
}

5.1.6 数组缩减

新建一个数组之后缩减, 再将原数组名指向新的数组, 原数组空间被垃圾回收机制回收销毁

5.1.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

public class ArrayExercise01 {

//编写一个main方法
public static void main(String[] args) {

/*
创建一个char类型的26个元素的数组,分别 放置'A'-'Z'。
使用for循环访问所有元素并打印出来。
提示:char类型数据运算 'A'+1 -> 'B'

思路分析
1. 定义一个 数组 char[] chars = new char[26]
2. 因为 'A' + 1 = 'B' 类推,所以老师使用for来赋值
3. 使用for循环访问所有元素
*/
char[] chars = new char[26];
for( int i = 0; i < chars.length; i++) {//循环26次
//chars 是 char[]
//chars[i] 是 char
chars[i] = (char)('A' + i); //'A' + i 是int , 需要强制转换
}

//循环输出
System.out.println("===chars数组===");
for( int i = 0; i < chars.length; i++) {//循环26次
System.out.print(chars[i] + " ");
}

}
}
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

public class ArrayExercise02 {

//编写一个main方法
public static void main(String[] args) {

//请求出一个数组int[]的最大值 {4,-1,9, 10,23},并得到对应的下标
//老韩思路分析
//1. 定义一个int数组 int[] arr = {4,-1,9, 10,23};
//2. 假定 max = arr[0] 是最大值 , maxIndex=0;
//3. 从下标 1 开始遍历arr, 如果max < 当前元素,说明max 不是真正的
// 最大值, 我们就 max=当前元素; maxIndex=当前元素下标
//4. 当我们遍历这个数组arr后 , max就是真正的最大值,maxIndex最大值
// 对应的下标

int[] arr = {4,-1,9,10,23};
int max = arr[0];//假定第一个元素就是最大值
int maxIndex = 0; //

for(int i = 1; i < arr.length; i++) {//从下标 1 开始遍历arr

if(max < arr[i]) {//如果max < 当前元素
max = arr[i]; //把max 设置成 当前元素
maxIndex = i;
}
}
//当我们遍历这个数组arr后 , max就是真正的最大值,maxIndex最大值下标
System.out.println("max=" + max + " maxIndex=" + maxIndex);
}
}
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

public class Homework04 {

//编写一个main方法
public static void main(String[] args) {

/*
已知有个升序的数组,要求插入一个元素,该数组顺序依然是升序, 比如:
[10, 12, 45, 90], 添加23 后, 数组为 [10, 12,23, 45, 90]


思路 本质数组扩容 + 定位
1. 我们先确定 添加数应该插入到哪个索引
2. 然后扩容
*/

//先定义原数组
int[] arr = {10, 12, 45, 90};
int insertNum = 111;
int index = -1; //index就是要插入的位置

//遍历 arr数组, 如果发现 insertNum<=arr[i], 说明 i 就是要插入的位置
//使用 index 保留 index = i;
//如果遍历完后,没有发现 insertNum<=arr[i], 说明 index = arr.length
//即:添加到arr的最后

for(int i = 0; i < arr.length; i++) {
if(insertNum <= arr[i]) {
index = i;
break; //找到位置后,就退出
}
}

//判断index 的值
if(index == -1) { //说明没有还没有找到位置
index = arr.length;
}

//扩容
//先创建一个新的数组,大小 arr.length + 1
int[] arrNew = new int[arr.length + 1];
//下面老师准备将arr的元素拷贝到 arrNew ,并且要跳过 index位置
/*
分析:
int[] arr = {10, 12, 45, 90};
arrNew = { }
*/
//i 控制arrNew的下标 , j用来控制arr数组的下标
for(int i = 0, j = 0; i < arrNew.length; i++) {

if( i != index ) { //说明可以把 arr的元素拷贝到 arrNew
arrNew[i] = arr[j];
j++;
} else { //i这个位置就是要插入的数
arrNew[i] = insertNum;
}
}

//让arr 指向 arrNew , 原来的数组,就成为垃圾,被销毁
arr = arrNew;

System.out.println("======插入后,arr数组的元素情况======");
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}

5.2 排序

5.2.1 内部排序

指将需要处理的所有数据都加载到内部存储器中进行排序。

包括 (交换式排序法、选择式排序法和插入式排序法);

5.2.2 外部排序

数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。

包括 (合并排序法和直接合并排序法)

5.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
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

public class BubbleSort {

//编写一个main方法
public static void main(String[] args) {

//老韩 化繁为简,先死后活
//
//



/*
数组 [24,69,80,57,13]
第1轮排序: 目标把最大数放在最后
第1次比较[24,69,80,57,13]
第2次比较[24,69,80,57,13]
第3次比较[24,69,57,80,13]
第4次比较[24,69,57,13,80]

*/
int[] arr = {24, 69, 80, 57, 13, -1, 30, 200, -110};
int temp = 0; //用于辅助交换的变量

//将多轮排序使用外层循环包括起来即可
//先死后活 =》 4就是 arr.length - 1
for( int i = 0; i < arr.length - 1; i++) {//外层循环是4次

for( int j = 0; j < arr.length - 1 - i; j++) {//4次比较-3次-2次-1次
//如果前面的数>后面的数,就交换
if(arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("\n==第"+(i+1)+"轮==");
for(int j = 0; j < arr.length; j++) {
System.out.print(arr[j] + "\t");
}

}

// 一下是一个一个循环, 两层循环的前一个版本

// for( int j = 0; j < 4; j++) {//4次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }

// System.out.println("==第1轮==");
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + "\t");
// }
// /*
// 第2轮排序: 目标把第二大数放在倒数第二位置
// 第1次比较[24,69,57,13,80]
// 第2次比较[24,57,69,13,80]
// 第3次比较[24,57,13,69,80]
// */

// for( int j = 0; j < 3; j++) {//3次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }

// System.out.println("\n==第2轮==");
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + "\t");
// }


// 第3轮排序: 目标把第3大数放在倒数第3位置
// 第1次比较[24,57,13,69,80]
// 第2次比较[24,13,57,69,80]


// for( int j = 0; j < 2; j++) {//2次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }

// System.out.println("\n==第3轮==");
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + "\t");
// }

// /*
// 第4轮排序: 目标把第4大数放在倒数第4位置
// 第1次比较[13,24,57,69,80]
// */

// for( int j = 0; j < 1; j++) {//1次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }

// System.out.println("\n==第4轮==");
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + "\t");
// }

}
}

5.3 查找

常用查找:

  • 顺序查找
  • 二分查找

5.3.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.Scanner;
public class SeqSearch {

//编写一个main方法
public static void main(String[] args) {
/*
有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王猜数游戏:
从键盘中任意输入一个名称,判断数列中是否包含此名称【顺序查找】
要求: 如果找到了,就提示找到,并给出下标值

思路分析
1. 定义一个字符串数组
2. 接收用户输入, 遍历数组,逐一比较,如果有,则提示信息,并退出
*/

//定义一个字符串数组
String[] names = {"白眉鹰王", "金毛狮王", "紫衫龙王", "青翼蝠王"};
Scanner myScanner = new Scanner(System.in);

System.out.println("请输入名字");
String findName = myScanner.next();

//遍历数组,逐一比较,如果有,则提示信息,并退出
//这里老师给大家一个编程思想/技巧, 一个经典的方法
int index = -1;
for(int i = 0; i < names.length; i++) {
//比较 字符串比较 equals, 如果要找到名字就是当前元素
if(findName.equals(names[i])) {
System.out.println("恭喜你找到 " + findName);
System.out.println("下标为= " + i);
//把i 保存到 index
index = i;
break;//退出
}
}

if(index == -1) { //没有找到
System.out.println("sorry ,没有找到 " + findName);
}

}
}

5.4 二维数组

5.4.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

public class TwoDimensionalArray01 {

//编写一个main方法
public static void main(String[] args) {

/*
请用二维数组输出如下图形
0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0
*/

//什么是二维数组:
//老韩解读
//1. 从定义形式上看 int[][]
//2. 可以这样理解,原来的一维数组的每个元素是一维数组, 就构成二维数组
int[][] arr = { {0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0},
{0,2, 0, 3, 0, 0},
{0, 0, 0, 0, 0, 0} };

//关于二维数组的关键概念
//(1)
System.out.println("二维数组的元素个数=" + arr.length);
//(2) 二维数组的每个元素是一维数组, 所以如果需要得到每个一维数组的值
// 还需要再次遍历
//(3) 如果我们要访问第 (i+1)个一维数组的第j+1个值 arr[i][j];
// 举例 访问 3, =》 他是第3个一维数组的第4个值 arr[2][3]
System.out.println("第3个一维数组的第4个值=" + arr[2][3]); //3


//输出二维图形
for(int i = 0; i < arr.length; i++) {//遍历二维数组的每个元素
//遍历二维数组的每个元素(数组)
//1. arr[i] 表示 二维数组的第i+1个元素 比如arr[0]:二维数组的第一个元素
//2. arr[i].length 得到 对应的 每个一维数组的长度
for(int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " "); //输出了一维数组
}
System.out.println();//换行
}
}
}

5.4.2 二维数组赋值机制 (※)

允许列不相等, 即 new 的时候必须把行确定出来, 列可以后续开辟

本质上是一维数组的每一个元素都是一维数组, 这时候就要把外层的一维数组确定出来

而内层的一维数组可以后续进行创建, 如果没创建, 内存默认为 null, 无伤大雅, 啥都不影响

因此可以动态定义每一行的列数, 没有定义的列均为 null

二维数组赋值机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 动态初始化
public class TwoDimensionalArray02 {

//编写一个main方法
public static void main(String[] args) {

//int arr[][] = new int[2][3];

int arr[][]; //声明二维数组
arr = new int[2][3];//再开空间

arr[1][1] = 8;
//遍历arr数组
for(int i = 0; i < arr.length; i++) {
for(int j = 0; j < arr[i].length; j++) {//对每个一维数组遍历
System.out.print(arr[i][j] +" ");
}
System.out.println();//换行
}
}
}
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
// 列数不确定性
public class TwoDimensionalArray03 {

//编写一个main方法
public static void main(String[] args) {

/*
看一个需求:动态创建下面二维数组,并输出

i = 0: 1
i = 1: 2 2
i = 2: 3 3 3

一个有三个一维数组, 每个一维数组的元素是不一样的
*/

//创建 二维数组,一个有3个一维数组,但是每个一维数组还没有开数据空间
int[][] arr = new int[3][];

for(int i = 0; i < arr.length; i++) {//遍历arr每个一维数组
//给每个一维数组开空间 new
//如果没有给一维数组 new ,那么 arr[i]就是null
arr[i] = new int[i + 1];

//遍历一维数组,并给一维数组的每个元素赋值
for(int j = 0; j < arr[i].length; j++) {
arr[i][j] = i + 1;//赋值
}

}

System.out.println("=====arr元素=====");
//遍历arr输出
for(int i = 0; i < arr.length; i++) {
//输出arr的每个一维数组
for(int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();//换行
}


}
}

静态初始化就是直接在定义时赋值

类型 数组名[][] = {{值 1,值 2..},{值 1,值 2..},{值 1,值 2..}}

5.4.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
37
38
39
40
41
42
43
44
45
46

public class YangHui {

//编写一个main方法
public static void main(String[] args) {
/*
使用二维数组打印一个 10 行杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

规律
1.第一行有 1 个元素, 第 n 行有 n 个元素
2. 每一行的第一个元素和最后一个元素都是 1
3. 从第三行开始, 对于非第一个元素和最后一个元素的元素的值. arr[i][j]
arr[i][j] = arr[i-1][j] + arr[i-1][j-1]; //必须找到这个规律

*/
int[][] yangHui = new int[12][];
for(int i = 0; i < yangHui.length; i++) {//遍历yangHui的每个元素

//给每个一维数组(行) 开空间
yangHui[i] = new int[i+1];
//给每个一维数组(行) 赋值
for(int j = 0; j < yangHui[i].length; j++){
//每一行的第一个元素和最后一个元素都是1
if(j == 0 || j == yangHui[i].length - 1) {
yangHui[i][j] = 1;
} else {//中间的元素
yangHui[i][j] = yangHui[i-1][j] + yangHui[i-1][j-1];
}
}
}
//输出杨辉三角
for(int i = 0; i < yangHui.length; i++) {
for(int j = 0; j < yangHui[i].length; j++) {//遍历输出该行
System.out.print(yangHui[i][j] + "\t");
}
System.out.println();//换行.
}

}
}

5.4.4 二维数组使用细节

  1. 一维数组的声明方式有: int[] x 或者 int x[]

  2. 二维数组的声明方式有: int[][] y 或者 int[] y[] 或者 int y[][]

  3. 二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同。

    比如: map[][] 是一个二维数组 int map [][] = {{1,2},{3,4,5}}

    由 map[0] 是一个含有两个元素的一维数组 ,map[1] 是一个含有三个元素的一维数组构成,我们也称为列数不等的二维数组