Java核心技术-I-3-Java的基本程序设计结构

注释

注释分为3类:

  1. 单行注释://其后的部分被视为注释。

    1
    Sysout.out.print("context") //annotation
  2. 多行注释:/* xxx */内的xxx被视为注释,可以包含多行。

    1
    2
    3
    4
    5
    /*
    annotation1
    annotation2
    annotation3
    */
  3. 文档注释型:这种注释以/**开始,以*/结束,这种注释可以用来自动生成文档。

    1
    2
    3
    4
    5
    /**
    annotation1
    annotation2
    annotation3
    */

数据类型

Java有8中基本类型(primitive type),其中有4种整型、2种浮点类型、1种字符类型和一种表示真假值的Boolean类型。

整型

类型 存储需求 取值范围
int 4字节 -2147483648~2147483647(刚好超过20亿)
short 2字节 -32768~32767
long 8字节 -9223372036854775808~9223372036854775807
byte 1字节 -128~127

Note:

  1. 在Java中,整型的范围与运行Java代码得机器无关。

  2. 长整型数值有一个后缀L或l。

    1
    Long lVal = 999999999999999l;
  3. 从java7开始,可以为数字字面量添加下划线,如9_999_999即为9999999

浮点类型

类型 存储需求 取值范围
float 4字节 大约±3.402823E+38F(有效位数为6~7位)
double 8字节 大约±1.79769313486231570E+308(有效位数为15位)

Note:

  1. 定义float类型时,其数值有一个后缀F或者f。没有后缀Ff会被默认视为double类型。(实际上也很少使用float,大多使用double)。

  2. 常量Double.POSITIVE_INFINITYDouble.NEGATIVE_INFINITYDouble.NaN分别表示IEEE754规定的用于表示溢出和出错情况的三个特殊浮点数值:

    1. 正无穷大
    2. 负无穷大
    3. NaN(Not a Number)
  3. 不能用==判断一个数是否为NaN,而应该用Double.isNaN(param)

  4. 浮点数存在误差,如经典的(2.0 - 1.1) = 0.899999999999, 而不是0.9。这是由于浮点数值采用二进制系统表示,而在二进制系统中无法精确的表示分数1/10。这就像无法用十进制精确的表达1/3一样。如果需要精确的计算,则应该采用BigDecimal类。

char类型

char类型原本表示单个字符,占2字节。不过现在一些Unicode字符需要两个char值来表达。

char类型表示的是十六进制值,其范围是从\u0000\uffff。如\u2122表示商标(™)。

除了转移序列\u之外,还有一些用于表示特殊字符的转移序列。参见下表。

转移序列 名称 Unicode值
\b 退格 \u0008
\t 制表 \u0009
\n 换行 \u000a
\r 回车 \u000d
\" 双引号 \u0022
\' 单引号 \u0027
\\ 反斜杠 \u005c

Note:

  1. Unicode转义序列会在解析代码之前得到处理。也就是说,Java源代码的任意字符都可以使用 Unicode来编写。

    以此会产生一些隐晦的语法错误(现在编译器都会提示),比如:

    1
    // look inside c:\users

    由于\u并没有跟着4个十六进制数。

变量与常量

  1. 从jdk10开始,对于局部变量,如果可以从变量的初始值推断出它的类型,就可以不声明变量类型。如:

    1
    2
    var vacationDays = 12;
    var greeting = "Hello";
  2. 常量的定义使用关键字final,并且其只可以被赋值一次(注意并不是只可以在声明时赋值,可以在声明后在构造器方法中赋值,但是仅可以被赋值一次)。

运算符

在Java中,使用+,-,*,/表示加、减、乘、除运算。

  1. 对于/运算,当两个操作数都是整数时,表示整数除法(即只返回整数部分),否则表示浮点除法。
  2. 对于%运算,表示求余操作,其操作数可以为整型或者浮点型。

数学函数

Math类中,为了达到最佳的性能,所有的方法都是用计算机浮点单元中的例程。如果要求计算更加准确而不是在乎速度,则可以使用StrictMath类,其API与Math类完全相同。

数值类型的转换

隐式转换

数值类型转换

图中展示出各种数值类型的转换,其中实线表示可以无损转换,而虚线表示转换会损失精度。

当一个二元操作符连接两个不同类型的值时,需要先将其转换为同一种类型才能进行运算。这种隐式转换的规则如下:

  1. 如果两个操作数中有一个是double类型,另一个操作数就会转换为double类型。
  2. 否则,如果其中一个操作数是flaot类型,另一个操作数就会转换成为float类型。
  3. 否则,如果其中一个操作数是long类型,另一个操作数将会转换为long类型。
  4. 否则,两个操作数都将会被转化为int类型。

强制类型转换

在Java中,通过:(type) variable来完成强制类型转换,如:

1
2
double pi = 3.1415926;
int intPi = (int)pi; //会丢失精度,编译器会warn

注意以上的转换会直接截断小数点。如果需要四舍五入,则可以使用Math.round()函数来实现。

运算符优先级

如下表

优先级 运算符 结合性
1 ()、[]、{} 从左向右
2 !、+、-、~、++、-- 从右向左
3 *、/、% 从左向右
4 +、- 从左向右
5 «、»、>>> 从左向右
6 <、<=、>、>=、instanceof 从左向右
7 ==、!= 从左向右
8 & 从左向右
9 ^ 从左向右
10 | 从左向右
11 && 从左向右
12 || 从左向右
13 ?: 从右向左
14 =、+=、-=、*=、/=、&=、|=、^=、~=、«=、»=、>>>= 从右向左

字符串

从概念上将,Java的字符串就是Unicode的字符序列。如,字符串”Java\u2122”由5个Unicode字符J、a、v、a和™组成。并且String并不是基础类型之一,所以在标准的Java类库中提供了一个预制类称为String。

String类没有提供修改字符串中某个字符的方法。如果希望修改字符串中某个位置的值,可以使用substring()方法来实现。

不提供修改方法的原因主要在于可以共享字符串的值,将其存储在一个共享池中,提升效率。详细在jvm虚拟机的内存模型时可以更加详细的了解。

检测字符串是否相等

在检测字符串是否相等时,一般不使用==,这是由于实际上只有通过字面量定义的字符串是共享的,而通过构造器或者substring()得到的方法并不是共享的。所以:

  1. 如果两个字符串都是用字面量定义的,则可以使用==来判断。
  2. 其他情况下,都应当equal()方法来判断相等关系。
  3. 综上,还是尽量使用equal()方法来判断,防止不可预知的bug。

底层

jdk9之前,String底层是使用char值序列组成,而jdk9中,其底层变成了byte值序列。

构建字符串

有些时候,需要由较短的字符串来构建字符,这时如果采用字符串拼接会比较消耗性能,这时候可以采用StringBuilder类来构建字符串。示例如下:

1
2
3
4
StringBuilder builder = new StringBuilder();
builder.append("str1");
buidler.append("str2");
String s = builder.toString();

输入输出

读取输入

1
2
3
4
5
Scanner in = new Scanner(System.in);
String name = in.nextLine(); //读取一行
String firstName = in.next(); //读取下一个单词
int age = in.nextInt(); //读取下一个int
double tall = in.nextDouble(); //读取下一个double

格式化输出

Sysout.print.out(x)将数值x输出到控制台。

Sysout.out.printf()可以进行格式化输出。如:Sysout.out.printf("%8.2f", x)。这种语法沿用了C语言函数库中的printf()方法。

其第一个参数格式如下:

格式化输出

分别解释每一项:

  1. %:表示格式化输出的标识符。

  2. argument index+$一起表示参数索引,即Sysout.out.printf(FORMAT, x,...restArg)可以接受多个参数,其中1$,2$,n$表示对第一个,第二个,第n个参数进行特定的格式化。

  3. flag:指定控制格式化输出外观的各种标志,如下表:

    标志目的举例
    +打印数字前的符号+3333.33
    space在正数之前加空格| 3333.33|
    0在数字前补0003333.33
    -左对齐|3333.33 |
    (负数括在括号内(3333.33)
    ,添加分组分隔符3,333.33
    # (for f )包含小数点3,333.
    # (for x or o)添加前缀 0x 或 00xcafe
    ^转化为大写0XCAFE
    $指定格式化参数索引,如%1$d,%1$d表示以十进制
    和十六进制打印第一个参数
    159 9F
    <格式化前面参数,如%d%<x表示以十进制和十六进
    制打印同一个参数
    159 9F
  4. width:表示输出的位宽,如果原内容不足width,则填空格。

  5. t+conversion character:转换符指示要格式化的数据类型。所有内容如下表:

    转换符类型 举例
    d十进制整数  159
    x十六进制整数9f
    o八进制整数237
    f定点浮点数15.9
    e指数浮点数1.59e+01
    g通常浮点数 
    a十六进制浮点数0x1.fccdp3
    s字符串Hello
    c字符H
    b布尔型TRue
    h散列码42628b2
    tx日期时间见时间介绍表
    %百分号%
    n分隔符      
  6. .+precision:表示数值输出的小数点位数,如果不足后面补0。

文件输入输出

读取文件

1
2
Scanner in = new Scanner(Path.of("file.txt"), StanardCharsets.UTF_8);
String l = in.nextLine(); //读取一行,还有其他类型如上代码一样

写入文件

1
PrintWriter out = new PrintWriter("file.txt", StanardCharsets.UTF_8);

流程控制

在Java中没有goto语句,但是设计了另外一种语法来实现其一部分语法。

带标签的break语法

可以使用带标签的break来讲程序跳转到确定位置。标签定义后加冒号,其后可以跟任何代码块。break后加标签名字。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 循环中使用
check_point: //定义标签位置
for(...){
for(...){
...;
break check_point; //跳转到check_point位置
}
}

//任何位置使用
check_point1:
{
if(...) break check_point1;
}

大数

如果基本的整数和浮点数精度不能满足需求,则可以使用java.Math包中的两个类:

  • BigInteger:大整数。

  • BigDecimal:大浮点数。

  • 可以使用vlaueOf方法将普通的数值转换为大数。

    1
    BigInteger big = BigInteger.valueOf(1000);
  • 可以使用构造器传入字符串数值

    1
    BigInteger big = new BigInteger("99999999999999999999999999999999999999999999999999999999999999999999999999999999")

但值得注意的是,大数不能使用普通的算术运算符(如+, -, *, /)。而是要使用大数类的addmultiply方法等来进行运算。如

1
2
BigInteger c = a.add(b);
BigInteger d = c.multipy(b.add(BigInteger.valueOf(2))); //d = c * (b + 2)

数组

数组声明

1
2
int[] a;		// 一般使用这种,因为更容易区分变量名和数据类型
int a[];

数组初始化

1
2
3
4
5
6
7
8
9
10
11
12
// 声明和初始化分开
int[] a;
a = new int[100];

// 声明和初始化一起
int[] b = new int[100];

// 类型推断
var c = new int[100];

//字面量方法创建数组
int[] d = {1,2,3,4};
  1. 一旦创建了数组,就无法改变它的长度。

  2. 如果需要可改变大小的数组,可以使用ArrayList

  3. 注意通过字面量方法创建数组时,不需要提供数组大小,也不需要new操作符。

  4. 创建一个数字数组时,所有元素都初始化为0;Boolean数组的元素会初始化为false;对象数组的元素则初始化为一个特殊值null

数组拷贝

可以使用Arrays.copyOf(originalArray, newArrayLength)来创建一个新的数组,并将原数组复制到新数组中,可以间接实现改变数组大小。

1
2
3
int[] a = {1,2,3};
int[] b = Arrays.copyOf(a, 5);
// b = {1, 2, 3, 0, 0}

Note:当新数组的长度小于原数组,则会截断原始数组。

命令行参数

主函数main(String[] args)的参数是作为命令行参数。如:

1
java A -g param1 param2

则结果为:

1
2
3
args[0]: "-g";
args[1]: "param1";
args[2]: "param2";

Powered by Hexo and Hexo-theme-hiker

Copyright © 2019 - 2024 My Wonderland All Rights Reserved.

UV : | PV :