Java基本语法
0.简单的DOS命令
md(生成文件),cd(跳转路径),rd(del)(删除文件),dir(显示文件目录)
1.JAVA程序基本结构
- JAVA执行的基本流程:
编写.java文件,之后由javac.exe文件生成字节码文件(.class),再由java.exe运行。
简单的HelloWorld程序:
1 | class HelloChina{ |
public是访问修饰符,表示class是公开的,没有仍能成功编译,但无法从命令行执行。(?)
在class内部,可以定义若干方法(method)。
关于命名
JAVA严格区分大小写,而Windows不区分大小写。
类名要求:
- 类名必须以英文字母开头,后接字母,数字和下划线的组合
- 习惯以大写字母开头,使用驼峰命名
方法名、变量名:
- 和类名一样,不过首字母要小写,使用小驼峰命名
关于注释
JAVA特有:文档注释
1 | /** |
练习题
1.为什么JAVA是半编译半解释型语言?
2.内存泄漏和内存溢出是什么,JAVA还会发生这些问题吗?能否举一个例子?
3.一个JAVA文件里能否声明多个类,有什么限制?
2.变量和运算符
关键字和标识符
JAVA里一共有50个关键字。false和true可以当做关键字来看待。
还有goto和const两个保留字
可以自己起名的都是标识符,包括类名、方法名、变量名、接口名等。
变量
JAVA中变量的两种类型
基本数据类型
- 整型 byte short int long
- 浮点型 float double
- 字符型 char
- 布尔型 boolean
引用数据类型(先记录三类)
- 类
- 数组
- 接口
基本数据类型
- 整型
分别占1、2、4、8个字节。与c语言不同,JAVA只定义了带符号的整型。long型结尾需要加L/l。不加则为int类型,但是int类型可以赋值给long型,可以正常运行。 - 浮点型
分别占用4、8字节。对于float类型,需要加上f后缀,否则默认为double类型。
ps:十进制小数和二进制小数并不能一一对应,二进制小数不能准确表示0.1、0.01……这些10的负次幂的数。所以说对于语句System.out.println(0.1+0.2);
输出的结果不等于0.3。 - 字符型
占两个字节,JAVA的char类型除了用ASCII码外,还可以用Unicode码赋值。综合下来可以有四种形式对char型赋值
char name = '中'
用一对单引号括起来进行赋值,单引号内有且仅有一个字符char name='\u0036'
单引号内是\u+相应的Unicode码char name='\n'
单引号内是转义字符char name=51
直接用ASCII码对字符进行幅值
布尔型
布尔型只有true
和false
两种取值,且不能用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:容量指的是表示数的范围大小而非所占内存大小)
结论:
整型常量默认为int型,浮点型默认为double型。byte、short、char之间运算结果为int型。
强制类型转换
强制类型转换用于将变量强制转换为指定类型。使用“( )“,”( )”内写上指定类型。
强制类型转换的本质是截断,直接将所存数据的多的字节截去,这牵扯到补码。
强制类型转换过程中可能有精度损失。
例如:
1 | byte testNum; |
这里的解释(不用太深入探究):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 | a++;//先取值后加1 |
这里可以引入操作数栈的概念理解,看下边的练习:
1 | int m,n; |
2.num++和num=num + 1的区别,num++不改变变量类型,例如:
1 | byte num=1; |
赋值运算符
重点介绍+=、-+、*=、/=、%=在参与运算时的数据类型。
与num++类似,上边的运算符也不改变数据类型
1 | byte num=1; |
练习
1 | int n=10; |
比较运算符
== != >= <= > < 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()方法
在流程控制之前,先介绍两个类方法
- Scanner类:
使用Scanner类的一般代码
1 | import java.util.Scanner;//导入包 |
常见Scanner的类方法:
Modifier and Type | Method |
---|---|
String | next() |
boolean | nextBoolean() |
byte | nextByte() |
short | nextShort() |
int | nextInt() |
float | nextFloat() |
double | nextDouble() |
- random()
- Math类的random()方法:返回一个[0 , 1)范围的double类型的随机数。
获得指定范围的随机整数:
1 | //假定范围为[a , b] |
分支语句
if else
和C语言几乎完全一致,在此省略。
switch case
语法结构:
1 | switch(表达式){ |
与if-else不同,switch-case具有穿透性
switch-case通常用于情况有限的问题
default位置可以改变
switch中的表达式只能是特定的数据类型:byte short char int ; 枚举(JDK5.0新增) String(JDK7.0新增)
一个利用穿透性的例子:
1 | Scanner input =new Scanner(System.in); |
对比
- 能用switch-case的,都可以用if-else代替
- switch-case比if-else的效率稍高
循环语句
循环的四要素
初始化部分
循环条件部分–>boolean类型的变量或表达式
循环体部分
迭代部分
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 | import java.util.Scanner; |
break、continue
适用范围 | 在循环结构中的作用 | 相同点 | |
---|---|---|---|
break | switch-case语句/循环结构 | 一旦执行,结束(或跳出)当前循环结构 | 此关键字的后面,不能声明语句 |
continue | 循环结构 | 一旦执行,结束(或跳出)当次循环结构 | 此关键字的后面,不能声明语句 |
算法好坏
currentTimeMillis()方法可获得从标准时间点到现在的时间(以ms为单位)
1 | /* |
4.数组
数组使用
- 声明和初始化:
初始化后数组的长度就确定了,无法更改
1 | //定义:类型[] 数组名 = new 类型 [长度]; |
数组的调用
与c语言相同,省略。数组的属性length
用来描述数组容器的容量大小,可以使用数组名.length
获得数组长度。数组的遍历
使用for循环数组的默认初始化
类型 初始化值 整型 0 浮点型 0.0 字节型 0(或者‘\u0000’) 布尔型 false 引用数据类型 null 一维数组的内存解析
JVM中与此相关的内容:栈(stack)、堆(heap),在此不展开描述。1
2
3
4
5
6
7
8
9
10
11
12public 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 | public class ArrExp { |
数组的缩容
1 | //不新建数组 |
1 | //新建数组 |
查找
线性查找
逐个遍历,算法简单、适用性广但效率较低。
二分查找
前提:只适用有序数组,算法较复杂,但效率较高。
1 | public class ArrSearch { |
排序
冒泡排序,需要会手写。
1 | public class SortTest { |
快速排序,需使用迭代,不必会手写,掌握实现思路即可。
Arrays常见工具类
1 | import java.util.Arrays; |