Java核心技术读书笔记3-Java程序基本语法与程序设计结构
1.数据类型
Java包含8中基本类型,包括4种整型,2种浮点型,1种表示Unicode编码字符的字符型以及1中布尔型
1.1 整型
byte 1字节 8个二进制位 -128~127
short 2字节 16个二进制位
int 4字节 32个二进制位
long 8字节 64个二进制位 数值后面用l或L表示,如long l = 100000L
进制:二进制用0b或0B开头,八进制用0开头,十六进制用0x开头。
正负数存储:正数存储为二进制原码,负数存储为对应正数的补码,java没有无符号整型,符号均用最高位表示。short 128为 0b0000 0000 1000 0000; short-128为0b1111 1111 1000 0000。
平台无关性:整型范围固定与运行Java代码的机器无关,所以Java代码具有高可移植性。
1.2 浮点类型
float 4字节 16个二进制位 数值后面用f或F表示,如float f = 0.25f
double 8字节 32个二进制位 数值后面用d或D表示,如double d = 0.5d
Double.NaN:不能用if(x == Double.NaN)来判断一个数是否等于NaN,所有NaN都是不同的。应该用Double.isNaN(x)
浮点数不适用于无法接受舍入误差的高精度计算,如银行。应使用BigDecimal类
POSITIVE_INFINITY与NEGATIVE_INFINITY:整数除0会得到一个除0异常,浮点数除0会得到无穷大或者NaN的情况。
1.3 char
char 2字节 16个二进制位
Unicode字符:大多数Unicode字符可以用一个char表示,还有一些需要用两个表示。
Java中的char描述了UTF-16编码中的一个代码单元(code unit),即每个字符用16位二进制表示。但Unicode字符的数量已经超过了65536即2^16个。所以对于一些字符,一个char已经不能满足表示条件了。
在Unicode中一个字符的编码称为码点(code point),码点用16进制书写,并加上前缀U+,如A的码点为U+0041。对于经典Unicode字符的码点为是从U+0000到U+FFFF(相当于16位2进制),其余字符包括一些辅助字符码点为从U+10000到U+10FFFF。
所以对于经典Unicode字符,使用一个UTF-16代码单元就可以表示。而对于其余字符,转换成UTF-16编码时需要使用两个代码单元。因此会出现一个char会表示不了一个字符的情况,尤其是使用String.charAt(i)方法返回的可能是不完整的装代码单元字符。所以如无必要,可不用char类型表示字符,而是使用字符串。
获取字符串所有码点的方法:
int[] codePoints = str.codePoints().toArray(); //获取字符串str的所有码点
String str = new String(codePoints, 0, codePoints.length); //使用码点组装成字符串
特殊转义字符:\b退格 \t制表 \r回车 \n换行 "双引号 '单引号 \反斜杠
转义序列处理规则:转义序列在解析代码前处理 "\u0022+\u0022"会先把\u0022转义成单引号,所以结果是""+""即一个空串。
1.4 boolean类型
长度:boolean类型的长度并没有严格要求,一般是1个字节到4个字节不等
1.5 类型转换与溢出问题
自动类型转换

上图展示了合法的类型转换(转换可以自动进行),其中,虚线表示可能会丢失精度。反之,则需要强制类型转换。
强制类型转换
在表达式的左侧加上括号,括号内为强制转换的类型。如:int a = 500; short b = (int)a;
强制类型转换可能会发生错误或丢失精度。整型间的强制转换在超过长度时会进行截断整数二进制位。浮点类型转换成整型会先截断小数的二进制位再按整数强制转换。
例: short s = 128;byte b = (byte)s;
实际上s = 0b 0000 0000 1000 0000 截断后为 0b 1000 0000。即为byte的-128。
整型溢出
整型在达到最大值的范围时+1会变为最小值。同理,到达最小值时-1会变为最大值
例: byte b = 127;(0b 0111 1111) b = b + 1;(0b 1000 0000即-128)
2.变量与常量
2.1 声明与定义:Java不区分。
2.2 final:final指示的变量即为常量,只能被赋值一次,且赋值之后就不可再更改了。
3.运算符
3.1 strictfp关键字:对于浮点运算实现平台无关性有一些困难。例如很多Intel处理器计算x * y,将结果保存到80位的寄存器中,再截断为64以已获得更高精度。但截断操作会导致与64位机运算结果不同。所以Java使用strictfp关键字标记方法,可以使方法参与的浮点计算必须直接截断。若不加这个关键字,则按CPU默认策略计算。
3.2 StrictMath:该类相比于Math类结果完全可预测,不会调用计算机浮点单元的例程而得到不确定的结果。
3.3 运算过程中的强制类型转换:运算后的结果若与左侧被赋值的变量类型不同,则进行强制类型转换。int x = 0; x += 3.5;相当于 x = (int)(x + 3.5);
3.4 移位运算符:java在对小于4字节的类型进行移位元素时会先对其补齐0成为int。同时根据左操作数的类型长度,会对右操作数按相应位数取模运算。如:int a = 128; a >> 33;//int为32位,33取模为1,所以等价于a >> 1;
算数移位: 左移<< 右移>>,算术右移会用原符号位补位。
逻辑移位:只有逻辑右移>>>,逻辑右移会用0补位。
4.字符串
Java中的字符串是不可修改的,即你不可以更改字符串中的字符。如果想修改已有的字符串,只能构造出这个新串,然后让字符串变量引用它。不可否认,不能修改字符串只能构建新的串的方式效率不高,但字符串不可更改就可以使不同变量引用的同一串共享。这对于字符串的高频率使用需求来说可以有更高的效率。
字符串是java中频繁使用的一种数据结构。JVM为了提升性能和减少内存开销,开辟并维护了一处允许字符串共享的空间,即字符串池(String Pool)。字符串池如何提供字符串的共享操作呢?首先需要明白几点:
String s1 = "abc",s2 = "abc"; //字面值赋值,值存储在字符串池中,返回字符串池的引用。
String s3 = new String("abc"), s4 = new String("abc");//创建对象,值存储在字符串池中和堆中。
字符串池中的值是可以共享的,而new出来的在堆中的对象自然是不可以共享。
所以 s1s2; //返回true;
而 s3s4; //返回false;
当使用字面值赋值是,会先检查池中该值存不存在,存在返回指向该值的同一个引用,否则创建该值并返回引用。当使用new创建对象时,也会检查池中存不存在,若存在,仅在堆中创建一个对象并返回引用。否则分别在池和堆创建对象并返回堆中对象的引用。
同时还有一点,字面值的拼接是在编译期完成的不会返回新串。而字符串变量的拼接是在运行期完成的完成后会创建一个新串。
String a = "a", b = "b", c = "c";
"abc" == "a" + "b" + "c"; //返回true
"abc" == a + b + c; //返回false;
注:'=='表示对比两侧变量存储的值是否相同,而.equals()对于存储的值是地址的情况(引用数据类型),会比较地址指向的对象的值是否相同
4.1 格式化字符串:Java可以用System.out对象的printf(str,param..)方法输出可以格式化参数的字符串。第一个参数为带有以%开始的标志的字符串,之后的可选个数参数为标志对应的参数。String类的静态方法format(str,param..)可以用相同的操作格式化str并返回格式化后的字符串;
5.控制流程
5.1 块:块是由大括号扩起来的区域,可以嵌套。块可以控制变量的作用域。
public static void main(String[] args) {
int a = 1; //一个块的变量作用域可以作用到本块和内部的嵌套块
{
int b = 1;
}
{
int b = 1; //不同同级别的块的同名变量定义互不影响
//int a = 1; 出错,和上级变量重名,定义重复
}
//b++; 出错,嵌套块内的变量不能作用到上级
}
5.2 goto:Java通过标签和带标签的break语句控制goto形式的跳转
label:
for(...){
...
if(conditon) break label;
...
}
5.3 for each循环:Java通过for each循环提供更便捷的遍历操作,其要求被遍历的结构只能是数组或实现了Iterable接口的类对象。形式为:for(variable : collection) statement
6.数组
6.1 构建数组
int[] a = {1, 2, 3}; //构建并赋初值
int[] a = new int[]{1, 2, 3}; //返回一个赋了值的数组,然后由变量a引用
int[] a = new int[n]; //构建一个长度为n的空数组,然后由变量a引用
6.2 数组拷贝
引用:
int[] a = {1, 2};
int[] b = a; //变量a、b指向数组{1, 2},对数组的修改,a,b变量都会感知到。
拷贝:
int[] a = {1, 2};
int[] b = Arrays.copyOf(a, 2); //构建一个新的长度为2的数组,并将a的值拷贝进去,若新数组长度小于a,则只拷贝符合长度的值。若新数组长度大于a,则空余位置用默认值填充。拷贝后两个数组互不影响。
int[] b = Arrays.copyOfRange(a, 0, 2); //用a的[0, 2)范围内的值构建一个新数组赋给b
6.3 命令行参数
public static void main(String[] args){}; //args接收使用命令行执行java文件时用空格分隔的参数附加的参数。如:
java className -a p aParam //args[0]-a args[1]p args[2]==aParam
浙公网安备 33010602011771号