本文介绍了Java的
注释
、标识符
、关键字/保留字
、变量
、常量
、基本数据类型
、运算符
、类型转换
、简单的键盘输入和输出
、控制语句
、方法重载
。
注释
为了方便程序的阅读,Java语言允许程序员在程序中写上一些说明性的文字,用来提高程序的可读性,这些文字性的说明就称为注释。 注释不会出现在字节码文件中,即Java编译器编译时会跳过注释语句。 在Java中根据注释的功能不同,主要分为单行注释、多行注释和文档注释。
单行注释
:使用“//”开头,“//”后面的单行内容均为注释。多行注释
:以“/*”开头以“*/”结尾,在“/*”和“*/”之间的内容为注释,我们也可以使用多行注释作为行内注释。但是在使用时要注意,多行注释不能嵌套使用。文档注释
:以“/**”开头以“*/”结尾,注释中包含一些说明性的文字及一些JavaDoc标签(后期写项目时,可以生成项目的API)
1 | /** |
标识符
标识符是用来给变量、类、方法以及包进行命名的,如Welcome、main、System、age、name、gender等。标识符需要遵守一定的规则:
- 标识符必须以字母、下划线_、美元符号$开头。
- 标识符其它部分可以是字母、下划线“_”、美元符“$”和数字的任意组合。
- Java 标识符大小写敏感,且长度无限制。
- 标识符不可以是Java的关键字。
标识符的使用规范
- 表示类名的标识符:每个单词的首字母大写,如Man, GoodMan
- 表示方法和变量的标识符:第一个单词小写,从第二个单词开始首字母大写,我们称之为“驼峰原则”,如eat(), eatFood()
【注意】:Java不采用通常语言使用的ASCII字符集,而是采用Unicode这样标准的国际字符集。因此,这里字母的含义不仅仅是英文,还包括汉字等等。但是不建议大家使用汉字来定义标识符!
示例:合法的标识符
1 | int a = 3; |
示例:不合法的标识符
1 | int 1a = 3; //不能用数字开头 |
关键字/保留字
Java关键字是Java语言保留供内部使用的,如class用于定义类。 关键字也可以称为保留字,它们的意思是一样的,我们不能使用关键字作为变量名或方法名。
变量
变量的本质
变量
本质上就是代表一个”可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定。我们可通过变量名来访问“对应的存储空间”,从而操纵这个“存储空间”存储的值。Java是一种
强类型语言
,每个变量都必须声明其数据类型。变量的数据类型决定了变量占据存储空间的大小。 比如,int a=3; 表示a变量的空间大小为4个字节。变量作为程序中最基本的存储单元,其要素包括变量名,
变量类型
和作用域
。变量在使用前必须对其声明, 只有在变量声明以后,才能为其分配相应长度的存储空间。
变量的声明格式为:
1 | type varName [=value][,varName[=value]...]; |
示例:声明变量:
1 | double salary; |
不同数据类型的常量会在内存中分配不同的空间,如下图所示:
注意事项
- 每个变量都有类型,类型可以是基本类型,也可以是引用类型。
- 变量名必须是合法的标识符
- 变量声明是一条完整的语句,因此每一个声明都必须以分号结束
示例:在一行中声明多个变量
1 | int i ,j; // 两个变量的数据类型都是int |
建议:不提倡这种”一行声明多个变量”风格,逐一声明每一个变量可以提高程序可读性。
示例:可以将变量的声明和初始化放在同一行中
1 | int age = 18; |
变量的分类
从整体上可将变量划分为局部变量、成员变量(也称为实例变量)和静态变量。
类型 | 声明位置 | 从属于 | 生命周期 |
---|---|---|---|
局部变量 | 方法或语句块内部 | 方法/语句块 | 从声明位置开始,直到方法或语句块执行完毕,局部变量消失 |
成员变量(实例变量) | 类内部,方法外部 | 对象 | 对象创建,成员变量也跟着创建。对象消失,成员变量也跟着消失; |
静态变量(类变量) | 类内部,static修饰 | 类 | 类被加载,静态变量就有效;类被卸载,静态变量消失。 |
- 局部变量(local variable)
方法或语句块内部定义的变量。生命周期是从声明位置开始到到方法或语句块执行完毕为止。局部变量在使用前必须先声明、初始化(赋初值)再使用。
示例:局部变量
1 | public void test() { |
- 成员变量(也叫实例变量 member variable)
方法外部、类的内部定义的变量。从属于对象,生命周期伴随对象始终。如果不自行初始化,它会自动初始化成该类型的默认初始值。
数据类型 | 初始值 |
---|---|
int | 0 |
double | 0.0 |
char | ‘\u0000’ |
boolean | false |
示例:实例变量的声明
1 | public class Test { |
- 静态变量(类变量 static variable)
使用static定义。 从属于类,生命周期伴随类始终,从类加载到卸载。 (注:讲完内存分析后我们再深入!先放一放这个概念!)如果不自行初始化,与成员变量相同会自动初始化成该类型的默认初始值,如表上所示。
测试代码
1 | /** |
常量
常量通常指的是一个固定的值,例如:1、2、3、’a’、’b’、true、false、”helloWorld”等。
在Java语言中,主要是利用关键字final来定义一个常量。 常量一旦被初始化后不能再更改其值。
声明格式为:
1 | final type varName = value; |
常量的声明及使用
1 | public class TestConstants { |
为了更好的区分和表述,一般将1、2、3、’a’、’b’、true、false、”helloWorld”等称为字面常量,而使用final修饰的PI等称为符号常量。
变量和常量命名规范:
- 所有变量、方法、类名:见名知意
- 类成员变量:首字母小写和驼峰原则: monthSalary
- 局部变量:首字母小写和驼峰原则
- 常量:大写字母和下划线:MAX_VALUE
- 类名:首字母大写和驼峰原则: Man, GoodMan
- 方法名:首字母小写和驼峰原则: run(), runRun()
基本数据类型
Java是一种强类型语言,每个变量都必须声明其数据类型。 Java的数据类型可分为两大类:基本数据类型(primitive data type)和引用数据类型(reference data type)。
Java中定义了3类8种
基本数据类型:
- 数值型- byte、 short、int、 long、float、 double
- 字符型- char
- 布尔型- boolean
注意事项:引用数据类型的大小统一为4个字节,记录的是其引用对象的地址!
整型变量/常量
整型用于表示没有小数部分的数值,它允许是负数。整型的范围与运行Java代码的机器无关,这正是Java程序具有很强移植能力的原因之一。与此相反,C和C++程序需要针对不同的处理器选择最有效的整型。
Java 语言整型常量的四种
表示形式:
- 十进制整数,如:99, -500, 0
- 八进制整数,要求以 0 开头,如:015
- 十六进制数,要求 0x 或 0X 开头,如:0x15
- 二进制数,要求0b或0B开头,如:0b01110011
Java语言的整型常数默认为 int 型,声明 long 型常量可以后加‘ l ’或‘ L ’ 。
示例:长整型常数的声明
1 | long a = 55555555; //编译成功,在int表示的范围内(21亿内)。 |
我们修改成long类型的常量即可:
1 | long b = 55555555555L; |
浮点型变量/常量
带小数的数据在Java中称为浮点型。浮点型可分为float类型和double类型。
float 类型又被称作
单精度类型
,尾数可以精确到7位有效数字,在很多情况下,float类型的精度很难满足需求。而double表示这种类型的数值精度约是float类型的两倍,又被称作双精度类型,绝大部分应用程序都采用double类型。浮点型常量默认类型也是double。
Java浮点类型常量有两种表示形式
- 十进制数形式,例如:3.14 314.0 0.314
- 科学记数法形式,如314e2 314E2 314E-2
示例:使用科学记数法给浮点型变量赋值
1 | double f = 314e2; //314*10^2-->31400.0 |
float类型的数值有一个后缀F或者f ,没有后缀F/f的浮点数值默认为double类型。也可以在浮点数值后添加后缀D或者d, 以明确其为double类型。
示例:float类型赋值时需要添加后缀F/f
1 | float f = 3.14F; |
建议:浮点类型float,double的数据不适合在不容许舍入误差的金融计算领域。如果需要进行不产生舍入误差的精确数字计算,需要使用BigDecimal
类。
示例:浮点数的比较一
1 | float f = 0.1f; |
示例:浮点数的比较二
1 | float d1 = 423432423f; |
运行以上两个示例,发现示例2-13的结果是“false”,而示例2-14的输出结果是“d1==d2”。这是因为由于字长有限,浮点数能够精确表示的数是有限的,因而也是离散的。 浮点数一般都存在舍入误差,很多数字无法精确表示(例如0.1),其结果只能是接近, 但不等于。二进制浮点数不能精确的表示0.1、0.01、0.001这样10的负次幂。并不是所有的小数都能可以精确的用二进制浮点数表示。
java.math包下面的两个有用的类:BigInteger
和BigDecimal
,这两个类可以处理任意长度的数值。BigInteger实现了任意精度的整数运算。BigDecimal实现了任意精度的浮点运算。
菜鸟雷区:
不要使用浮点数进行比较!很多新人甚至很多理论不扎实的有工作经验的程序员也会犯这个错误!需要比较请使用BigDecimal
类
示例:使用BigDecimal
进行浮点数的比较
1 | import java.math.BigDecimal; |
字符型变量/常量
字符型
在内存中占2个字节,在Java中使用单引号
来表示字符常量
。例如’A’是一个字符,它与”A”是不同的,”A”表示含有一个字符的字符串
。
char
类型用来表示在Unicode
编码表中的字符。Unicode
编码被设计用来处理各种语言的文字,它占2个字节,可允许有65536个字符。
示例:字符型举例
1 | char eChar = 'a'; |
Unicode
具有从0到65535之间的编码,他们通常用从’\u0000’
到’\uFFFF’
之间的十六进制值来表示(前缀为u表示Unicode)
示例:字符型的十六进制值表示方法
1 | char c = '\u0061'; |
Java 语言中还允许使用转义字符 ‘\’ 来将其后的字符转变为其它的含义。常用的转义字符及其含义和Unicode值如下表所示。
示例:转义字符
1 | char c2 = '\n'; //代表换行符 |
注意事项:String类,其实是字符序列(char sequence)。
boolean类型变量/常量
boolean类型有两个常量值,true和false,在内存中占一位(不是一个字节),不可以使用 0 或非 0 的整数替代 true 和 false ,这点和C语言不同。 boolean 类型用来判断逻辑条件,一般用于程序流程控制 。
示例:boolean类型
1 | boolean flag ; |
运算符
计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操作变量。
运算符分类
算术运算符
算术运算符中+,-,*,/,%属于二元运算符,二元运算符指的是需要两个操作数才能完成运算的运算符。其中的%是取模运算符,就是我们常说的求余数操作。
二元运算符的运算规则:
- 整数运算:
- 如果两个操作数有一个为Long, 则结果也为long。
- 没有long时,结果为int。即使操作数全为short,byte,结果也是int。
- 浮点运算:
- 如果两个操作数有一个为double,则结果为double。
- 只有两个操作数都是float,则结果才为float。
- 取模运算:
- 其操作数可以为浮点数,一般使用整数,结果是“余数”,“余数”符号和左边操作数相同,如:7%3=1,-7%3=-1,7%-3=1。
算术运算符中++,–属于一元运算符,该类运算符只需要一个操作数。
示例:一元运算符++与--
1 | int a = 3; |
运行该程序,执行结果如下图所示:
赋值及其扩展赋值运算符
赋值及其扩展运算符
运算符 | 用法举例 | 等效的表达式 |
---|---|---|
+= | a += b | a = a+b |
-= | a -= b | a = a-b |
*= | a *= b | a = a*b |
/= | a *= b | a = a/b |
%= | a *= b | a = a%b |
示例:扩展运算符
1 | int a=3; |
运行该程序,执行结果如下图所示:
关系运算符
关系运算符用来进行比较运算,如表2-9所示。关系运算的结果是布尔值:true/false;
关系运算符
运算符 | 含义 | 示例 |
---|---|---|
== | 等于 | a==b |
!= | 不等于 | a!=b |
> | 大于 | a>b |
< | 小于 | a<b |
>= | 大于或等于 | a>=b |
<= | 小于或等于 | a<=b |
注意事项
=是赋值运算符,而真正的判断两个操作数是否相等的运算符是==。
==、!= 是所有(基本和引用)数据类型都可以使用
> 、>=、 <、 <= 仅针对数值类型(byte/short/int/long, float/double。以及char)
逻辑运算符
Java中的逻辑运算符如下表所示。逻辑运算的操作数和运算结果都是boolean值。
运算符 | 说明 |
---|---|
逻辑与 | &( 与) 两个操作数为true,结果才是true,否则是false |
逻辑或 | |(或) 两个操作数有一个是true,结果就是true |
短路与 | &&( 与) 只要有一个为false,则直接返回false |
短路或 | ||(或) 只要有一个为true, 则直接返回true |
逻辑非 | !(非) 取反:!false为true,!true为false |
逻辑异或 | ^(异或) 相同为false,不同为true |
短路与和短路或采用短路的方式。从左到右计算,如果只通过运算符左边的操作数就能够确定该逻辑表达式的值,则不会继续计算运算符右边的操作数,提高效率。
示例:短路与和逻辑与
1 | //1>2的结果为false,那么整个表达式的结果即为false,将不再计算2>(3/0) |
位运算符
位运算指的是进行二进制位的运算,常用的位运算符如下表所示。
位运算符 | 说明 |
---|---|
~ | 取反 |
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
<< | 左移运算符,左移1位相当于乘2 |
>> | 右移运算符,右移1位相当于除2取商 |
示例:左移运算和右移运算
1 | int a = 3*2*2; |
注意
- &和|既是逻辑运算符,也是位运算符。如果两侧操作数都是boolean类型,就作为逻辑运算符。如果两侧的操作数是整数类型,就是位运算符。
- 不要把“^”当做数学运算“乘方”,是“位的异或”操作。
字符串连接符
“+”运算符两侧的操作数中只要有一个是字符串(String)类型,系统会自动将另一个操作数转换为字符串然后再进行连接。
示例:连接符“+”
1 | int a=12; |
条件运算符
语法格式:
1 | x ? y : z |
其中 x 为 boolean 类型表达式,先计算 x 的值,若为true,则整个运算的结果为表达式 y 的值,否则整个运算结果为表达式 z 的值。
示例:三目条件运算符
1 | int score = 80; |
运行结果如下图所示。
运算符优先级
优先级 | 运算符 | 类 | 结合性 |
---|---|---|---|
1 | () | 括号运算符 | 由左至右 |
2 | !、+(正号)、-(负号) | 一元运算符 | 由左至右 |
2 | ~ | 位逻辑运算符 | 由右至左 |
2 | ++、– | 递增与递减运算符 | 由右至左 |
3 | *、/、% | 算术运算符 | 由左至右 |
4 | +、- | 算术运算符 | 由左至右 |
5 | <<、>> | 位左移、右移运算符 | 由左至右 |
6 | >、>=、<、<= | 关系运算符 | 由左至右 |
7 | ==、!= | 关系运算符 | 由左至右 |
8 | & | 位运算符、逻辑运算符 | 由左至右 |
9 | ^ | 位运算符、逻辑运算符 | 由左至右 |
10 | | | 位运算符、逻辑运算符 | 由左至右 |
11 | && | 逻辑运算符 | 由左至右 |
12 | || | 逻辑运算符 | 由左至右 |
13 | ? : | 条件运算符 | 由右至左 |
14 | =、+=、-=、*=、/=、%= | 赋值运算符、扩展运算符 | 由右至左 |
建议:
- 逻辑与、逻辑或、逻辑非的优先级一定要熟悉!(逻辑非>逻辑与>逻辑或)。如:
- a||b&&c的运算结果是:a||(b&&c),而不是(a||b)&&c
类型转换
自动类型转换
自动类型转换指的是容量小的数据类型可以自动转换为容量大的数据类型。如图2-6所示,黑色的实线表示无数据丢失的自动类型转换,而虚线表示在转换时可能会有精度的损失。
可以将整型常量直接赋值给byte、 short、 char等类型变量,而不需要进行强制类型转换,只要不超出其表数范围即可。
示例:自动类型转换特例
1 | short b = 12; //合法 |
强制类型转换
强制类型转换,又被称为造型,用于显式的转换一个数值的类型。在有可能丢失信息的情况下进行的转换是通过造型来完成的,但可能造成精度降低或溢出。
语法格式:
1 | (type)var |
运算符“()”中的type表示将值var想要转换成的目标数据类型。
示例:强制类型转换
1 | double x = 3.14; |
运行结果如下图所示。
当将一种类型强制转换成另一种类型,而又超出了目标类型的表数范围,就会被截断成为一个完全不同的值。
示例:强制类型转换特例
1 | int x = 300; |
注:不能在布尔类型和任何数值类型之间做强制类型转换
基本类型转化时常见错误和问题
- 操作比较大的数时,要留意是否溢出,尤其是整数操作时。
示例:常见问题一
1 | int money = 1000000000; //10亿 |
运行结果如下图所示。
L
和l
的问题:
不要命名名字为 l
的变量,l
容易和 1
混淆。long
类型使用大写 L
不要用小写。
示例:常见问题二
1 | int l = 2; //分不清是L还是1, |
简单的键盘输入和输出
为了我们能写出更加复杂的程序,可以让我们的程序和用户可以通过键盘交互,我们先学习一下简单的键盘输入和输出。
示例:使用Scanner获取键盘输入
1 | import java.util.Scanner; |
运行结果如下图所示。
控制语句
带标签的break
和continue
goto关键字很早就在程序设计语言中出现。尽管goto仍是Java的一个保留字,但并未在Java语言中得到正式使用;Java没有goto语句。然而,在
break
和continue
这两个关键字的身上,我们仍然能看出一些goto的影子—带标签的break和continue。“
标签
”是指后面跟一个冒号的标识符,例如:“label:”。对Java来说唯一用到标签的地方是在循环语句之前。而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另一个循环,由于break
和continue
关键字通常只中断当前循环,但若随同标签使用,它们就会中断到存在标签的地方。在 “goto有害”论中,最有问题的就是标签,而非goto, 随着标签在一个程序里数量的增多,产生错误的机会也越来越多。 但Java标签不会造成这方面的问题,因为它们的活动场所已被限死,不可通过特别的方式到处传递程序的控制权。由此也引出了一个有趣的问题:通过限制语句的能力,反而能使一项语言特性更加有用。
示例:带标签break和continue:控制嵌套循环跳转(打印101-150之间所有的质数)
1 | public class Test18 { |
switch多选择结构
语法结构:
1 | switch (表达式) { |
switch
语句会根据表达式的值从相匹配的case
标签处开始执行,一直执行到break
语句处或者是switch
语句的末尾。如果表达式的值与任一case
值不匹配,则进入default
语句(如果存在default
语句的情况)。根据表达式值的不同可以执行许多不同的操作。
switch
语句中case
标签在JDK1.5之前必须是整数(long
类型除外)或者枚举,不能是字符串,在JDK1.7之后允许使用字符串(String
)。注意,当布尔表达式是等值判断的情况,可以使用if-else if-else多选择结构或者switch结构,如果布尔表达式区间判断的情况,则只能使用if-else if-else多选择结构。
方法重载
方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。
注:重载的方法,实际是完全不同的方法,只是名称相同而已!
构成方法重载的条件:
不同的含义:
形参类型
、形参个数
、形参顺序
不同只有返回值不同不构成方法的重载,如:
1 | //不构成方法重载 |
- 只有形参的名称不同,不构成方法的重载,如:
1 | //不构成方法重载 |
示例:方法重载
1 | public class Test21 { |