0.简单的DOS命令

md(生成文件),cd(跳转路径),rd(del)(删除文件),dir(显示文件目录)

1.JAVA程序基本结构

  • JAVA执行的基本流程:

编写.java文件,之后由javac.exe文件生成字节码文件(.class),再由java.exe运行。

简单的HelloWorld程序:

1
2
3
4
5
class HelloChina{
public static void main(String[] args){
System.out.println("Angel Beats!");
}
}
  • public是访问修饰符,表示class是公开的,没有仍能成功编译,但无法从命令行执行。(?)

  • 在class内部,可以定义若干方法(method)。

关于命名

JAVA严格区分大小写,而Windows不区分大小写。

类名要求:

  • 类名必须以英文字母开头,后接字母,数字和下划线的组合
  • 习惯以大写字母开头,使用驼峰命名

方法名、变量名:

  • 和类名一样,不过首字母要小写,使用小驼峰命名

关于注释

JAVA特有:文档注释

1
2
3
4
/**
* look in my eyes!
* @KuoZ
*/

练习题

1.为什么JAVA是半编译半解释型语言?

2.内存泄漏和内存溢出是什么,JAVA还会发生这些问题吗?能否举一个例子?

3.一个JAVA文件里能否声明多个类,有什么限制?

2.变量和运算符

关键字和标识符

  • JAVA里一共有50个关键字。false和true可以当做关键字来看待。

  • 还有goto和const两个保留字

  • 可以自己起名的都是标识符,包括类名、方法名、变量名、接口名等。

变量

JAVA中变量的两种类型

基本数据类型

  • 整型 byte short int long
  • 浮点型 float double
  • 字符型 char
  • 布尔型 boolean

引用数据类型(先记录三类)

  • 数组
  • 接口

基本数据类型

  1. 整型
    分别占1、2、4、8个字节。与c语言不同,JAVA只定义了带符号的整型。long型结尾需要加L/l。不加则为int类型,但是int类型可以赋值给long型,可以正常运行。
  2. 浮点型
    分别占用4、8字节。对于float类型,需要加上f后缀,否则默认为double类型。
    ps:十进制小数和二进制小数并不能一一对应,二进制小数不能准确表示0.1、0.01……这些10的负次幂的数。所以说对于语句System.out.println(0.1+0.2);输出的结果不等于0.3。
  3. 字符型
    占两个字节,JAVA的char类型除了用ASCII码外,还可以用Unicode码赋值。综合下来可以有四种形式对char型赋值
  • char name = '中' 用一对单引号括起来进行赋值,单引号内有且仅有一个字符
  • char name='\u0036'单引号内是\u+相应的Unicode码
  • char name='\n'单引号内是转义字符
  • char name=51直接用ASCII码对字符进行幅值
  1. 布尔型
    布尔型只有truefalse两种取值,且不能用1、0代替。在编译时不谈boolean型的占用字节,在内存分配上,实际上占用4个字节

    1
    ps:JVM的内存分配问题:小于4个字节的分配1个slot(slot,槽位,等于4个字节),大于四个字节的分配2个slot。

var关键字

使用var时,会自动根据赋值语句来判断变量类型,实际上也就是省了写变量类型。

注意:var关键字在JAVA10之后才有。

常量

使用final表示常量类型,如final int AGE = 20 。常量的命名应全大写,使用常量以避免被人诟病”MagicNumber”。

作用域(scope)

定义作用域时,要遵循作用域最小原则,尽量少定义全局变量,也不要重复使用变量名。

基本数据类型变量运算规则

  • 对于变量之间运算问题,变量的类型问题尤为重要。

  • 除布尔型的其他7种基本数据类型可以参与运算,运算时候的变量类型问题如下:

自动类型提升

自动类型提升用于将容量小的变量类型自动提升为容量大的类型(ps:容量指的是表示数的范围大小而非所占内存大小)
结论:

image-20250405181905392

整型常量默认为int型,浮点型默认为double型。byte、short、char之间运算结果为int型。

强制类型转换
  • 强制类型转换用于将变量强制转换为指定类型。使用“( )“,”( )”内写上指定类型。

  • 强制类型转换的本质是截断,直接将所存数据的多的字节截去,这牵扯到补码。

  • 强制类型转换过程中可能有精度损失。

例如:

1
2
3
4
5
byte testNum;
int intNum=128;
testNum=(byte)intNum;
System.out.println(testNum);
//运行结果是?-128

这里的解释(不用太深入探究):128为0b1000 0000,截断后变为0b1000 0000,赋值给testNum,如果不深究的话可以直接认为计算机规定0b1000 0000为-128。如果深究的话,0b1000 0000是一个负数的补码,按照规则求原数,减去1得到0b0111 1111,再取反就是0b1000 0000,其大小是128,表明这个负数的绝对值是128,自然这个数就是-128。不要试图求0b1000 0000的原码,因为其无对应原码(128超出了byte类型的范围)

String类

  • String类为引用数据类型,使用时用“ ”括起来的字符串赋值。

  • String类型使用”+“连接符进行运算,可以与基本数据类型(包括布尔型)和String类型进行运算。结果为String类型。

运算符

运算符类型

包括算术运算符、赋值运算符、比较运算符、逻辑运算符、位运算符和条件运算符

算术运算符

  • 除常见的加减乘除外还有++、- -、连接符+
  • 运算遵从四则运算规则
++ - -运算符(以++为例):

1.区分先++、后++:

1
2
a++;//先取值后加1
++a;//先加1后取值

这里可以引入操作数栈的概念理解,看下边的练习:

1
2
3
4
int m,n;
m=n=1;
m=m++;//m等于1。先将m的值1放入操作数栈,然后将m加1,再把操作数栈的数(1)赋值给m
n=++n;//n等于2。先将将n加1,然后n的值2放入操作数栈,再把操作数栈的数(2)赋值给n

2.num++和num=num + 1的区别,num++不改变变量类型,例如:

1
2
3
byte num=1;
num++;//不报错
num=num + 1;//会报错

赋值运算符

重点介绍+=、-+、*=、/=、%=在参与运算时的数据类型。
与num++类似,上边的运算符也不改变数据类型

1
2
3
byte num=1;
num+=2;//不报错,实际上可以理解为num=(byte)(num + 2)
num=num + 2;//会报错

练习

1
2
int n=10;
n+=(n++)+(++n);//n=n+(n++)+(++n)结果为10+10+12=32

比较运算符

== != >= <= > < instanceof

  • 运算结果为布尔型
  • 除布尔型外的7中基本变量类型可以参与比较运算
  • == !=适用于引用数据类型

逻辑运算符

区分&和&&

位运算符(难点非重点)

1
>> << >>>(无符号右移) & | ^ ~
  • 位运算符的运算效率较高

条件运算符

条件表达式?表达式1:表达式2
条件表达式为true执行表达式1,为false执行表达式2

  • 条件运算符的运算效率比if else略高

练习题

1.效率较高地运算2*8

2.&和&&的区别

3.boolean型变量占用的字节数

4.为什么0.1+0.2不等于0.3

3.流程控制

Scanner类和random()方法

在流程控制之前,先介绍两个类方法

  1. Scanner类:

使用Scanner类的一般代码

1
2
3
4
5
6
7
8
import java.util.Scanner;//导入包
class ScannerTemplate{
public static void main(String[] arr){
Scanner input =new Scanner(System.in);//创建对象,格式固定
int inputNum=input.nextInt();//变量类型不同,相应有不同的方法
input.close();//收回,防止内存泄漏
}
}

常见Scanner的类方法:

Modifier and Type Method
String next()
boolean nextBoolean()
byte nextByte()
short nextShort()
int nextInt()
float nextFloat()
double nextDouble()
  1. random()
  • Math类的random()方法:返回一个[0 , 1)范围的double类型的随机数。

获得指定范围的随机整数:

1
2
//假定范围为[a , b]
int randomInt = (int)(Math.random()*(b-a+1))+a;//注意强转和所乘倍数

分支语句

if else

和C语言几乎完全一致,在此省略。

switch case

语法结构:

1
2
3
4
5
6
7
8
9
10
11
switch(表达式){
case 常量1:
执行语句1
break;
case 常量2:
执行语句2
break;
...
default:
break;
}
  • 与if-else不同,switch-case具有穿透性

  • switch-case通常用于情况有限的问题

  • default位置可以改变

  • switch中的表达式只能是特定的数据类型:byte short char int ; 枚举(JDK5.0新增) String(JDK7.0新增)

一个利用穿透性的例子:

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
Scanner input =new Scanner(System.in);
int month=input.nextInt();
int days=input.nextInt();
input.close();
int sumDays=days;
switch(month){
case 12:
sumDays+=30;
case 11:
sumDays+=31;
case 10:
sumDays+=30;
case 9:
sumDays+=31;
case 8:
sumDays+=31;
case 7:
sumDays+=30;
case 6:
sumDays+=31;
case 5:
sumDays+=30;
case 4:
sumDays+=31;
case 3:
sumDays+=28;
case 2:
sumDays+=31;
default: break;
}
System.out.println(sumDays);

对比

  • 能用switch-case的,都可以用if-else代替
  • switch-case比if-else的效率稍高

循环语句

循环的四要素

  1. 初始化部分

  2. 循环条件部分–>boolean类型的变量或表达式

  3. 循环体部分

  4. 迭代部分

for循环

for(1;2;4){
3
}

  • 一般用于有明显循环次数(范围)需求的问题

while循环

1
while(2){
3
4
}

  • 一般用于不知道循环多少次的问题
  • 初始化条件的作用域与for循环不同,while循环的初始化条件在循环语句之后依旧有效

do-while循环

1
do {
3
4
}while(2);

  • 至少执行一次循环体

无限循环

  • 结构:while(true)和for(;;)
  • 需要根据一定的条件使用break终止循环
  • 如果循环无法终止,就构成了死循环,开发中要避免死循环。死循环的后边不能有语句,否则编译会报错

嵌套循环

例:使用嵌套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
import java.util.Scanner;
class Diamond{
public static void main(String[] arr){
Scanner input = new Scanner(System.in);
int row = input.nextInt();
input.close();
for(int i=1;i<=(row+1)/2;i++){
for(int j=1;j<=row+1-i*2;j++){
System.out.print(' ');
}
for(int j=1;j<=2*i-1;j++){
System.out.print("* ");
}
for(int j=1;j<=row-i*2;j++){
System.out.print(" ");
}
System.out.println();
}
for(int i=1;i<=(row-1)/2;i++){
for(int j=1;j<=2*i;j++){
System.out.print(' ');
}
for(int j=1;j<=row-2*i;j++){
System.out.print("* ");
}
for(int j=1;j<=2*i-1;j++){
System.out.print(" ");
}
System.out.println();
}

}
}

break、continue

适用范围 在循环结构中的作用 相同点
break switch-case语句/循环结构 一旦执行,结束(或跳出)当前循环结构 此关键字的后面,不能声明语句
continue 循环结构 一旦执行,结束(或跳出)当次循环结构 此关键字的后面,不能声明语句

算法好坏

currentTimeMillis()方法可获得从标准时间点到现在的时间(以ms为单位)

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
/*
案例:找出100000以内的所有质数
*/
public class ZNum {
public static class Main {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
for(int i=2;i<=100000;i++){

boolean isFlag = true;

for(int j=2;j<Math.sqrt(i);j++){//使用开根值可大大加快速度
if(i%j==0){
isFlag = false;
break;//避免多余操作
}
}
if(isFlag){
System.out.println(i);
}
}
long endTime = System.currentTimeMillis();

System.out.println("time spend: " + (endTime - startTime));

}
}
}

4.数组

数组使用

  1. 声明和初始化:
    初始化后数组的长度就确定了,无法更改
1
2
3
4
5
6
7
//定义:类型[] 数组名 = new 类型 [长度];
//第一种方式(静态初始化)
int[] arr;//声明
arr=new int[]{68, 79, 91, 85, 62};//初始化
int[] arr = {68, 79, 91, 85, 62};//进一步简写,必须写在一行!
//第二种方式(动态初始化)
int[] arr = new int[5];//声明和初始化
  1. 数组的调用
    与c语言相同,省略。

  2. 数组的属性length
    用来描述数组容器的容量大小,可以使用数组名.length获得数组长度。

  3. 数组的遍历
    使用for循环

  4. 数组的默认初始化

    类型 初始化值
    整型 0
    浮点型 0.0
    字节型 0(或者‘\u0000’)
    布尔型 false
    引用数据类型 null
  5. 一维数组的内存解析
    JVM中与此相关的内容:栈(stack)、堆(heap),在此不展开描述。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class ArrTest2 {
    public static void main(String[] args) {
    int[] arr = new int[3];
    arr[0]=1;
    arr[1]=2;
    arr[2]=3;
    System.out.println(arr[1]);//2
    int[] arr1 =arr;
    arr1[1]=114;
    System.out.println(arr[1]);//114
    }
    }

    数组变量存储的实际上是首地址,在这段代码中创建arr1时并未在堆中开辟一段新内存,因此更改arr1的数组内容也同样更改了arr的数组内容。

二维数组

所谓的二维数组本质上还是数组,也就是说Java中实际上不存在二维数组这一数据结构。

  • 调用内层
    返回的是元素值

  • 调用外层
    返回的是地址值

  • 内存解析
    数组元素名存放的是一个数组的首地址,这个数组存放各个第二层数组的首地址

常见算法操作

扩容/缩容

数组的扩容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ArrExp {
public static void main(String[] args) {
int[] arr = new int [5];
//扩容1倍容量
int[] newArr = new int [arr.length<<1];
//复制到新的数组中
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
//添加新的数字
newArr[arr.length] = 10;
newArr[arr.length + 1] = 20;
newArr[arr.length+2] = 30;
//将新的数组地址赋值给原有的数组变量
arr = newArr;
System.out.println(arr.length);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}

数组的缩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//不新建数组
public class ArrayDel {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,8,5,7,7};
int delMinus =2;
for (int i = delMinus; i < arr.length-1; i++) {
arr[i]=arr[i+1];
}
arr[arr.length - 1] = 0;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//新建数组
public class ArrayDel {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,8,5,7,7};
int delMinus =2;
int[] newArr = new int[arr.length-1];
for (int i = 0; i < delMinus; i++) {
newArr[i] = arr[i];
}
for (int i = delMinus; i < arr.length-1; i++) {
newArr[i] = arr[i+1];
}
arr = newArr;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}

查找

线性查找
逐个遍历,算法简单、适用性广但效率较低。

二分查找
前提:只适用有序数组,算法较复杂,但效率较高。

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 ArrSearch {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,9};
int target = 4;
int head=0;
int tail=arr.length-1;
int mid;
while (head<=tail) {
mid=(head+tail)/2;
if (arr[mid]==target) {
System.out.println("找到了,在第"+mid+"个位置");
break;
}
else if (target>arr[mid]) {
head=mid+1;
}
else{
tail=mid-1;
}
}
if(head > tail) System.out.println("没找到");
}
}

排序

冒泡排序,需要会手写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SortTest {
public static void main(String[] args) {
int [] arr = {1,2,90,3,5,8,5,7,7};
for (int j = 0; j < arr.length-1; j++) {
for (int i = 0; i < arr.length-1-j; i++) {
if(arr[i]>arr[i+1]){
int temp = arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}

快速排序,需使用迭代,不必会手写,掌握实现思路即可。

Arrays常见工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Arrays;
public class ArrToolTest {
public static void main(String[] args) {
int [] arr = {1,2,3,4,5,8,5,7,7};
//打印数组
System.out.println(Arrays.toString(arr) );//[1, 2, 3, 4, 5, 8, 5, 7, 7]
//排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr) );//[1, 2, 3, 4, 5, 5, 7, 7, 8]
//查找
System.out.println(Arrays.binarySearch(arr,2));//1
//填充数组
Arrays.fill(arr,6);
System.out.println(Arrays.toString(arr) );//[6, 6, 6, 6, 6, 6, 6, 6, 6]
//相等判断
int [] arr2 = {1,2,3,4,5,8,5,7,7};
Arrays.equals(arr,arr2);
System.out.println(Arrays.equals(arr,arr2));//false
}
}