# Java 快速入门
# 2.1 Java 历史
略
# 2.2 搭建开发环境
略
# 2.3 Java 程序基础
- Java程序基本结构
- 变量和数据类型
- 整数运算
- 浮点数运算
- 布尔运算
- 字符和字符串
- 数组类型
# 2.3.1 Java程序基本结构
我们先剖析一个完整的Java程序,它的基本结构是什么:
/**
* 特殊的多行注释
* 可以用来自动创建文档的注释
*/
// 类名必须以英文字母开头,后接字母,数字和下划线的组合
// 习惯以大写字母开头
// 注意到 public 是访问修饰符,表示该 class 是公开的
public class Demo {
// 这里的方法名是main,返回值是void,表示没有任何返回值。
public static void main(String[] args) {
// 在方法内部,语句才是真正的执行代码。Java的每一行语句必须以分号结束
// 向屏幕输出文本:
System.out.println("Hello, world!");
// 单行注释
// 这是注释...
// 多行注释
/*
这是注释
blablabla...
这也是注释
*/
}
}
Java程序对格式没有明确的要求,多几个空格或者回车不影响程序的正确性,但是我们要养成良好的编程习惯,注意遵守Java社区约定的编码格式。
# 标识符
public class Demo01 {
public static void main(String[] args) {
// 所有的标识符都应该以 字母 $ _ 开始
// 首字符之后可以是 字母 $ _ 数字
// 注意标识符是大小写敏感的
String hello = "Hello";
String world = "World";
String $hello = "Hello";
String hello1 = "Hello";
String hello_world = hello + world + "!";
System.out.println(hello_world);
}
}
- 所有的标识符都应该以 字母 $ _ 开始
- 首字符之后可以是 字母 $ _ 数字
# 2.3.2 变量和数据类型
# 变量
Java 是强类型语言,要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
public static void main(String[] args) {
String a;
System.out.println(a); // 这里会报错
}
来看一个完整的定义变量,然后打印变量值的例子:
// 定义并打印变量
public class Main {
public static void main(String[] args) {
int x = 100; // 定义int类型变量x,并赋予初始值100
System.out.println(x); // 打印该变量的值
}
}
变量的一个重要特点是可以重新赋值。例如,对变量x,先赋值100,再赋值200
// 重新赋值变量
public class Main {
public static void main(String[] args) {
int x = 100; // 定义int类型变量x,并赋予初始值100
System.out.println(x); // 打印该变量的值,观察是否为100
x = 200; // 重新赋值为200
System.out.println(x); // 打印该变量的值,观察是否为200
}
}
Java 的数据类型分为两大类
- 基本类型
- 引用类型
# 基本数据类型
基本数据类型是CPU可以直接进行运算的类型。Java定义了以下几种基本数据类型
基本数据类型 | 具体类型 | 细节 |
---|---|---|
数字 整数 | byte | 1 个字节 8 位二进制数 |
数字 整数 | short | 2 个字节 16 为二进制数 |
数字 整数 | int | 4 个字节 32 位数,可用来表示 10 位时间戳 |
数字 整数 | long | 8 个字节 64 位数,可用来表示 13 位时间戳 |
数字 浮点数 | float | 4 个字节 |
数字 浮点数 | double | 8 个字节 |
字符 | char | 2 个字节 表示单个字符 |
布尔值 | boolean | 1 个位 表示真/假 (是/否) |
public static void basic() {
// 整数
byte b1 = 10;
short s1 = 20;
int num3 = 30;
int i = 2147483647; // int 最常用
int i2 = -2147483648;
int i3 = 2_000_000_000; // 加下划线更容易识别
int i4 = 0xff0000; // 十六进制表示的16711680
int i5 = 0b1000000000; // 二进制表示的512
long num4 = 30L; // long 数字后面要加 L
long n2 = 900; // 没有加L,此处900为int,但int类型可以赋值给long
int i6 = 900L; // 错误:不能把long型赋值给int
// 浮点数
float f1 = 3.14f; // 数字后面要加 f
float f2 = 3.14e38f; // 科学计数法表示的3.14x10^38
float f3 = 1.0; // 错误:不带f结尾的是double类型,不能赋值给float
double d = 1.79e308;
double d2 = -1.79e308;
double d3 = 4.9e-324; // 科学计数法表示的4.9x10^-324
// 布尔值
boolean b1 = true;
boolean b2 = false;
boolean isGreater = 5 > 3; // 计算结果为true
int age = 12;
boolean isAdult = age >= 18; // 计算结果为false
/*
Java语言对布尔类型的存储并没有做规定,
因为理论上存储布尔类型只需要1 bit,
但是通常JVM内部会把boolean表示为4字节整数。
*/
// 字符
char c1 = 'A'; // 字符要使用单引号
char zh = '中';
}
# 引用类型
引用数据类型 | 具体类型 | 细节 |
---|---|---|
数字 整数 类 | BigInteger | 表示任意大小的整数 |
数字 浮点数 类 | BigDecimal | 表示一个任意大小且精度完全准确的浮点数 |
字符串 类 | String | 表示多个字符 |
String s = "hello";
# 常量
定义变量的时候,如果加上final修饰符,这个变量就变成了常量
final double PI = 3.14; // PI是一个常量
double r = 5.0;
double area = PI * r * r;
PI = 300; // compile error!
# 示例代码
public class Demo02 {
public static void main(String[] args) {
// Java 是强类型语言
// 要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
/**
* String a;
* System.out.println(a); 这里会报错
*/
number();
reference();
}
public static void number() {
// ====================
System.out.println("====================进制");
// ====================
int i2 = 0b10; // 二进制的 10 表示十进制的 2
int i10 = 10;
int i8 = 010; // 八进制的 10 表示十进制的 8
int i16 = 0x10; // 八进制的 10 表示十进制的 16
System.out.println(i2);
System.out.println(i10);
System.out.println(i8);
System.out.println(i16);
// ====================
System.out.println("====================浮点数的问题");
// ====================
// 浮点数的问题
// 精度
float f = 0.3f;
double d1 = 0.1 + 0.2;
double d2 = 0.3;
System.out.println(f == d1); // false
System.out.println(d1 == d2); // false
// 溢出
float f1 = 12345678910f;
float f2 = f1 + 1;
System.out.println(f1 == f2); // true
// ====================
System.out.println("====================强制转换");
// ====================
// 字符 转 Int 输出:字符对应的 Unicode 码
// 字符的本质还是数字
char c1 = '1';
char c2 = 'a';
char c3 = '中';
char c4 = '\u0061'; // 16 进制的 61 表示 97 最终输入 a
System.out.println(c1); // 1
System.out.println((int)c1); // 49
System.out.println((int)c2); // 97
System.out.println((int)c3); // 20013
System.out.println(c4); // a
}
public static void reference() {
Integer num0 = 0;
String Gauss = "Gauss"; // 字符串要使用双引号
// ====================
System.out.println("====================字符串常量池");
// ====================
// 字符串常量池
// 为了提高性能并减少内存的开销,JVM在实例化字符串常量时进行了一系列的优化操作
// 1.在JVM层面为字符串提供字符串常量池,可以理解为是一个缓存区
// 2.创建字符串常量时,JVM会检查字符串常量池中是否存在这个字符串
// 3.若字符串常量池中存在该字符串,则直接返回引用实例;若不存在,先实例化该字符串,并且,将该字符串放入字符串常量池中
String sa = "abc";
String sb = "abc";
System.out.println(sa == sb); // true
String sc = new String("abc");
String sd = new String("abc");
System.out.println(sc == sd); // false
}
}
# 2.3.3 整数运算
Java的整数运算遵循四则运算规则,可以使用任意嵌套的小括号。四则运算规则和初等数学一致。例如:
// 四则运算
public class Main {
public static void main(String[] args) {
int i = (100 + 200) * (99 - 88); // 3300
int n = 7 * (5 + (i - 9)); // 23072
int x = 12345 / 67; // 184
int y = 12345 % 67; // 12345÷67的余数是17
System.out.println(i);
System.out.println(n);
System.out.println(x);
System.out.println(y);
}
}
整数的数值表示不但是精确的,而且整数运算永远是精确的,即使是除法也是精确的,因为两个整数相除只能得到结果的整数部分
# 溢出
要特别注意,整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,而溢出不会出错,却会得到一个奇怪的结果
// 运算溢出
public class Main {
public static void main(String[] args) {
int x = 2147483640;
int y = 15;
int sum = x + y;
System.out.println(sum); // -2147483641
long sum = x + y;
System.out.println(sum); // 2147483655
}
}
# 自增/自减
Java还提供了++运算和--运算,它们可以对一个整数进行加1和减1的操作
// 自增/自减运算
public class Main {
public static void main(String[] args) {
int n = 3300;
n++; // 3301, 相当于 n = n + 1;
n--; // 3300, 相当于 n = n - 1;
int y = 100 + (++n); // 不要这么写
System.out.println(y);
}
}
# 移位运算
在计算机中,整数总是以二进制的形式表示。例如,int类型的整数7使用4字节表示的二进制如下:
00000000 0000000 0000000 00000111
可以对整数进行移位运算。对整数7左移1位将得到整数14,左移两位将得到整数28:
int n = 7; // 00000000 00000000 00000000 00000111 = 7
int a = n << 1; // 00000000 00000000 00000000 00001110 = 14
int b = n << 2; // 00000000 00000000 00000000 00011100 = 28
# 位运算
对两个整数进行位运算,实际上就是按位对齐,然后依次对每一位进行运算。例如:
// 位运算
public class Main {
public static void main(String[] args) {
int i = 167776589; // 00001010 00000000 00010001 01001101
int n = 167776512; // 00001010 00000000 00010001 00000000
System.out.println(i & n); // 167776512
}
}
# 运算优先级
在Java的计算表达式中,存在运算优先级,一般来说乘除优先于加减。
记不住也没关系,只需要加括号就可以保证运算的优先级正确。
# 类型转换
public class Demo05 {
public static void main(String[] args) {
/**
* 注意点
* 1. 不能对布尔值进行转换
* 2. 不能把对对象类型转换位不相干类型
* 3. 高容量到低容量需要强制转换
* 4. 转换的时候可能存在内存溢出或者丢失精度
*/
// 强制转换 高到低
int i = 128;
byte b = (byte) i;
System.out.println(b); // - 128
float f = 61.8f;
double d = 61.8;
System.out.println((int) f); // 61
System.out.println((int) d); // 61
// 自动转换 低到高
long l = (long) i;
System.out.println(l); // 128
char c = 'a';
System.out.println(c + 1); // 98
}
}
# 整数运算小结
整数运算的结果永远是精确的;
运算结果会自动提升;
可以强制转型,但超出范围的强制转型会得到错误的结果;
应该选择合适范围的整型(int
或long
),没有必要为了节省内存而使用byte
和short
进行整数运算。
# 2.3.4 浮点数运算
# 2.3.5 布尔运算
# 2.3.6 字符和字符串
在Java中,字符和字符串是两个不同的类型。
# 字符类型
字符类型char是基本数据类型,它是character的缩写。一个char保存一个Unicode字符:
char c1 = 'A';
char c2 = '中';
因为Java在内存中总是使用Unicode表示字符,所以,一个英文字符和一个中文字符都用一个char类型表示,它们都占用两个字节。要显示一个字符的Unicode编码,只需将char类型直接赋值给int类型即可:
int n1 = 'A'; // 字母“A”的Unicodde编码是65
int n2 = '中'; // 汉字“中”的Unicode编码是20013
# 字符串类型
和char类型不同,字符串类型String是引用类型,我们用双引号"..."表示字符串。一个字符串可以存储0个到任意个字符:
String s = ""; // 空字符串,包含0个字符
String s1 = "A"; // 包含一个字符
String s2 = "ABC"; // 包含3个字符
String s3 = "中文 ABC"; // 包含6个字符,其中有一个空格
# 字符串连接
Java的编译器对字符串做了特殊照顾,可以使用+连接任意字符串和其他数据类型,这样极大地方便了字符串的处理。例如:
// 字符串连接
public class Main {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "world";
String s = s1 + " " + s2 + "!";
System.out.println(s); // Hello world!
}
}
# 多行字符串
从Java 13开始,字符串可以用"""..."""表示多行字符串(Text Blocks)了。举个例子:
// 多行字符串
public class Main {
public static void main(String[] args) {
String s = """
SELECT * FROM
users
WHERE id > 100
ORDER BY name DESC
""";
System.out.println(s);
}
}
# 不可变特性
Java的字符串除了是一个引用类型外,还有个重要特点,就是字符串不可变。考察以下代码:
// 字符串不可变
public class Main {
public static void main(String[] args) {
String s = "hello";
System.out.println(s); // 显示 hello
s = "world";
System.out.println(s); // 显示 world
}
}
执行String s = "hello";
时,JVM虚拟机先创建字符串"hello",然后,把字符串变量s指向它:
s
│
▼
┌───┬───────────┬───┐
│ │ "hello" │ │
└───┴───────────┴───┘
紧接着,执行s = "world";
时,JVM虚拟机先创建字符串"world",然后,把字符串变量s指向它:
s ───────────────────┐
│
▼
┌───┬───────────┬───┬───────────┬───┐
│ │ "hello" │ │ "world" │ │
└───┴───────────┴───┴───────────┴───┘
# 字符与字符串小结
Java的字符类型char是基本类型,字符串类型String是引用类型;
基本类型的变量是“持有”某个数值,引用类型的变量是“指向”某个对象;
引用类型的变量可以是空值null;
要区分空值null和空字符串""。
# 2.3.7 数组类型
如果我们有一组类型相同的变量,例如,5位同学的成绩,可以这么写:
public class Main {
public static void main(String[] args) {
// 5位同学的成绩:
int n1 = 68;
int n2 = 79;
int n3 = 91;
int n4 = 85;
int n5 = 62;
}
}
但其实没有必要定义5个int变量。可以使用数组来表示“一组”int类型。代码如下:
// 数组
public class Main {
public static void main(String[] args) {
// 5位同学的成绩:
int[] ns = new int[5];
ns[0] = 68;
ns[1] = 79;
ns[2] = 91;
ns[3] = 85;
ns[4] = 62;
}
}
Java的数组有几个特点:
- 数组所有元素初始化为默认值,整型都是0,浮点型是0.0,布尔型是false;
- 数组一旦创建后,大小就不可改变。
# 字符串数组
# 数组类型小结
数组是同一数据类型的集合,数组一旦创建后,大小就不可变;
可以通过索引访问数组元素,但索引超出范围将报错;
数组元素可以是值类型(如int)或引用类型(如String),但数组本身是引用类型;