Java基本程序设计结构
3.1 一个简单的Java应用程序
最简单的Java程序
public class FirstSample {
public static void main(String[] Args){
System.out.println("We will not use hello world");
}
}
-
psvm
生成public static void main(String[] Args){}
-
sout
生成System.out.println()
-
区分大小写
-
源代码的文件名必须和
public
类的名字相同,并以.java作为扩展名。所以这个程序文件名应该是FirstSample.java -
驼峰命名法
3.2 Java注释
//
单行注释/**/
多行注释/**
和*/
生成doc文档
3.3 数据类型
3.3.1 整型
类型 | 存储需求 |
---|---|
int | 4个字节 |
short | 2个字节 |
long | 8个字节 |
byte | 1个字节 |
- 可以在数值后面加一个
l
或L
后缀表示long
类型数值 - 十六进制前缀
0x
或0X
- 八进制前缀
0
。容易混淆,最好不用 - (Java7)前缀
0b
或者0B
表示二进制数。 - (Java7)支持为数字字面值加下划线,提高可读性
- Java中整型的范围和运行Java代码的机器无关,解决了移植问题
3.3.2 浮点类型
类型 | 存储需求 |
---|---|
float | 4字节 |
double | 8字节 |
- 大部分采用
double
才能满足精度需求 - 默认
double
类型,也可后缀d
或D
- 后缀
f
或F
表示float
类型 - 可以十六进制表示浮点数,使用
p
表示指数而不是e
3.3.3 char类型
char
类型原本用于表示单个字符,现在有些Unicode字符可以用一个char
值表示,有些需要用两个char
值表示
char
字符的字面值用单引号''
括起来。例如'A'
是编码为65对应的字符常量。
char
类型值可以表示为十六进制值,范围从\u0000
到\Uffff
转义字符 | 作用 |
---|---|
\b | 退格 |
\t | 制表 |
\n | 换行 |
\r | 回车 |
\" | 双引号 |
\' | 单引号 |
\\ | 反斜杠 |
3.3.5 boolean类型
boolean
值有两个:false
和true
。用来判定逻辑条件。
整型和布尔值之间不能互相转换
3.4 变量
Java为强类型语言,每个变量都有一个类型。声明变量时,变量的类型位于变量名之前
double salary;
int vacationDays;
boolean done, notDone; // 不推荐,单行可读性高
- 变量名大小写敏感,长度无限制。字母开头
- 不能用保留字作为变量名
3.4.1 变量初始化
int vacationDays = 12; // 声明+初始化
- 声明后必须对变量进行显式初始化,不可以使用未初始化的变量
- 可以将变量声明和初始化放在同一行中
- 变量声明尽可能靠近第一次使用的地方,这是良好的书写风格
3.4.2 常量
Java中,用final
指示常量。
final double CM_PER_INCH = 2.54;
final
表示这个变量智能呗赋值一次,一旦赋值不能更改- 习惯上常量名使用全大写
类常量:可以在一个类中的多个方法中使用。可以用关键字static final
设置一个类常量
public class Constants2{
public static final double CM_PER_INCH = 2.54; // 在main方法外部
// public使得其他类的方法也可以使用这个常量 Constants2.CM_PER_INCH
public static void main(String[] args){
...
}
}
const
是Java保留的关键字,但目前没被使用
3.5 运算符
算术运算符:+-*/%
3.5.1 数学函数与常量
Math
类中包含各种数学函数
double x = 4;
double y = Math.sqrt(x); // 平方根
double z = Marh.pow(x, 2); // 幂
Math.PI // pi
Math.E // e
可以不必在数学方法和常量名前添加前缀Math
,只需在源文件顶部添加这句代码import static java.lang.Math.*;
3.5.2 数值类型之间的转换
3.5.3 强制类型转换
double x = 9.997;
int nx = (int) x; // 强制类型转换 nx = 9
- 不要在
boolean
类型与任何类型之间进行强制类型转换
3.5.4 结合赋值和运算符
x += 4;
// 等价于
x = x+4;
x += 3.5; // 合法,等效于
x = (int) x+3.5;
3.5.5 自增和自减运算符
和C++一样
建议不使用,可读性差
3.5.9 枚举类型
变量的值只在一个有限的集合内
enum Size {SMALL, MEDIUM, LAEGE, EXTRA_LARGE};
Size S = Size.SMALL;
3.6 字符串
3.6.1 子串
String
类的substring
方法可以从一个大字符串中提取一个子串
String greeting = "Hello";
String s = greeting.substring(0,3); // s = "Hel"
- 第一参数为子串起始位置
- 第二参数为子串长度
3.6.2 拼接
Java语言允许使用+
拼接两个字符串
String expletive = "Expletive";
String PG13 = "deleted";
String message = expletive+PG13; // message = "Expletivedeleted"
一个字符串和一个非字符串的值进行拼接时,后者被转化为字符串(任何一个Java对象都可以转换为字符串。这种特性常用在输出语句中
int age = 13;
String rating = "PG"+age; // rating = "PG13"
System.out.println("The answer is "+rating);
如果需要把多个字符串房子啊一起,用一个定界符分割,可以采用静态join
方法
String all = String.join("/","S","M","L","XL"); // all = "S/M/L/XL"
3.6.3 不可变字符串
String
类没有提供修改字符串的方法。可以用提取子串+拼接实现
String str = "Hello";
String str2 = str.substring(0,3)+"p!"; // str2 = "Help!"
3.6.4 检测字符串是否相等
使用equals
方法检测字符串是否相等;千万不要使用==
,==
检测的是两个字符串的位置
s.equals(t);
s.equals("hello");
s.equalsIgnoreCase("Hello"); // 忽略大小写检测
3.6.5 空串和Null串
空串""
是长度为0的字符串,可以如下检测
if(str.length()==0){...}
// 或者
if(str.equals("")){...}
空串是一个Java对象,有长度(0)和内容他(空)。
null
串表示目前没有任何对象与该变量关联,检测可用
if(str == null){...}
检测一个字符串既不是null
也不是空串:
if(str != null && str.length() != 0){...}
在一个null
值上调用方法会发生错误
3.6.6 码点与代码单元
Java字符由char
值序列组成。char
数据类型是采用UTF-16编码表示Unicode码点的代码单元。
length
方法返回采用UTF-16编码表示的给定字符串所需要的代码单元数量,实际码点数量需要调用codePointCount
方法。
调用charAr(n)
将返回位置n
的代码单元,n
介于0~s.length()-1
之间。想得到第i
个码点,则需要offsserByCodePoints
和codePointAt
方法
String greeting = "Hello";
int n = greeting.length(); // n = 5;
int cpCount = greeting.codePointCount(0, greeting.length());
char first = greeting.charAt(0); // first = 'H'
// 第i个码点
int index = greeting.offsetByCodePoints(0, i);
int cp = greeting.codePointAt(index);
3.6.7 String API
3.6.9 构建字符串
需要很多小段的字符串构建一个字符串,可以使用StringtBuider
类
StringBuilder builder = new StringBuilder(); // 空的字符串构建器
builder.append(ch); // 添加一部分内容
// 构建字符串
String completedString = builder.toString();
3.7 输入输出(TODO
3.7.1 读取输入
通过控制台进行输入,首先需要构造Scanner
对象,并且和标准输入流System.in
关联
Scanner in = new Scanner(System.in);
接着就可以使用Scanner
类的各种方法实现输入操作了,例如nextLine
方法将输入一行
system.out.print("what is your name");
String name = in.nextLine();
int age = in.nextInt(); // 读取int
double price = in.nextDouble(); // 读取double
String str = in.next(); // 以空白符作为结束
// Demo
public static void main(String[] Args){
Scanner in = new Scanner(System.in);
System.out.println("what is your name?");
String name = in.nextLine();
System.out.println("how old are you?");
int age = in.nextInt();
System.out.println("Hello, "+name+". Next year, you'll be "+(age+1));
}
3.7.2 格式化输出
3.7.3 文件输入与输出
要对文件进行读取,需要用一个File对象构造一个Scanner
对象
Scanner in = new Scanner(Paths.get("file.txt"), "UTf-8");
如果文件名中包含反斜杠,记得转义字符\\
现在就可以用Scanner
的方法对文件进行读取
3.8 控制流程
3.8.1 块作用域
块(block)是指一对大括号括起来的若干条简单的Java语句。块确定了变量的作用域。一个块可以嵌套在另一个块中。
但是,不能在嵌套的两个块中声明同名的变量。这点区别于C++
3.8.2 条件语句
Java的条件语句格式是
// 单条语句
if(condition) statement
// 多条语句,需要用块语句
if(condition){
statements;
}else if{
...
}else{
...
}
3.8.3 循环
包括while
循环和for
循环。和C++一样,不赘述
3.8.4 多重选择
switch
语句。和C++一样,不赘述
case
标签可以是:
char
/short
/int
/byte
的常量表达式- 枚举常量
- 从Java SE 7开始,可以是字符串字面量
3.8.6 中断控制流程语句
break
:退出外面一层循环continue
:略过当前循环后面的部分,开始下一次循环
3.9 大数值
如果基本的整数和浮点精度不能满足需求,可以用java.math
包中的BigInteger
和BigDecimal
类,可以处理任意长度数字序列的数值
静态的valueOf
方法可以讲普通数值转换为大数值
BigInteger a = BigInteger.valueOf(100);
但不能用算术运算法处理大数值,需要用add
方法和multiply
方法
BigInteger c = a.add(b);
BigInteger d = c.multiply(a.add(BigInteger.valueOf(20)));
其他API:
BigInteger add(BigInteger other)
和BigInteger substract(BigInteger other)
差BigInteger multiply(BigInteger other)
积BigInteger divide(BigInteger other)
商BigInteger mod(BigInteger other)
余int compareTo(BigInteger other)
如果这个大整数和other
相等,返回0;比他大返回正数;否则返回负数static BigInteger valueOf(long x)
返回数值等于x
的大整数
3.10 数组
数组是一种数据结构,用来存储同一类型值的集合。
通过一个整型下标就可以访问数组中的值,例如a
是一个整型数组,a[i]
就是下标为i
的整数。Java中下标从0开始
使用new
运算符创建数组
int[] a = new int[100]; // 创建一个可以存储100个int的数组
int a[] = new int[100]; // 也可以,但推荐上面那种
数组有默认初始化。例如int
数组的元素会默认初始化为1,boolean
数组的元素会初始化为false
,对象数组会初始化为null
获取数组长度,可以用array.length
一旦创建了数组,就不能改变数组的长度。如果经常需要在运行中扩展数组长度,应该使用另一种数据结构——array list
。详见第五章
3.10.1 for each 循环
for
循环的简便形式,可以不指定下标值而遍历数组
for(variable : collection) statement
3.10.2 数组初始化及匿名数组
Java提供了一种创建数组对象并同时赋予初始值的简化书写形式,例如
int[] smallPrimes = {1, 2, 3, 4, 5};
不需要调用new
。甚至可以初始化一个匿名的数组
new int[] {1, 2, 3, 4, 5}
结合起来可以在,不创建新变量的情况下重新初始化一个数组
smallPrimes = new int[] {1, 2, 3};
// 等价于
int[] anonymous = {1, 2, 3};
smallPrimes = anonymous;
Java中允许数组长度为0,它和null
不同。在编写一个结果为数组的方法时,这一点就显得有用。
3.10.3 数组拷贝
Java中允许将一个数组变量拷贝给另一个数组变量,这时候两个变量将引用同一个数组
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12; // 此时smallPrimes[5]被修改为12
如果要将一个数组的所有值拷贝到一个新的数组中,就要使用Arrays
类的copyOf
方法
// 第一参数为欲拷贝对象数组,第二参数为拷贝长度
int copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
// 可以通过设置第二参数来扩展数组大小
luckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length*2); // 扩展两倍,多出来的会默认初始化
// 第二参数小于长度时,只会拷贝前面的元素
Java中数组分配基本和C++中分配在堆上的数组指针一样。也就是说int[] a = new int[100]
不同于int a[100] // C++
而等同于int* a = new int[100] // C++
Java的[]
运算符被预定义为检查数组边界,而且没有指针运算