本博客只做个人查漏补缺使用
Java概述
java特点
- 简单性:Java语法是C++语法的一个“纯净”版本,这里没有头文件,指针运算,结构,联合,操作符重载,虚基类等
如今java的开发环境已经远远超出其他变成语言的开发环境。
现在有一个独立的具有较小类库的Java微型版(Java Micro Edition),这个版本适用于嵌入式设备 - 面向对象:Java与C++主要的不同点在于多重继承,Java中,取而代之的是更简单的接口编程。
- 健壮性:Java非常强调进行早期的问题检测,后期动态(运行时)检测,Java与C++最大的不同在于Java采用的指针模型可以消除重写内存和损坏数据的可能性。
- 结构体系中立:编译器生产一个体系中立的目标文件格式,Java编译器通过生成与特定的计算机体系结构无关的字节码指令来实现这一特性。精心设计的字节码不仅可以很容易的在任何机器上解释执行,而且还可以动态的转换成本地机器代码。
- 可移植性:除了与用户界面相关的部分之外,所有其他Java库确定能够很好地支持平台独立性。你可以处理文件,正则表达式,XML,日期和时间,数据库,网络连接,线程等,而不用操心底层操作系统。
- 解释型:Java解释器可以在任何移植了解释器的机器上直接执行Java字节码。直到Java9才提供了jshell工具支持快捷而且具有探索性的编程。
- 多线程:Java在当时是第一个支持鬓发程序设计的主流语言。
- 动态性:Java和C或C++相比更加具有动态性。它能够适应不断发展的环境。库中可以自由的添加新方法和实例变量,而对客户端却没有任何影响。
- Java applet 与 Internet
- 在网页中运行的Java程序成为applet
不同版本的Netscape与Internet Explorer运行不同版本的Java,其中有些早已经过时。
Java发展简史
5.0版是1.1版以来第一个对Java语言重大改进的版本,除了添加泛型类型,还增加几个有用的语言特性,“foreach” 循环,自动装箱和注解
Java8开始着力分解这个庞大的平台,为此引入了模块,模块是提供一个特定功能的自包含的代码单元。
关于Java的常见误解
- 使用XML,所以不需要Java
Java是一种程序设计语言,XML是一种描述数据的方式。可以使用任何一种程序设计语言处理XML数据,而JavaAPI对XML处理提供了很好地支持,此外,许多重要的XML工具都由Java编写 - JavaScript是Java的简易版
JavaScript是一种可以在网页中使用的脚本语言。处了名字有点像之外,没有任何关系
尤其是,Java是强类型的,编译器能够捕获类型滥用导致的许多错误,而在JavaScript中,只有当程序运行的时候才能发现这些错误。
Java程序设计环境
JShell
Java9引入了另一种使用Java的方法,JShell程序提供了一个“读取-计算-打印循环” 。键入一个Java表达式,JShell会评估你的输入,打印结果,等待你的下一个输入
使用步骤:
- 启动JShell,在终端窗口键入jshell
- 键入一个表达式:
“Core Java”.length()
,然后JShell会回应一个结果。 - 键入tab值,会得到可以在generator变量上调用的所有方法的一个列表
Java的基本程序设计结构
注释
在java中,/* */
注释不能嵌套。也就是说,不能简单的吧代码用/*
和 */
括起来作为注释,因为这段代码本身可能也含有*/
界定符
整形
如果要使用不可能为负的整数值而且确实需要一位额外的bit,也可以吧有符号整数化成无符号整数,但是要注意细节。
例如,一个byte值可以不表示范围-128~127,如果你想要表示范围0 ~ 255,也可以存储在一个byte中,基于二进制运算的性质,只要不溢出,加减乘法都可以正常计算。但是对于其他运算,需要调用Byte.toUnsignedInt(b)
来得到一个0-255的值,然后处理这个整数值,再把他转换会byte。Integer和Long都提供了无符号处罚和求余数的方法。
浮点类型
float类型的数值都有一个后缀F或f(例如,3.14f)。
没有后缀F的浮点数(如,3.14)总认为是double类型,也可以在后面加D和d
所有的浮点数数值计算都遵循IEEE 754规范,下面是表示溢出和出错情况的三个特殊的浮点数值:
- 正无穷大
- 负无穷大
- NaN(不是一个数字)
例如,一个正整数除以0的结果为正无穷大,计算0/0或者负数的平方根结果为NaN
常量Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY和Double.NaN(以及相应的float类型的变量)分别表示这三个特殊的值。
但是,不能如下检测一个特定值是否等于Double.NaN;if(x == Double.NaN)
所有非数值得值都认为是不同的,不过可以使用Double.isNaN()
方法来判断一个数字 - 注意:浮点数值不适用于无法接受摄入误差的金融计算。
例如:System.out.println(2.0-1.0)
将打印出0.89999999,而不是0.9,这是因为,浮点数值都是采用二进制表示,而二进制系统中无法精确的表示分数1/10。就像十进制无法精确表示分数1/3一样。
如果在数值计算中不允许有任何的舍入误差,应该使用BigDecimal类
char类型
- Java中,一些Unicode字符需要一个char值表示,一些需要两个char值。
- char类型的值可以表示为十六进制值,其范围从
\u0000-\uFFFF
除了转义序列\u之外,还有一些用于表示特殊字符的转义序列,所有转义序列都可以出现在加引号的字符字面量或字符串中。并且转移序列\u还可以出现在加引号的字符常量和字符串之外(其他转移字符不可以)
如public static void main(String\u005B\u005D args)
- 注意:Unicode转义序列会在解析代码之前得到处理,例如
"\u0022+\u0022"
并不是一个字符串,实际上,\u0022在解析之前会被转换为"
,所以最后答案得到的是一个空串。
一定要注意注释中的\u// \u000A is a newline
会产生一个语法错误,因为\u000A会被替换成一个换行符
再一个,// look inside c:\users
也会产生一个错误,因为\u后面并没有跟着4个16进制数
Unicode和char类型
- 码点:是指与一个编码表中某个字符对应的代码值,在Unicode标准中,码点采用十六进制书写,并加上前缀U+。
Unicode码点可以分为17个代码平面,第一个代码平面成为基本多语言平面,包括码点从U+0000~U+FFFF的经典Unicode代码,其余的16个代码平面为从U+10000到U+10FFFF,包括辅助字符。 - UTF-16编码采用不同长度的编码表示所有的Unicode码点,基本多语言平面中,每个字符用16位表示,成为代码单元,而辅助字符编码为一对连续的代码单元。
例如:码点为U+1D546的负号,编码为两个代码单元U+D846和U+DD46
在Java中,char类型描述了UTF-16编码中的一个代码单元
变量初始化
- 从Java10开始,对于局部变量,如果可以从变量的初始值推导出他的类型,就不需要在声明类型。只需要使用var关键字
var a = 10; var s = "hello"
类常量
- 在Java中,经常希望一个常量可以在一个类的多个方法中使用,通常将这些常量称为类常量,可以使用static final声明一个类常量
- 注意:类常量的定义是位于main方法的外部。因此在同一个类的其他方法也可以使用这个常量。而且,如果这个常量被声明为public,那么其他类的方法也可以使用这个常量。
枚举类型
enum Size = {SMALL,MEDIUM,LARGE};
Size s = Size.SMALL;
Size类型的变量只能存储这个类型声明中给定的某个枚举值,或者特殊值null
算数运算符
- 整数被0除将会产生一个异常,而浮点数被0除则会得到无穷大或者NaN结果。
- 使用
strictfp
关键字标记的方法必须使用严格的浮点计算来生成可再生的结果
数学函数与常量
- 静态导入:可以不必在静态方法名和常量名之前添加“Math”,只要在源文件的顶部加上下面这行代码就可以了
import static java.lang.Math.*;
- Math类提供了一些方法使整数有更好的运算安全性。如果一个计算溢出,数学运算符只会返回错误结果而不作任何提醒,如果调用
Math.multiplyExact(10000000000,3)
,就会产生一个异常。另外还有一些方法也可以正确的处理int和long参数。
数值类型之间的转换
- 精度可能有损失的转换:long to double , long to float , int to float
- 二元运算转换优先级:
double > float > long > int
自增自检运算符
- 自增自减运算符改变的是变量的值,所以不能应用于数值本身,比如4++就是一个错误的语句。
位运算符
- 在应用到boolean值上时,&和|运算符也会得到一个布尔值,不过这两个运算符没有“短路“的特性。
>>>
运算符会用0填充高位,这与>>
不同,他会用符号位填充高位,不存在<<<
运算符- 位移运算符的右操作数要完成模32的运算(long为64),所以1<<35等同于1<<3
括号和运算符级别
- 除了赋值符和运算符结合的符号( = ,+=,&=,>>=,>>>=)结合性是 从右往左 之外,其他运算符都是 从左往右
字符串
- Java没有内置的字符串类型,而是在标准的Java类库中提供了一个预定义类,叫做String。每个用双引号括起来的字符串都是String类型
子串
- substring的工作方式(左包含 右不包含)有一个优点:容易计算子串的长度。字符串s.substring(a,b)的长度为b-a
拼接
- 如果需要吧多个字符串放在一起,用一个界定符分隔,可以使用静态join方法
String all = String.join("/","S","M","L");
在Java11当中,还提供了一个repeat方法String repeated = “Java”.repeat(3);
- 在Java中String类对象成为不可变对象,不过可以修改字符串变量,使其引用另外一个字符串,不变字符串有一个优点:编译器可以让字符串共享。
- 原始字符串在堆中分配,Java将自动进行垃圾回收,如果一个内存块不在使用了,系统将会将其回收。
检测字符串是否相等
- C++的String类重载了==运算符,以便检测字符串内容的相等性。Java并没有采用这种方式
空串与null值
- 有时要检查一个字符串既不是null也不是空串,这种情况下就需要用到以下判断
if(str != null && str.length() != 0
首先要检查str不为null,不然在一个null上面调用方法,会出现空指针异常。
码点与代码单元
- 最常用的Unicode字符使用一个代码单元就可以表示,而辅助字符则需要一对代码单元来表示。
- length()方法返回采用UTF-16编码表示的给定字符串所需要的的代码单元数量。
String = greeting = "Hello";
int n = greeting.length();
想要得到实际的长度,即码点数量,则需要调用int cpCount = greeting.codePointCount(0,greeting.length());
调用s.charAt(n)则会返回位置n的代码单元,n介于0~s.length()-1之间。
想要得到第i个码点,应该使用int index = greeting.offsetByCodePoints(0,i);
int cp = greeting.codePointAt(index);
为了避免出错,在有辅助字符出现的字符串中,尽量避免使用charAt,因为charAt拿到的是代码单元,而辅助字符占两个代码单元,所以可能会截取到辅助字符的一部分,容易出错。
所以,码点代表一个编码表中一个字符所对应的代码值,在Unicode中,辅助字符的码点 = 两个代码单元 常用的字符的码点 = 一个代码单元,而Java中的charAt()拿到的是一个代码单元,所以在辅助字符出现的地方,请慎重使用charAt()
String 常用API
- boolean isBlank()
- String replace(CharSequence oldString, CharSequence newString)
返回一个新字符串,这个字符串用newString代替原始字符串中所有的oldString,可以使用String或StringBuilder对象作为CharSequence参数
输入与输出
- 因为输入是可见的,Scanner类不适合于从控制台读取密码,Java6引入了Console这个类来实现
Console cons = System.console();
String username = cons.readLine("User name:");
char[] password = cons.readPassword("Password:");
为了安全起见,返回的密码存储在一个字符数组中,而不是字符串中。对密码处理完成之后,应该马上用一个填充值覆盖数组元素。Console对象不如Scanner方便,必须每次读取一行输入,没有读取单个字符或数值的方法。
java.utl.Scanner API
- String next() 读取输入的下一个单词(空格作为分隔符)
- boolean hasNext() 检测输入中是否还有其他单词
格式化输出
- 可以使用静态的
String.format()
方法创建一个格式化输出的字符串,而不打印输出String message = String.format("Hello,%s,Next year ,you will be %d",name,age);
文件输入与输出
- 想要读取一个文件,可以构造Scanner对象
Scanner in = new Scanner(Path.of("myfile.txt"))
- 可以构造一个带有字符串参数的Scanner对象,但这个Scanner会把字符串解释成数据,而不是文件名。
Scanner in = new Scanner("myfile.txt");
Java.nio.file.Path 11
- static Path of(String pathname)
确定循环
- 在循环中,检测两个浮点数是否相等时要注意
for(double x = 0;x != 10; x+=0.1)
可能永远不会结束,因为舍入的误差,0.1无法精确的用二进制表示,x可能会从9.9999999999998跳到10.099999999998
switch语句
- 如果没有匹配的case标签,而用default字句,就执行default字句
- 在switch语句中使用枚举常量时,不必再每个标签中指明枚举名可以由switch表达式推导得出。例如
case SMALL:
不需要使用Size.SMALL
中断控制流程的语句
- Java提供的带标签的break语句,用于跳出多重嵌套的循环语句。标签得放在希望跳出的最外层循环之前,而且必须紧跟一个冒号。标签得放在最外层循环的上一行
break_out:
while(){
while(){
break break_out;
}
}
- 另外,只能跳出语句块,不能跳入语句块。
- continue在while中跳过剩余部分,立刻到循环首部
- continue在for中直接跳到循环的更新部分,即 i++ 语句
大数
- BigInteger 实现任意精度的整数运算,BigDecimal实现任意精度的浮点数运算
- 使用静态的valueOf方法可以将普通的数值转换为大数
BigInteger a = BigInteger.valueOf(100);
- 对于更大的数,可以使用一个带字符串参数的构造器\
BigInteger a =- new BigInteger("123341234123413123412341341341341");
- 另外还有一些常量:
BigInteger.ZERO BigInteger.ONE BigInteger.TEN
Java9之后还增加了BigInteger.TWO
数组
- 可以使用
int[] a
int a[]
定义数组,第一种可以将类型和变量名清晰地分开 int[] arr = {1,2,3,4,}
最后一个值后面允许有逗号,如果要不断为数组增加值,这很方便- Java中,有长度为0的数组,在编写一个结果为数组的方法时,如果碰巧结果为空,这样一个长度为0的数组就很有用
可以这样创建长度为0的数组new arr[0]
或new arr[]{}
foreach循环
- foreach循环的collection对象必须是一个数组或者是一个实现了Iterator接口的类对象
- 有一个更简单的办法打印数组的值,
Arrays.toString(a)
返回[1,2,3,4,5]
数组拷贝
- Java中,允许价格一个数组变量拷贝到另一个数组变量,两个变量将引用一个数组
- 要将一个数组的所有值拷贝到一个新的数组中去,可以使用Arrays.coyeOf()方法
int[] arr1 = Arrays.copyOf(arr2,arr2.length);
第二个参数是新数组的长度,这个方法通常用来增加数组的大小 - 如果数组元素是数值型,额外元素被赋值为0,布尔型为false
命令行参数
- 每个Java程序都带有一个args[] 参数的main方法,这个参数表明main方法将接受一个字符串数组,也就是命令行上指定的参数,例如在命令行调用java程序
java demo hello java se
程序名为demo的程序中args[]数组的参数将会是args[0] = "hello" args[1] = "java" args[2] = "se"
- 在java程序的main方法中,程序名并没有存储在args数组中(也就是“demo”并没有存储在args数组中)
数组排序
- Array.sort(arr),该方法使用了优化的快婿排序
- Math.random()方法返回一个0~1之间(左包含右不包含)的随机浮点数,用n乘以这个浮点数,就可以得到0到n-1之间的一个随机数
java.util.Arrays
- static boolean equals(xxx[] arr1,xxx[] arr2)
如果两个数组大小相同,并且下标对应元素相同,返回true static int binarySearch(xxx[] a, int start, int end, xxx v)
使用二分查找算法在有序数组a中查找值v,找到,返回v下标,否则返回一个负数值r,-r-1是v应该插入的位置(保持a有序)
多维数组
- 想要快速打印出一个二维数组的元素
Arrays.deepToString(a)
参考资料
《Java核心技术 卷I》