整理自:老师课件、动力节点Javase基础讲义
Java基础语法
前言
在本文中,学习Java的基础语法,包括注释、标识符与关键字、变量、数据类型、运算符以及控制语句
通过本文的学习,您将了解到:
- 注释是什么?
- 标识符是什么意思,关键字呢?
- 数据类型是什么,跟现实的数据有什么对应的关系吗?
- Java中的运算符都有哪些?
- 为什么要学习控制语句?
- …
注释
为什么有注释这个语法
- 对于复杂的程序,注释可以在代码旁边写下思路,便于他人了解代码功能而不必一行一行的阅读代码甚至跟踪;甚至对于本人,下次阅读此代码,也不一定能一下子全然了解其功能,这时候若有思路记录,便很容易回忆理解。即俗话说的“好记性不如烂笔头”
注释有哪些
- 单行注释
- 在语句行中以“//”开头到本行末的所有字符视为注释
- 多行注释
- 以"/*" 和"*/"进行标记,其中"/*"标记着注释的开始,"*/"标记着注释的结束
- 当注释文字较多,一行写不下或者排版难看要分成多行,若每行都写"//"将很麻烦也不美观,故有多行注释
- 文档注释
- 类似多行注释,但注释开始标记为"/**",结束为"*/"
- 在有了多行注释基础上,还有此文档注释是因为它可通过javadoc.exe命令解析并生成帮助文档,如JDK帮助文档
怎么写
- 类和接口
- x写明创建者、创建时间、版本及该类的作用
- 方法
- 标明入参、出参以及返回值
- 常量
- 使用多行注释,标明用途
- 关键算法
- 按顺序依次标明该方法为什么这么做
标识符与关键字
标识符是什么
- 是用于编程时使用的名字,用于给变量、常量、函数、语句块等命名,以建立起名称与使用之间的关系
- 通常由字母和数字以及其他字符构成
- 总结:标识符即起名字
标识符怎么命名
- 标识符只能由数字、字母、下划线、美元符号组成
- 这里的字母是Java字母,可以用中文作为变量、方法名,但是不推荐用中文作为类名,编译时会出现莫名其妙的错误
- 标识符不能以数字开始
- Java关键字与保留字不能作为标识符
- 标识符严格区分大小写
- 标识符理论上没有长度限制
标识符命名规范:提高代码可读性
- 见命知意
- 遵循驼峰命名方式
- 类名、接口名首字母大写,后面每个单词首字母大写
- 变量名、方法名首字母小写,后面每个单词首字母大写
- 常量名全部大写,单词之间用'_'衔接
关键字是什么?
- 是编程语言里事先定义的,有特殊意义的单词(因此不能作为标识符,避免冲突),Java中所有关键字都是小写的英文单词
关键字有哪些(不必记)
关键字 | 大致含义 |
abstract | 表明类或成员方法具有抽象属性 |
assert | 断言,用于程序调试 |
boolean | 基本数据类型之一,声明布尔类型的关键字 |
break | 提前跳出一个块 |
byte | 基本数据类型之一,字节类型 |
case | 用在switch语句之中,表示其中的一个分支 |
catch | 用在异常处理中,用来捕捉异常 |
char | 基本数据类型之一,字符类型 |
class | 声明一个类 |
const | 保留关键字,没有具体含义 |
continue | 回到一个块的开始处 |
default | 默认,例如,用在switch语句中,表明一个默认的分支 |
do | 用在do-while循环结构中 |
double | 基本数据类型之一,双精度浮点数类型 |
else | 用在条件语句中,表明当条件不成立时的分支 |
enum | 枚举 |
extends | 表明一个类型是另一个类型的子类型,这里常见的类型 有类和接口 |
final | 表示不可变,最终的 |
finally | 用于处理异常情况,用来声明一个基本肯定会被执行 到的语句块 |
float | 基本数据类型之一,单精度浮点数类型 |
for | 一种循环结构的引导词 |
goto | 保留关键字,没有具体含义 |
if | 条件语句的引导词 |
implements | 表明一个类实现了给定的接口 |
import | 表明要访问指定的类或包 |
instanceof | 用来测试一个对象是否是指定类型的实例对象 |
int | 基本数据类型之一,整数类型 |
interface | 接口 |
long | 基本数据类型之一,长整数类型 |
native | 用来声明一个方法是由与计算机相关的语言(如C/C++ 语言)实现的 |
new | 用于创建新实例对象 |
package | 包 |
private | 一种访问控制方式:私用模式 |
protected | 一种访问控制方式:保护模式 |
public | 一种访问控制方式:共用模式 |
return | 从成员方法中返回数据 |
short | 基本数据类型之一,短整数类型 |
static | 表明具有静态属性 |
strictfp | 用来声明FP_strict(单精度或双精度浮点数)表达式遵循 IEEE 754算术规范 |
super | 表明当前对象的父类型的引用或者父类型的构造方法 |
switch | 分支语句结构的引导词 |
synchronized | 表明一段代码需要同步执行 |
this | 指向当前实例对象的引用 |
throw | 抛出一个异常 |
throws | 声明在当前定义的成员方法中所有需要抛出的异常 |
transient | 声明不用序列化的成员域 |
try | 尝试一个可能抛出异常的程序块 |
void | 声明当前成员方法没有返回值 |
volatile | 表明两个或多个变量必须同步地发生变化 |
while | 用在循环结构中 |
难点解惑
- 新建一个123Test.java文件,里面写class T{},编译通过,是不是违反标识符不能以数字开头?
- 不是的,因为此时123Test只是一个普通的文件名(因为没有把该类声明为共同的,所以文件名不必和类名一致),不是作为类名
- 如果将其作为类名,编译是会出现:需要
变量
字面量
是什么
- 表示Java中数与字符的明显值,即常量
- 字符型字面量须用半角单引号括起来
- 只能是单个字符
- 字符串型字面量需用半角双引号括起来
变量概述
是什么
- 把数据(字面量)放到内存中,给这块内存起一个名字,即是变量
有什么特点
- 变量中存储的数据可改变
- 变量的数据类型须和存储的字面值一致
变量定义
- 格式:数据类型 变量名 = 值…;
- 在同一个域中不能同时声明多个同名变量
- 方法体中if/switch等都在同一个域,所以若if外面已声明变量,不可在if里声明同名变量
- 如果一个是类体域,一个是方法体域,则可声明同名变量,且Java遵循就近原则,会自动访问离它最近的数据
- 方法中的代码有执行顺序,遵循自上而下的顺序
变量分类
- 局部变量
- 在方法体中声明的变量以及方法的每一个参数
- 成员变量:在方法体外,类体内声明的变量
- 没有static修饰
- 有static修饰
- 静态成员变量/静态变量
- 实例成员变量/实例变量
变量作用域
- 出了大括号后就不认识了
- 注意区分成员变量及局部变量,对应的大括号不一致
数据类型
数据类型概述
是什么
- 现实中有很多数据(如数字、字母),编程语言对其进行分门别类,产生数据类型
- 主要作用:决定程序运行阶段给该变量分配多大的内存空间
字符编码
- 编码和解码都要采用同一种字符编码方式,否则出现乱码
- 支持简体中文的编码方式:GB2312、GBK、GB18030(容量大小从左到右增大)
- Java采用Unicode编码
基本数据类型
- 可以在各自的包装类查看最大最小值,MAX_VALUE,MIN_VALUE
- 字符型char
- 两个字节,可容纳一个汉字(两个字节)
- 转义字符会在解析代码之前得到处理
- 整数型
- 赋值时在字面量后加L
- 整数型字面量默认是int类型
- byte
- short
- int
- long
- 布尔型
- boolean
- 浮点型
- 赋值时在字面量后面加F
- float类型容量比long大是因为float有一部分空间用于存储有效位数,一部分存储多少次方
- 浮点型字面量默认是double
- float
- double
- 基本数据类型转换规则
- 八个基本类型中,除boolean类型不能转换,其他都可以转换
- 如果整数型字面量没有超过byte,short,char的取值范围,可以直接将其赋值为byte,short,char类型的变量
- 注意是指字面量,而不是整数型变量,对于变量编译器不知道其大小,不能判断是否超过取值范围
- 小容量转换成大容量,称为自动类型转换,容量从小到大的排序为:byte
- int->float、long->float、long->double有可能出现精度损失,因为浮点型只能存储有限位数
- 大转小,称为强制类型转换,可能会出现精度损失
- byte,short,char类型混合运算时,先各自转换成int类型再做运算,结果也是int类型,注意了
- 多种数据类型混合运算,各自先转换成容量最大的那一种再做运算
引用类型(之后展开)
- 字符串类型
- 数组
- 类
运算符
为什么有运算符
- 因为数据有运算
有哪些运算符
算术运算符
- 注意++、--运算符,该运算符只能用于变量且只能用于除boolean类型的基本数据类型,不能用字面值
关系运算符
- 关系运算符的结果是布尔类型
逻辑运算符
- 操作数都是布尔类型
- 根据是否期望右边的表达式一定执行选择短路与&&或逻辑与&,前者若左边为空,右边不执行;后者左右两边都执行
赋值运算符
- 对于+=等拓展类运算符,在运算过程中不会改变运算的结果类型,相当于b=(byte)()b+1)等价于b += 1;如果超过当前类型的最大容量,则会截断,跟强转一样
控制语句
为什么要学习控制语句
- 因为单单依靠“标识符、关键字、变量、运算符”等知识无法进行流程控制,而现实中的业务常常需要进行条件判断或循环执行等流程,如“小孩身高1.2m以下乘车免费,否则收费”
- 概述
- 控制语句即用来实现对程序流程的选择、循环、转向和返回等进行控制
控制语句有哪些
选择语句
- if
- 语法:if(布尔表达式){}
- if语句的任何一种形式在执行时只要有一个分支执行,则所对应的整个if语句就全部结束
- else/else if会与最近的if/else if匹配
- switch
- 语法:switch(int/String/enum){case int/String/enum: …}
- case可以合并
- 如果当前分支没有“break;”语句,则会发生case穿透现象,即下一个分支不再进行匹配,直接进入下一个分支执行,直到遇到break;语句或到末尾
- 用于几个常量数据的条件判断,一般要进行逻辑判断的找if
- default可以写在switch方括号里的任何位置,但它的执行时机永远不变,永远都是在所有分支都没有匹配成功的时候才会执行
循环语句
- 为什么要学习循环语句?
- 为了提高代码的复用性,对于一些重复代码,如果每次都写,那样既不美观也不现实
- for
- 语法:for(初始化表达式;布尔表达式;迭代表达式){循环体;}
- 初始化表达式最先执行,并且在整个循环当中只执行一次;布尔表达式的结果是true或false,true表示循环可以继续执行,false则循环终止;迭代表达式用于迭代某个变量,更新后可能布尔表达式的结果不再为true,换言之,一般是为了达到终止条件
- 执行顺序:先执行初始化表达式(若有的话),然后判断布尔表达式是否为true,若是,执行循环体;否则退出循环。执行完循环体后,执行迭代表达式(如果有的话),之后再判断布尔表达式是否为true……直到满足退出条件
- 初始化表达式;布尔表达式;迭代表达式都不是必须的,但是两个分号不能省略
- 注意初始化变量的作用域,如果是在for循环内创建,那么循环结束后该变量不复存在
- while
- 语法:while(布尔表达式){循环体;}
- 先判断再执行
- do…while
- 语法:do{}while(布尔表达式); 别忘while后面的分号
- 先执行后判断
转向语句
- 转向语句有什么用?
- 用于实现循环执行过程中程序流程的跳转
- 标号:紧跟着":"的标识符
- 标号必须放置语句块前面才有作用
- break
- 不带标号:即break;跳出当前循环
- 带标号:即break 标号;跳出标号所指的代码块,执行块后的下一条语句
- continue
- 不带标号:即continue;终止当前一轮循环,继续下一轮判断
- 带标号:即continue 标号;跳转到标号指明的外层循环,继续外层循环的下一轮判断
返回语句
- return
- 返回方法指定类型的值,也可以是对象
- 方法的结束
对于上述的各种结论,可以验证一下,说服自己接受
易错点
1、局部变量调用前需要初始化,全局变量若没有赋值,会按照缺省默认值初始化
public class Test{
public static void main(String[] args){
//变量使用前需初始化
int age;
System.out.println(age);
}
}
2、java语言默认整数型为int类型,long类型精度比int高,所以可以转换,但是当超过int类型范围却没有加L的就会出现错误
public class Test{
public static void main(String[] args) {
//当数值超过int(4个字节)类型最大值后,若想定义为long类型,
//需在后面加L,因为整数型默认字面值为int类型
/*Integer number too large*/
long num = 123456666666666666;
System.out.println(num);
}
}
3、Java中浮点类型的值默认为double类型
public class Test{
public static void main(String[] args) {
//不兼容的类型: 从double转换到float可能会有损失
float num = 10.5;
System.out.println(num);
}
}
4、boolean类型只有true或false
public class Test{
public static void main(String[] args) {
//不兼容的类型: int无法转换为boolean
boolean a = 1;
boolean b = 0;
System.out.println(a);
System.out.println(b);
}
}
5、类型转换测试
public class Test{
public static void main(String[] args) {
//默认转换:容量小的会直接转换为容量大的类型
//只要不超过范围可以把整数型赋值给char、short、byte
//错误: 不兼容的类型: 从int转换到byte可能会有损失
//byte是一个字节,1000已超过范围
byte a = 1000;
//从byte赋值给short可以,但是反之不行
short b = a;
//错误: 不兼容的类型: 从short转换到byte可能会有损失
a = b;
//错误: 已在方法 main(String[])中定义了变量 a
//变量重复命名
short a = 1000;
//可以用b赋值给c,因为有默认转换
long c = b;
//错误: 不兼容的类型: 从long转换到int可能会有损失
int d = c;
//强转后若数值太大,会截断,出现一个很奇怪的数
c = 1234567890123456L;
d = (int)c;
System.out.println(d);//1015724736
//先按照int类型相除然后再转化为double类型
double e = 10 / 3;
System.out.println(e);//3.0
//先转换为double类型然后相除
e = 10 / 3.0;
System.out.println(e);//3.3333333333333335
//错误: 不兼容的类型: 从long转换到int可能会有损失
//多个值运算时会先转换为容量最大的类型
long g = 10;
int h = g / 3;
System.out.println(h);
//错误: 不兼容的类型: 从int转换到byte可能会有损失
//会先把g转换为int类型,然后转换为byte类型,接着再除以3,
//因为3是int类型,所以会转换为int类型运算
byte i = (byte)(int)g / 3;
byte a = 1;
short b = 2;
char c = 'a';
//错误: 不兼容的类型: 从int转换到short可能会有损失
/*三个都错误,因为byte、short、char之间没有自动转换,
即使short取值范围大,但都是转换为int后才处理*/
b = a + b;
b = b + c;
b = a + c;
boolean c = 10 > 5;
System.out.println(c);
}
}
6、switch测试
6.1、switch后面的括号表达式可以取的数据类型
- switch后面只能跟byte、short、int、char、String、enum及前四者的包装类
- switch(表达式){case 值1……},case后面的值要和表达式的值一致
public class Test{
public static void main(String[] args) {
//L与数值之间不要分开
//long a = 2 L;
//错误: 不兼容的类型: 从long转换到int可能会有损失,
long a = 2L;
switch(a){}
//错误: 不兼容的类型: boolean无法转换为int,表达式不可以为Boolean类型
switch(5 > 10){}
//表达式可以为String类型
switch("ll"){
//错误: 不兼容的类型: int无法转换为String
case 1:
System.out.println("优秀");
break;
//错误: 不兼容的类型: int无法转换为String
case 2:
System.out.println("厉害啊");
break;
//错误: 不兼容的类型: int无法转换为String
case 3:
System.out.println("牛");
break;
default:
System.out.println("强");
}
//char类型与String类型不存在强转
switch("ll"){
//错误: 不兼容的类型: char无法转换为String
case '1':
System.out.println("优秀");
break;
//错误: 不兼容的类型: char无法转换为String
case '2':
System.out.println("厉害啊");
break;
//错误: 不兼容的类型: char无法转换为String
case '3':
System.out.println("牛");
break;
default:
System.out.println("强");
}
switch(1){
//错误: 不兼容的类型: 从double转换到int可能会有损失
//case后面的值都要为int类型
case 1.5:
System.out.println("优秀");
break;
case 2:
System.out.println("厉害啊");
break;
case 3:
System.out.println("牛");
break;
default:
System.out.println("强");
}
switch('a'){
//错误: case 标签重复
//97跟'a'在这里是一样的
case 97:
System.out.println("优秀");
break;
case 'a':
System.out.println("厉害啊");
break;
case 3:
System.out.println("牛");
break;
default:
System.out.println("强");
}
switch(1){
case 97:
System.out.println("优秀");
break;
//这里是short类型也可以输出,
//总结起来就是表达式可以为int、short、byte、char、String
case (short)1:
System.out.println("厉害啊");
break;
case 3:
System.out.println("牛");
break;
default:
System.out.println("强");
}
//可
switch(""){
case "ldh":
System.out.println("优秀");
break;
case "":
System.out.println("厉害啊");
break;
case "12":
System.out.println("牛");
break;
default:
System.out.println("强");
}
}
}
- 表达式也可以是一个枚举常量
public class Test {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
String size = s.next().toUpperCase();
switch (Enum.valueOf(Size.class,size)){
case MEDIUM:
System.out.println('m');
break;
case LARGE:
System.out.println('l');
break;
case SMALL:
System.out.println('s');
break;
}
}
}
6.2、case穿透
- default可以在switch里的任何位置,且执行时机不变,但其若在前面又不带break;语句,则也有可能出现穿透现象
- 以下代码输出
white
blue
yellow
public class Test {
public static void main(String[] args) {
String color = "blind";
switch(color){
default:
System.out.println("white");
case "blue":
System.out.println("blue");
case "yellow":
System.out.println("yellow");
break;
case "red":
System.out.println("red");
break;
}
}
}
7、短路与与逻辑与
public class Test {
public static void main(String[] args) {
int x = 5;
if((--x) >= 5 && (x--) >= 4)
System.out.println(x);
System.out.println(x);//4
if((--x) >= 4 & (x--) >= 3)
System.out.println(x);
System.out.println(x);//2
}
}
8、else if/else的最近匹配原则
- 注意,不是说如果有多个else if就只有第一条是和最近的else if/if匹配,视情况而定,有时候可能会所有else if语句都和最近的if/else if匹配
public class Test {
public static void main(String[] args) {
/*没有输出*/
int x = 0;
if(x > 0)
if(x > 5) System.out.println(5);
else System.out.println(6);
}
}
- 所有else if语句都和最近的if匹配
//输出2
public class Test {
public static void main(String[] args) {
int x = 9;
if(x 10)
if(x 6) System.out.println(1);
else if(x 10) System.out.println(2);
else if(x 15) System.out.println(3);
}
}
- 不是所有else if语句都和最近的if/else if匹配
//输出4
public class Test {
public static void main(String[] args) {
int x = 11;
if(x 10)
if(x 6) System.out.println(1);
else if(x 10) System.out.println(2);
else System.out.println(3);
else if(x 15) System.out.println(4);
}
}
9、for循环的循环条件部分不可使用逗号语句
public class Test {
public static void main(String[] args) {
//循环条件部分不能使用逗号语句,否则出现找不到j,缺少分号等错误
for(int i = 1,j = 2;i <= 10,j <= 100;i ++,j ++){}
}
}
10、标号必须在代码块前,但不一定要在循环前
public class Test {
public static void main(String[] args) {
int x = 5;
first:if((--x) >= 5 && (x--) >= 4){}
second:switch (x){}
/*Not a statement*/
//third:int y = 5;
third:{int y = 5;}
}
}