Java 简介与安装、语法说明、数据类型、运算符
Java 介绍
Java 简介
- Java 是美国 Sun 公司(Stanford University Network)在 1995 年推出的计算机语言。
- Java 之父:詹姆斯·高斯林(James Gosling)
- 2009 年,Sun 公司被甲骨文公司收购。
Java 语言的三个版本:
- JavaSE: Java 语言的标准版,用于桌面应用的开发,是以下两个版本的基础。
- JavaME: Java 语言的小型版,用于嵌入式消费类电子设备。
- JavaEE: Java 语言的企业版,用于 Web 方向的网站开发。
Java 语言跨平台原理
Java 程序并非是直接运行的,而是 Java 编译器将 Java 源程序编译成与平台无关的字节码文件(class 文件)
,然后由 Java 虚拟机(JVM)对字节码文件解释执行。
所以在不同的操作系统下,只需安装不同的 Java 虚拟机即可实现 Java 程序的跨平台。
JRE 和 JDK
- JVM(Java Virtual Machine):Java 虚拟机。
- JRE(Java Runtime Environment):Java 运行环境,包含了 JVM 和 Java 的核心类库(Java API)。
- JDK(Java Development Kit):Java 开发工具,包含了 JRE 和开发工具。
总结:只需安装 JDK 即可,它包含了 Java 的运行环境和虚拟机。
JDK 下载/安装说明
通过 Oracle 官方网站下载对应版本的 JDK。
JDK 安装目录说明:
目录名称 | 说明 |
---|---|
bin | 该路径下存放了 JDK 的各种工具命令,如 javac 和 java 就放在这个目录。 |
conf | 该路径下存放了 JDK 的相关配置文件。 |
include | 该路径下存放了一些平台特定的头文件。 |
jmods | 该路径下存放了 JDK 的各种模块。 |
legal | 该路径下存放了 JDK 各模块的授权文档。 |
lib | 该路径下存放了 JDK 工具的一些补充 JAR 包。 |
Java 语法说明
“Hello World”示例:
main() 方法详解:
public
:表示公共的。权限是最大的,在任何情况下都可以访问。- 原因:为了保证 JVM 在任何情况下都可以访问到 main 方法。
static
:可以使 JVM 调用 main 方法更加方便,而不需要通过对象调用。- 不使用 static 修饰的麻烦:
- 需要创建对象调用。
- JVM 不知道如何创建对象,因为创建对象有些是需要参数的。
- 不使用 static 修饰的麻烦:
void
:因为返回的数据是给 JVM 的,而 JVM 使用这个数据是没有意义的。main
:函数名。arguments
:担心某些程序在启动时需要参数。
问题 1:一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?
- 可以有多个类,但只能有一个 public 的类,并且 public 的类名必须与文件名相一致。一个文件中可以只有非 public 类,如果只有一个非 public 类,那么此类可以跟文件名不同。
问题 2:为什么一个 Java 源文件中只能有一个 public 类?
- 在 Java 编程思想(第四版)一书中有这样 3 段话(6.4 类的访问权限):
- 每个编译单元(文件)都只能有一个 public 类,这表示,每个编译单元都有单一的公共接口,用 public 类来表现。该接口可以按要求包含众多的支持包访问权限的类。如果在某个编译单元内有一个以上的 public 类,编译器就会给出错误信息。
- public 类的名称必须完全与含有该编译单元的文件名相同,包含大小写。如果不匹配,同样将得到编译错误。
- 虽然不是很常用,但编译单元内完全不带 public 类也是可能的。在这种情况下,可以随意对文件命名。
注释
注释是对代码的解释和说明文字,可以提高程序的可读性,因此在程序中添加必要的注释文字十分重要。
Java 中的注释分为三种:
1)单行注释
:单行注释的格式是使用//
,从//
开始至本行结尾的文字将作为注释文字。
// 单行注释
2)多行注释
:多行注释的格式是使用/*
和*/
将一段较长的注释括起来。
/*
多行注释
注意:多行注释不能嵌套使用
*/
3)文档注释
:文档注释以/**
开始,以*/
结束,是 Java 特有的注释,其中注释内容可以被 JDK 提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档。
Javadoc –d 指定存储文档的路径 -version –author(可选参数) 目标文件
关键字
Java 的关键字对 Java 的编译器有特殊的意义,他们常被用来表示一种数据类型,或者表示程序的结构等。关键字不能用作变量名、方法名、类名、包名。
关键字的特点:
- 关键字的字母全部小写。
- 常用的代码编辑器对关键字都有高亮显示,比如 public、class、static 等。
- 注意:main 不是关键字,但可以理解为比关键字更为关键的单词,是 JVM 唯一识别的单词。
标识符
标识符是程序员在编写 Java 程序时,自定义的一些名字,例如 helloworld 程序里关键字 class 后跟的“HelloWorld”,就是我们定义的类名。类名就属于标识符的一种。
标识符除了应用在类名上,还可以用在变量、函数名、包名上。
标识符必须遵循以下规则:
- 标识符由英文字母(a~zA~Z)、数字(0~9)、下划线(_)和美元符号($)组成。
- 不能以数字开头,不能是关键字。
- 区分大小写。
- 标识符可以为任意长度。
Java 中的标识符命名规范:
项目名
:多个单词组成时所有字母小写(例:workdesk、jobserver)包名
:多个单词组成时所有字母小写(例:package、com.util)类名和接口名
:多个单词组成时所有单词的首字母大写(例:HelloWorld)变量名和函数名
:多个单词组成时,首个单词首字母小写,后面单词首字母大写(例:lastAccessTime、getTime)。常量名
:多个单词组成时,字母全部大写,多个单词之间使用_分隔(例:INTEGER_CACHE)
注意:上述只是为了增加代码规范性、可读性而做的一种约定,但在定义标识符时最好还是见名知意,提高代码阅读性。
数据类型
Java 是一个强类型语言,其数据必须明确数据类型。
在 Java 中,数据类型包括基本数据类型和引用数据类型两种。
基本数据类型
Java 的基本数据类型有 4 类 8 种:
四类 | 八种 | 内存占用 (字节) |
取值范围 | 说明 |
---|---|---|---|---|
整数类型 | byte | 1 | 最小值是 -128(-2^7) 最大值是 127(2^7-1) 默认值是 0 |
byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一。 |
short | 2 | 最小值是 -32768(-2^15) 最大值是 32767(2^(15-1)) 默认值是 0 |
short 数据类型也可以像 byte 那样节省空间。一个 short 变量是 int 型变量所占空间的二分之一。 | |
int | 4 | 最小值是 -2,147,483,648(-2^31) 最大值是 2,147,483,647(2^(31-1)) 默认值是 0 |
整数默认是 int 类型(因此 byte、short 和 char 类型数据在参与整数运算均会自动转换为 int 类型) | |
long | 8 | 最小值是 -9,223,372,036,854,775,808(-2^63) 最大值是 9,223,372,036,854,775,807(2^(63-1)) 默认值是 0L |
这种类型主要使用在需要比较大整数的系统上; "L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。 |
|
浮点类型 | float | 4 | 默认值是 0.0f | float 数据类型是单精度、32 位、符合IEEE 754 标准的浮点数; 范围规模可变,保留 7 位小数; float 在储存大型浮点数组的时候可节省内存空间; 浮点数不能用来表示精确的值,如货币; |
double(默认类型) | 8 | 默认值是 0.0d | double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数; 范围规模可变,保留 15 位小数; 浮点数的默认类型为 double 类型; double类型同样不能表示精确的值,如货币。 |
|
字符类型 | char | 2 | 最小值是 \u0000(十进制等效值为 0) 最大值是 \uffff(即为 65535) |
char 类型是一个单一的 16 位 Unicode 字符; char 数据类型可以存储任何字符。 |
布尔类型 | boolean | 1 | 只有两个取值:true 和 false 默认值是 false |
boolean 数据类型表示一位的信息。 |
引用数据类型
引用数据类型有类(class)、接口(Interface)、数组(Array)等。
// 声明两个 Book 的引用变量并创建两个 Book 对象,然后将 Book 对象赋值给引用变量。
Book b = new Book();
Book c = new Book();
b = c; // 把变量 c 赋值给变量 b,此时 b、c 对应 Book2,而 Book1 已经没有引用,会被垃圾回收。
c = null; // 代表它不再引用任何事物,但还是个可以被指定引用其他Book的引用变量。
隐式类型转换
隐式类型转换是指把一个表示数据范围小的数值或者变量赋值给另一个表示数据范围大的变量。
这种转换方式是自动的,直接书写即可。例如:
double num = 10; // 将 int 类型的 10 直接赋值给 double 类型
System.out.println(num); // 输出 10.0
整数默认是 int 类型,因此 byte、short 和 char 类型数据在参与整数运算均会自动转换为 int 类型。
即多个不同数据类型的数据在运算的时候,结果取决于大的数据类型。
强制类型转换
强制类型转换是指把一个表示数据范围大的数值或者变量赋值给另一个表示数据范围小的变量。
强制类型转换格式:目标数据类型 变量名 = (目标数据类型)值或者变量;
double num1 = 5.5;
int num2 = (int) num1; // 将 double 类型的 num1 强制转换为 int 类型
System.out.println(num2); // 输出 5(小数位直接舍弃)
byte a = 3;
byte b = 4;
byte c = a + b; // 报错。因为两个 byte 变量相加,会先提升为 int 类型
byte d = 3 + 4; // 正确。常量优化机制
常量优化机制:编译器在编译的时候能确认常量的值,但不能确认变量的值(变量存储的值只有在运行的时候才会在内存分配空间)
。
在上例中,在编译时,整数常量的计算会直接算出结果,并且会自动判断该结果是否在 byte 取值范围内,在则编译通过,不在则编译失败。
查看数据类型
public static void main(String[] args) {
int n1 = 1;
Integer n2 = 1;
String s = "1";
Book book = new Book();
// System.out.println(n1.getClass().getName()); 此行报错;需使用下行的间接方法
System.out.println(getType(n1)); // class java.lang.Integer
System.out.println(n2.getClass().getName()); // java.lang.Integer
System.out.println(s.getClass().getName()); // java.lang.String
}
public static String getType(Object o){ // 获取变量类型方法
return o.getClass().toString(); // 使用int类型的getClass()方法
}
变量
变量的定义:在程序运行过程中,其值可以发生改变的量。
从本质上讲,变量是内存中的一小块区域,其值可以在一定范围内变化。
变量的定义方式有如下 3 种:
1)声明变量并赋值
数据类型 变量名 = 初始化值;
int age = 18;
System.out.println(age);
2)先声明,后赋值
(在使用前赋值即可)
数据类型 变量名;
变量名 = 初始化值;
double money;
money = 55.5;
System.out.println(money);
3)在同一行定义多个同一种数据类型的变量
,中间使用逗号隔开。但不建议使用这种方式,因为降低了程序的可读性。
int a = 10, b = 20; // 定义int类型的变量a和b,中间使用逗号隔开
System.out.println(a);
System.out.println(b);
int c, d; // 声明int类型的变量c和d,中间使用逗号隔开
c = 30;
d = 40;
System.out.println(c);
System.out.println(d);
变量的修改:
int a = 10;
a = 30; // 变量前面不加数据类型时,表示修改已存在的变量的值。
System.out.println(a);
运算符
算术运算符
符号 | 作用 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余 |
小数运算:
// 整数操作只能得到整数,要想得到小数,必须有浮点数参与运算。
int a = 10;
int b = 3;
System.out.println(a / b); // 输出结果 3
System.out.println(a % b); // 输出结果 1
取余的结果正负:
int num = -10; // 运算结果正负取决于被除数的正负
System.out.println(num % 2); // 0
System.out.println(num % -3); // -1
System.out.println(num % 4); // -2
System.out.println(num % 5); // 0
System.out.println(num % -6); // -4
字符
的+
操作:
char 类型参与算术运算,使用的是计算机底层对应的十进制数值:
- 'a' -- 97
- 'A' -- 65
- '0' -- 48
// 可以通过使用字符与整数做算术运算,得出字符对应的数值是多少
char ch1 = 'a';
System.out.println(ch1 + 1); // 输出 98(97 + 1 = 98)
char ch2 = 'A';
System.out.println(ch2 + 1); // 输出 66(65 + 1 = 66)
char ch3 = '0';
System.out.println(ch3 + 1); // 输出 49(48 + 1 = 49)
数据类型隐式提升:
算术表达式中包含不同的基本数据类型的值的时候,整个算术表达式的类型会自动进行提升。
提升规则:
- byte、short 和 char 类型自动提升到 int 类型,不管是否有其他类型参与运算。
- 整个表达式的类型自动提升到与表达式中最高等级的操作数相同的类型。等级顺序:
byte、short、char --> int --> long --> float --> double
byte b1 = 10;
byte b2 = 20;
// byte b3 = b1 + b2; // 该行报错,因为 byte 类型参与算术运算会自动提示为 int,而 int 赋值给 byte 可能会导致精度损失
int i3 = b1 + b2; // 应该使用 int 接收
byte b3 = (byte) (b1 + b2); // 或者将结果强制转换为 byte 类型
int num1 = 10;
double num2 = 20.0;
double num3 = num1 + num2; // 使用 double 接收,因为 num1 会自动提升为 double 类型
字符串
的+
操作:
在“+”操作中,如果出现了字符串,就是连接运算符
,否则就是算术运算。当连续进行“+”操作时,从左到右逐个执行。
System.out.println(1 + 99 + "年"); // 输出:100年
System.out.println(1 + 2 + "+" + 3 + 4); // 输出:3+34
// 可以使用小括号改变运算的优先级
System.out.println(1 + 2 + "+" + (3 + 4)); // 输出:3+7
数值拆分:
需求:键盘录入一个三位数,将其个位、十位、百位数的值分别打印在控制台。
import java.util.Scanner;
public class Day1 {
public static void main(String[] arg){
// 1. 使用Scanner键盘录入一个三位数
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个三位数:");
int num = sc.nextInt();
// 2. 个位的计算:数值 % 10
int ge = num % 10;
// 3. 十位的计算:数值 / 10 % 10
int shi = num / 10 % 10;
// 4. 百位的计算:数值 / 100
int bai = num / 100;
// 5. 将个位、十位、百位拼接上正确的字符串, 打印即可
System.out.println("整数"+num+"个位为:"+ge);
System.out.println("整数"+num+"十位为:"+shi);
System.out.println("整数"+num+"百位为:"+bai);
}
}
自增自减运算符
符号 | 作用 | 说明 |
---|---|---|
++ | 自增 | 变量的值加 1 |
-- | 自减 | 变量的值减 1 |
注意事项:
- ++ 和 -- 既可以放在变量的后边,也可以放在变量的前边。
- 单独使用的时候, ++ 和 -- 无论是放在变量的前边还是后边,结果是一样的。
- 参与操作的时候,如果 ++/-- 放在变量的后边,则先拿变量参与操作,后拿变量做 ++ 或者 -- 运算;如果 ++/-- 放在变量的前边,则先拿变量做 ++ 或者 -- 运算,后拿变量参与操作。
- 最常见的用法:单独使用。
int i = 10;
i++; // 单独使用
System.out.println("i:"+i); // i:11
int j = 10;
++j; // 单独使用
System.out.println("j:"+j); // j:11
int x = 10;
int y = x++; // 赋值运算,++ 在后边,所以是使用 x 原来的值赋值给 y,x 本身自增 1
System.out.println("x:"+x+ ", y:"+y); // x:11,y:10
int m = 10;
int n = ++m; // 赋值运算,++ 在前边,所以是使用 m 自增后的值赋值给 n,m 本身自增 1
System.out.println("m:"+m+", m:"+m); // m:11,m:11
思考题:
int x = 10;
int y = x++ + x++ + x++;
System.out.println(y); // y 的值是多少?
/*
解析,三个表达式都是 ++ 在后,所以每次使用的都是自增前的值,而程序是从左至右执行的,所以第一次自增时,使用的是 10 进行计算;第二次自增时,x 的值已经自增到 11 了,所以第二次使用的是 11;然后第三次再次自增。
所以整个式子应该是:int y = 10 + 11 + 12,最终输出结果为 33。
*/
注意:通过此示例可以进一步理解自增和自减的规律,但实际开发中不建议写这样的代码,小心挨打!
赋值运算符
赋值运算符的作用是将一个表达式的值赋给左边,左边必须是可修改的,不能是常量。
符号 | 作用 | 说明 |
---|---|---|
= | 赋值 | a = 10,将 10 赋值给变量 a |
+= | 加后赋值 | a += b,将 a+b 的值给 a |
-= | 减后赋值 | a -= b,将 a-b 的值给 a |
*= | 乘后赋值 | a *= b,将 a×b 的值给 a |
/= | 除后赋值 | a /= b,将 a÷b 的商给 a |
%= | 取余后赋值 | a %= b,将 a÷b 的余数给 a |
注意:赋值运算符隐含了强制类型转换。
short s = 10;
s = s + 10; // 此行代码报错,因为运算中 s 提升为了 int 类型
s += 10; // 此行代码不报错,因为隐含了强制类型转换,相当于 s = (short) (s+10);
关系运算符
符号 | 说明 |
---|---|
== | 比较基本数据类型时,比较的是值内容 比较引用数据类型时,比较的是对象地址 成立为 true,不成立为 false |
!= | a != b,判断 a 和 b 的值是否不相等,成立为 true,不成立为 false |
> | a > b,判断 a 是否大于 b,成立为 true,不成立为 false |
>= | a >= b,判断 a 是否大于等于 b,成立为 true,不成立为 false |
< | a < b,判断 a 是否小于 b,成立为 true,不成立为 false |
<= | a <= b,判断 a 是否小于等于 b,成立为 true,不成立为 false |
int a = 10;
int b = 20;
System.out.println(a == b); // false
System.out.println(a != b); // true
System.out.println(a > b); // false
System.out.println(a >= b); // false
System.out.println(a < b); // true
System.out.println(a <= b); // true
// 关系运算的结果肯定是 boolean 类型,所以也可以将运算结果赋值给 boolean 类型的变量
boolean flag = a > b;
System.out.println(flag); // false
逻辑运算符
逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断的结果是 true 或 false。
符号 | 作用 | 说明 |
---|---|---|
& | 逻辑与 | a&b,若 a 和 b 都是 true,结果为 true,否则为 false |
| | 逻辑或 | a|b,若 a 和 b 都是 false,结果为 false,否则为 true |
^ | 逻辑异或 | a^b,若 a 和 b 结果不同,结果为 true,相同为 false |
! | 逻辑非 | !a,则结果和 a 的结果正好相反 |
异或运算符的特点:
// 一个数被另外一个数,异或两次, 该数本身不变
public static void main(String[] args) {
System.out.println(10 ^ 5 ^ 10); // 5
}
示例:已知两个整数变量 a = 10、b = 20,使用程序实现这两个变量的数据交换。
public class Test {
public static void main(String[] args) {
int[] result1 = change1(10, 20);
int[] result2 = change2(10, 20);
int[] result3 = change3(10, 20);
System.out.println(result1[0]+" "+result1[1]); // 20 10
System.out.println(result2[0]+" "+result2[1]); // 20 10
System.out.println(result3[0]+" "+result3[1]); // 20 10
}
// 方法1:利用第三方变量
public static int[] change1(int a, int b) {
int tmp = b;
b = a;
a = tmp;
int[] arr = {a, b};
return arr;
}
// 方法2:利用算术运算符
public static int[] change2(int a, int b) {
a = a + b;
b = a - b;
a = a - b;
int[] arr = {a, b};
return arr;
}
// 方法3:利用异或运算符
public static int[] change3(int a, int b) {
a = a ^ b;
b = a ^ b; // = a ^ b ^ b = a
a = a ^ b; // = a ^ b ^ a ^ b ^ b = b
int[] arr = {a, b};
return arr;
}
}
短路逻辑运算符
符号 | 作用 | 说明 |
---|---|---|
&& | 短路与 | 作用和 & 相同,但是有短路效果 |
|| | 短路或 | 作用和 | 相同,但是有短路效果 |
在逻辑与运算中,只要有一个表达式的值为 false,那么结果就可以判定为 false 了,没有必要将所有表达式的值都计算出来,而短路与操作就有这样的效果,这样可以提高效率。同理在逻辑或运算中,一旦发现值为 true,右边的表达式将不再参与运算。
-
逻辑与 &,无论左边真假,右边都要执行。
-
短路与 &&,如果左边为真,右边执行;如果左边为假,右边不执行。
-
逻辑或 |,无论左边真假,右边都要执行。
-
短路或 ||,如果左边为假,右边执行;如果左边为真,右边不执行。
int x = 3;
int y = 4;
System.out.println((x++ > 4) & (y++ > 5)); // 两个表达都会运算
System.out.println(x); // 4
System.out.println(y); // 5
System.out.println((x++ > 4) && (y++ > 5)); // 左边已经可以确定结果为 false,则右边不参与运算
System.out.println(x); // 4
System.out.println(y); // 4
三元运算符
语法:
条件表达式 ? 表达式1 : 表达式2;
解释:如果条件表达式成立或者满足,则执行前面的表达式 1,否则执行后面的表达式 2。
举例:
int a = 10;
int b = 20;
int c = a > b ? a : b; // 判断 a > b 是否为真,如果为真则取 a 的值,如果为假则取 b 的值
三元运算符案例:
需求:一座寺庙里住着三个和尚,已知他们的身高分别为 150cm、210cm、165cm,请用程序实现获取这三个和尚的最高身高。
public class OperatorTest02 {
public static void main(String[] args) {
//1. 定义三个变量用于保存和尚的身高,单位为 cm,这里仅仅体现数值即可。
int height1 = 150;
int height2 = 210;
int height3 = 165;
//2. 用三元运算符获取前两个和尚的较高身高值,并用临时身高变量保存起来。
int tempHeight = height1 > height2 ? height1 : height2;
//3. 用三元运算符获取临时身高值和第三个和尚身高较高值,并用最大身高变量保存。
int maxHeight = tempHeight > height3 ? tempHeight : height3;
//4. 输出结果
System.out.println("maxHeight:" + maxHeight);
}
}
位移运算符
位运算符指的是二进制位的运算,先将十进制数转成二进制后再进行运算。在二进制位运算中,1 表示 true,0 表示 false。
示例:
public class Test {
/*
<< 有符号左移运算,二进制位向左移动, 左边符号位丢弃, 右边补齐0
运算规律: 向左移动几位, 就是乘以2的几次幂
12 << 2
(0)0000000 00000000 00000000 000011000 // 12的二进制
-----------------------------------------------------------------------------
>> 有符号右移运算,二进制位向右移动, 使用符号位进行补位
运算规律: 向右移动几位, 就是除以2的几次幂
000000000 00000000 00000000 0000001(1) // 3的二进制
-----------------------------------------------------------------------------
>>> 无符号右移运算符, 无论符号位是0还是1,都补0
010000000 00000000 00000000 00000110 // -6的二进制
*/
public static void main(String[] args) {
System.out.println(12 << 1); // 24
System.out.println(12 << 2); // 48
}
}