Java基础——(二)Java基本程序结构设计
1. 一个简单的Java程序
在电脑上安装好JDK和IDEA后,我们打开IDEA,创建一个Java工程,然后创建一个FirstSample类,添加以下代码
package org.example.test;
public class FirstSample {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
在上述代码中,涉及的关键字和对应含义如下:
- public:public为访问修饰符,用于控制程序对这段代码的访问级别,访问级别包括public、protected和private
- class:class后面紧跟着类名,在Java中,定义类名的规则比较宽松,名字必须以字母开头,后面可以跟字母和数字的任意组合,此外,不能使用到Java的保留字。
- FirstSample:类名,标准的命名规范为大写字母开通,如果由多个单词组成,每个单词的第一个字母都应该大写,这种命名方式成为驼峰命名法。
- main:运行编译程序时,Java虚拟机将从指定类的main方法开始执行。
- {}:在Java中,用花括号划分程序的各个部分(通常成为块)
- System.out.println:在这里,使用System.out对象并调用了它的println方法。
上述代码执行的结果如下:
2. 注释
在Java中,有三种书写注释的方式。
第一种,也是最常用的一种,使用//
// 这是一行注释
System.out.println("Hello World!");
第二种,使用/* 和 */将一段比较长的注释括起来
package org.example.test;
/*
* @author cxy
*/
public class FirstSample {
public static void main(String[] args) {
// 这是一行注释
System.out.println("Hello world");
}
}
第三种注释,以/** 开始,以*/结束
package org.example.test;
/**
* @author cxy
*/
public class FirstSample {
public static void main(String[] args) {
// 这是一行注释
System.out.println("Hello world");
}
}
3. 数据类型
java有8种数据类型,分别是byte、char、short、int、long、float、double、bool。注意,String不属于Java的基本数据类型。
数据类型 | 类型 | 存储需求 |
---|---|---|
int | 整型 | 4字节 |
short | 整型 | 2字节 |
long | 长整型 | 8字节 |
byte | 整型 | 1字节 |
float | 浮点型 | 4字节 |
double | 浮点型 | 8字节 |
char | 字符 | 和字符集相关,如果是ASCII编码集,那么占一个字节,如果是UTF-8,因为UTF-8不定长,长度是动态的,所以不确定 |
boolean | 布尔型 | 单独使用,占4个字节,以boolean数组使用,占用1个字节 |
长整型long数值,后面有一个后缀L,比如1024L。float类型的数值后有一个后缀F,例如3.14F。没有后缀F的浮点数默认为double类型。
4. 变量
4.1 变量名
在java中,每一个变量属于一种类型,变量所属的类型位于变量名之前,示例如下:
double salary;
int a;
long b;
boolean done;
从上可以看出,每个声明以分号结束,因为每一个声明是一条完整的语句。变量必须是一个以字母开头并由字母或数字构成的序列,当然,也可以包括横杆。比如:
int hello;
int h123;
int h_123;
4.2 初始化
声明一个变量之后,我们必须用赋值语句对变量进行显式初始化,千万不要使用未被初始化的变量。要对变量进行初始化,需要将变量名放在等号左侧,相应取值的java表达式放在等号右侧,比如:
int a;
a = 1;
或者
int a = 1;
4.3 常量
在java中,使用关键字final表示常量,比如:
final double pi = 3.14;
通过final,表示这个变量只能被赋值一次,一旦被赋值后,不能再更改这个变量。一般我们常量的变量名会是大写,此外,一般会和public、static关键字结合,以保证一个类定义的多个常量能被多个类消费,比如:
public class Constant {
public static final double PI = 3.14;
public static final int ONE_KM = 1000;
public static final long TWO_TEN = 1024L;
5. 运算符
在java中,使用算法运算符+、-、*、/分别表示加减乘除。当参与/运算的两个操作数都是整数时,表示整数乘法,否则表示浮点数除法。
package org.example.test;
/*
* @author cxy
*/
public class FirstSample {
public static void main(String[] args) {
// 这是一行注释
System.out.println("Hello world");
int a = 10;
int b = 3;
double c = 3.0;
System.out.println(a / b);
System.out.println(a / c);
}
}
结果如下:
5.1 二元运算符
在赋值语句中,可以使用一些简化的格式书写二元算术运算符,比如
x += 4; 等价于 x = x + 4;
x *= 4; 等价于 x = x * 4;
5.2 自增、自减运算符
此外,对于加1、减1这些比较常见的操作,可以使用自增运算符和自减运算符来实现,而自增、自减运算符的位置,会影响到赋值。如果放在前面,表示先自增/自减,然后再赋值。如果放在后面,表示先赋值然后再自增/自减。
5.3 关系运算符和boolean运算符
java包含各种关系运算符,其中通过==检测是否相等,用!=检测是否不相等。此外,常用的运算符还有<, >, <=, >=。
然后Java沿用了C++的习惯,使用&&表示逻辑与,||表示逻辑或, !表示非。
&&和||为短路求值,也就是如果第一个操作数能确定表达式的值,就不会执行第二个操作数。
此外,Java还支持三元操作符?:。比如"condition ? expression1 : expression2;"的意思是,当condition为true时,执行第一个表达式,否则执行第二个。
5.4 位运算符
java的位运算符包括&,|,^,~,分别表示与、或、异或、非。另外,>>和<<运算符将二进制进行右移或左移操作。
5.5 数值类型之间的转换
在程序运行时,经常涉及一种数值类型转换为另一种数值类型的问题,下图为数值类型之间的合法转换。
其中,实线箭头表示无信息丢失的转换;有3个虚线箭头表示可能有精度损失的转换。例如123 456 789是一个大整数,它所包含的位数比float类型所能表达的位数多,所以在将这个整数转化为float时,会得到相同大小的结果,但却失去一定的精度。
当涉及不同类型的二元操作时,遵循以下规则:
- 如果2个操作数有一个是double类型,另一个操作数就会转化为double类型
- 否则,如果其中一个操作数是float类型,另一个操作数就会转化为float类型
- 否则,如果其中一个操作数是long类型,另一个操作数就会转化为long类型
- 否则,两个操作数都将转化为int类型。
5.6 枚举类型
有时候,变量的取值只在一个有限的集合内,例如服装大小为S、M、L、X等,针对这种情况,可以自定义枚举类型,枚举类型包括有限个命名的值,例如:
enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE};
6. 字符串
每个用双引号括起来的字符串都是String类的一个实例。例如:
String e = "";
String greeting = "hello";
6.1 子串
substring方法可以从一个较大的字符串中提取一个子串。其包括两个参数,分别代表起始位置和结束位置,注意,这是一个左闭右开的区间。
6.2 拼接
Java允许使用+号拼接两个字符串。
6.3 不可变字符串
String类中没有提供修改字符串的方法,如果需要修改,只能通过substring或拼接来实现,此时相当于引用另一个字符串给当前变量,也就是说,java的String类对象是一个不可变字符串。这有一个优点:编译器可以让字符串共享。
在Java中,各种字符串存放在公共的存储池中,字符串变量指向存储池中的相应位置,如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符。
6.4 字符串是否相等
在Java中,使用equals检测两个字符串是否相等。注意,一定不能使用==运算符检测两个字符串是否相等!这个运算符只能确定两个字符串是否放置在同一个位置。
String greeting = "hello";
boolean flag = "hello".equals(greeting);
System.out.println(flag);
如果虚拟机始终将相同的字符串共享,就可以使用==运算符检测是否相等,但实际上只有字符串常量是共享的,而+或substring等操作产生的结果并不是共享的。
6.5 空串与Null
空串""是长度为0的字符串,空串是一个Java对象,有自己的串长度(0)和内容(空)。不过,String变量还可以存放一个特殊的值,名为null,表示目前没有任何对象与该变量关联。要检测一个字符串是否为null,可以使用如下条件:
if (str == null)
6.6 常用的字符串api
方法名 | 作用 |
---|---|
char charAt(int index) | 返回给定位置的字符 |
int compareTo(String other) | 比较大小,按照字典顺序,如果字符串位于other之前,返回一个负数,如果位于之后,返回一个正数,如果相等,返回0 |
boolean endsWith(String suffix) | 判断字符串是否以suffix结尾 |
boolean equals(Object other | 判断字符串是否与other相等 |
boolean equalsIgnoreCase(String other) | 如果字符串与other相等(忽略大小写),返回true |
int length() | 返回字符串长度 |
boolean startsWith(String prefix) | 判断字符串是否以prefix开头 |
String toLowerCase() | 返回一个新字符串,这个新字符串将原始字符串中所有大写字符改为小写字符 |
String toUpperCase() | 返回一个新字符串,这个新字符串将原始字符串中所有小写字符改为大写字符 |
String trim() | 返回一个新字符串,该新字符串将删除原始字符串头部和尾部的空格 |
7. 输入输出
7.1 读取输入
在前面的例子中,我们可以看到打印输出到标准输出流(控制台窗口)是一件非常容易的事情,只要使用System.out.println即可,但“标准输入流” System.in就比较复杂,当我们像通过控制台进行输入,首先需要构造一个Scanner对象,并将System.in与之关联。
Scanner in = new Scanner(System.in);
然后我们可以:
使用nextLine来输入一行(以换行结束);
使用next来输入一个单词(以空格结束);
使用nextInt读取一个整数(以换行结束);
使用nextDouble读取一个浮点数(以换行结束);
如下列代码所示,我们通过scanner获取控制台输入,并赋值给对应的变量。
7.2 格式化输出
在Java中,可以使用printf格式化数值,例如
System.out.printf(“%8.2f”, x) 可以用8个字符的宽度和小数点后两个字符的精度打印x。(当宽度不够时,会使用空格补齐)
格式化输出,在我们的系统中,需要打印日志信息,用于后续排查问题,如果是使用字符串拼接的方式,不够清晰并且比较繁琐,而格式化输出则能以比较清晰简单的方式实现我们期望的输出格式。
8. 控制流程
8.1 条件语句
在Java中,条件语句的格式为:
if(condition) statement
这里的条件必须用括号括起来。当希望符合条件时执行多条语句时,使用块语句,格式为:
if (condition) {
statement1;
statement2;
}
在Java中,更常见的条件格式如下,表示符合条件时执行某语句,不符合时执行另一个语句。
if (condition) {
statement1;
statement2;
} else {
statement3;
statement4;
}
此外,还有另一种条件格式,用于有多个判断条件的情况,但某个条件不符合时,接着判断另一个条件,直到结束。
if (condition1) {
statement1;
statement2;
} else if(condition2) {
statement3;
statement4;
} else if(condition3) {
statement5;
statement6;
} else {
statement7;
statement8;
}
8.2 循环
while用于当条件为true时,循环执行某语句块。直到不符合条件。
while(condition) {
statement1;
statement2;
}
示例如下:
另一个循环执行语句的方式为:
do {
statement1;
statement2;
} while(condition);
这种循环语句成为先执行语句,它会先执行语句块的内容,再检测循环条件。
8.3 for循环
for循环语句是支持迭代的一种通用结构,利用每次迭代之后更新的计数器或类似的变量来控制迭代次数。在下列例子中,首先定义变量名为i,初始化值为1,然后判断是否符合i<10这个条件,如果符合,执行System.out.println(i)这条语句,然后执行i+=2这条语句来更新i的数值,然后再判断i<10,如果符合条件,接着执行System.out.println(i)和i+=2, 直到不符合i<10这个条件。
8.4 switch语句
在处理多个选项时,有时候if/else结构会显得比较笨拙,这个时候,我们可以使用switch语句。以发送验证码为例,假设我们现在的验证码方式有邮箱、短信、语音、站内信等方式,如果是if/else,结构,写法如下:
if("sms".equals(sendType) {
// 发送短信
} else if ("email".equals(sendType) {
// 发送邮箱
} else if("voice".equals(sendType) {
// 发送语音
} else if("siteMsg".equals(sendType) {
// 发送站内信
} else {
// 默认发送方式
}
使用switch,可以简化为:
switch(sendType) {
case "sms":
// 发送短信
break;
case "email":
// 发送邮箱
break;
case "voice":
// 发送语音
break;
case "siteMsg":
// 发送站内信
break;
default:
//默认发送方式
break;
}
8.5 break中断语句
在刚才的switch示例中,每一个case结束时,都会加上一个break语句,这个break就是中断,如果不加break,那么会接着往下一个一个匹配。通过break语句,我们可以结束当前的条件块或循环块。如下列例子所示,当i的值为10时,直接退出循环:
8.6 大数值
如果基本的整数和浮点数精度不能满足我们的需求,那么可以使用java.math包中的BigInteger和BigDecimal这两个类,他们可以处理包含任意长度数字序列的数值,其中BigInteger实现了任意精度的整数运算,BigDecimal实现任意精度的浮点数运算。通过valueOf方法,可以将普通的数值转化为大数值。
BigInteger a = BigInteger.valueOf(100);
对于大数值,我们不能直接使用算术运算符,但可以使用他们提供的运算方法,比如add、multiply等。
9. 数组
数组是一种数据结构,用于存储同一类型值的集合,通过一个整数下标可以访问数组中的每一个值。
在声明数组时,需要指出数组类型(数据元素类型紧跟[])和数组变量的名字,如下所示:
int[] a; // 推荐这种声明方式
int b[];
int[] a这条语句只是声明了变量a,但没有将a初始化为一个真正的数组,我们可以使用new运算符创建一个数组,如下语句所示,我们创建一个存储100个整数的数组, 此时所有元素都初始化为0,如果是boolean数组,会初始化为false,对象数组会初始化为null。
int[] a = new int[100];
对于数组,我们可以使用for循环和for each循环来执行遍历,如下所示:
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i * 2;
}
// fori循环
for(int i = 0; i < arr.length; i++) {
int a = arr[i];
System.out.println(a);
}
// foreach循环,等价于上面的fori循环,但是更简单
for(int a : arr) {
System.out.println(a);
}
参考文档
https://www.cnblogs.com/wuqinglong/p/10329368.html
《Java核心技术卷I》(网盘链接:https://pan.quark.cn/s/06c58d47dce1)