细说java
类型转换
基本数据类型的关系

低类型数据
可以不作任何处理,直接赋值给高类型数据
好比将一个杯子(低类型数据
)中的水倒入一个水桶中(高类型数据
)
|
|
在上面的福之中,byte类型数据占1个字节,而short类型数据占2字节,系统在赋值时直接将short类型的高8位截断,而只将低8位赋值给byte类型变量。
char short byte之间的转换
char是无符号类型(0~65535),无论是与short还是byte,相互转换都不安全
在char
类型与short
类型,char
类型与byte
类型之间转换必须使用类型转换运算符boolean
类型不能转换成其他类型,其他类型也不能转换成其他类型
表达式运算结果类型
如果两个(或多个)操作数的类型不同,则运行结果的类型与较高类型的操作数相同
格外注意,负号-
也是一个运算符,假设存在一操作数x,x可以使byte、char或short类型,那么-x就不再是以前x的类型了,而是int类型
整数运算
|
|
BigInteger与BigDecimal
BigInteger可以对任意精度整数进行运算
BigDecimal可以对任意精度小数进行运算
注释中的编译错误
要小心Unicode中的转义字符,如果不是必须使用,尽量不要使用。同时,要当心程序中的”\u”,就算出现在注释中也不例外
移位运算
三种移位运算符
右移运算符:>>
左移运算符: <<
无符号右移运算符:>>>
:左边移出的空位一律以0填充
移位运算的操作数可以使byte,char,short,int,long类型变量,当左侧操作数为byte,short或char类型时候,会被自动转换成int类型,运算结果也为int类型。
当左侧操作数为int
类型时,以为运算符右侧的操作数只有低5位
是有效的(低5位的十进制最大值为31),因为int类型只有32位,这样就可以避免将数据全部移出而失去意义。
同样,当左侧操作数为long
类型时,右侧操作数也只有低6位
是有效的
例如,要计算
27 << 40
那么会取右侧操作数的低5位,40的补码为:0000
0000
0000
0000
0000
0000
0000
0010
1000
取低5位01000
所以,上面表达式相当于
27 >> 8
移出”负数位”
右操作数可以是负数,比如
48 << -7
-7 & 31
-7的补码:1111
1111
1111
1111
1111
1111
1111
1001
31的补码:0000
0000
0000
0000
0000
0000
0001
1111
取-7低5位,11001
相当于48 << 25
移位运算不是纯粹的乘除运算
对于正数
,左移一位相当于乘以2,右移一位相当于除以2
对于负数
,左移一位同样相当于乘以2,右移一位并不都相当于除以2
首先,对于除法的商,计算机是向零取整的
10 / 4 = 2
-10 / 4 = -2
而对于移位,都是向下取整
10 >> 2 = 2
-10 >> 2 = -3
异或
交换两个变量
但当x+y足够大的时候,会发生溢出,可以用异或解决
在异或
运算中,对于两个变量x,y,有这样一个性质:
(x^y^y) == x
改进:
循环
循环优化
嵌套循环的 调整
因为CPU在循环的内外层之间的切换也会有一定的开销,因此,建议使最内层的循环次数最多,依次递减,使最外层的循环次数最少
局部变量与成员变量的访问调整
由于局部变量分配在栈
上,而类的实例变量分配在堆
中。而对局部变量的访问速度要快于对堆中变量的访问。
因此,当在循环中多次访问某个实例变量时,可先将实例变量赋值给一局部变量,然后对局部变量进行访问。
拼接字符串的时候,使用StringBuilder替换String
跳转控制——循环标签
当程序存在多重循环嵌套时,如果需要直接跳出最外层的循环(break),或是终止内层的循环,而从外层的循环继续进行(continue),可以使用循环标签来实现
Java中对循环标签做了一定的限制,使其只能跳出循环,而不像goto语句那样可以随意跳转:
而continue的使用与break类似
死循环
达不到上限
|
|
当i 达到最大值127后,再加1就是-128
for/in循环
for/in循环写法
|
|
for/in 循环的局限
- 只能
按顺序
操作全部
元素
for/in 循环只能对集合(或数组)的全部元素进行顺序的操作,因而,在某些情况下,如只对集合(数组)的部分元素进行操作,for/in元素就无能为力了。
如果是从后往前访问,也不行 - 无法改变基本类型的数值
将基本类型取出来,进行操作无法改变原来对象的值
但是,如果元素是引用类型
,那么在for/in循环中是可以修改对象元素的值的123for(Clock c :clock){c.setHour(8);}
数组
数组的声明
可以采用如下的方式声明数组
或者
但在声明数组的时候不能指定数组的大小,例如下面的声明是错误的:
对数组的维数,可以如下声明
数组的初始化
一维数组初始化
可以使用两种方式对数组进行初始化
对于第二种方式,也可以指定元素的值;
如果未指定元素的值,那么元素会存在一个默认值,数值为0,布尔型为false,引用类型为null。因为数组也是对象,所以数组元素的默认值与类中定义的变量默认值相同。如果指定了元素的值,就不能在[]中指定数组的大小,例如不能写成:
第二种方式可以在声明后使用,第一种方式只能与声明同时使用,例如:
多维数组初始化
在Java中多维数可以是不规则的(每个维度的元素个数可以不同),在为多维数组分配空间时,一定要从高维到低维分配。因为多维数组实际上就是数组的 数组,即高维数组的每个元素也是数组,如果数组(高维)还没有分配空间,便无法为数组中的元素(低维)分配空间。
例如:
对于矩阵数(每维的元素个数都相等),可以采用一种简便的分配方式:
常量length——数组的长度
表示数组长度的是length属性,不要同String类的length()方法相混淆
数组有一个length
属性,代表数组的长度,数组的长度一经创建就不能修改(但可以将数组的引用指向另一个数组)
指定数组长度的变量为int类型,如果为byte, char, short类型则会自动转化为int类型,不可以为其他类型,尤其是long类型,例如:
另外,如果指定长度为负数,可以通过编译,但运行时候会报错。
复制差异——数组的复制
在java中,可以将一个数组的引用赋值给另一个数组的引用,例如:
但是,这样只是将引用y指向引用x所指的内存空间,即引用x,y指向相同的内存单元,x的改变将直接影响到x
arraycopy介绍
arraycopy的声明原型为:
src
: 被复制的源数组secPos
: 源数组开始复制的位置,即指明需要从原数组哪个位置开始复制dest
: 目标数组,即指出要将源数组的数据复制到哪个数组中destPos
: 将源数组复制到目标数组的起始位置length
: 在源数组中需要复制的元素个数
arraycopy方法可能会抛出三个 异常,分别如下:IndexOutOfBoundsException
: 如果secPos、desPos或length小于0,或者secPos+length大于等于src数组元素的个数,或者destPos+length大于等于dest数组元素的个数,则抛出此异常NullPointerException
: 如果src或dest数组有一个为null或两个都为null,则抛出此异常ArrayStoreException
: 对于基本数据类型,如果src与dest数组中元素的类型不同,对于对象,如果src数组中的元素不能存储在dest数组中,即dest数组元素类型不能兼容src数组元素类型,则抛出此异常。
注意:如果src与dest数组都是对象类型,则src与dest未必是相同的类型 ,只要兼容即可,即src类型也可以为dest类型的子类或实现了dest类型接口(src为dest的子类型)
基本类型元素数组的复制
|
|
复制之后,改变src数组元素并不会影响到dest数组的元素。
引用元素数组的复制
arraycopy方法实现了数组元素的复制,并且源数组与目标数组之间元素的改变不会影响到对方,不过,这只局限于数组为基本数据类型的情况。对于引用类型,事情就不是想象中的那么完美。
通过修改src[0]的标签导致dest[0]的标签也随之改变,而修改dest[1]标签后也引起src[1]相同的变化,这说明src[0]与dest[0],src[1]与dest[1]指向相同的内容空间,也表明如果源数组的类型为对象类型,那么arrycopy方法复制的是对象的引用,而不是对象本身。
注意:
与复制基本类型数据的数组不同,当数组的类型为对象类型时,arraycopy复制的是对象的引用,而不是对象本身。即复制完成后,源数组中某元素(引用)与对应的目标数组中元素(引用)指向相同的内存单元,其中一个元素的改动(所指向对象内容的改变,非引用的改变,请参考参数传递)将直接影响到另一个元素。
另外,在java.util包中存在一个Arrays类,该类中定义的方法可以对数组进行查询、排序、填充等操作。
总结
使用arraycopy
时,如果数组元素类型为基本数据类型
,那么数组复制后就类似于基本类型数据之间的复制,一个变量值的改变不会对另一个变量的值产生影响。
如果数组元素类型为引用类型
,那么数组复制后就类似于引用类型变量之间的复制,复制后两个引用指向同一内存单元,其中一个引用对对象所做的任何改变将直接影响到另一个引用。
early binding && late binding
early binding
: static method, final method, private method这些事early bindinglate binding
: 其他都是late binding
interface
要显示地声明为public
和abstract
length 和 length()
String 类要得到length,需要调length()方法,而没有length属性
s.indexOf(“#”,n);
从下标为n开始第一个匹配”#”的下标
Exception
构造方法子类的Exception与父类相比,只能多,不能少
方法,子类的Exception与父类相比,只能少,不能多
hashcode
Object中的hashcode用的就是Object的address
构造方法不能继承
in.nextLine()和in.next()吃不吃换行符
float a[10]; 错误
float[] a[];可以
boolean b = s1.compareTo(s2); 不对,compareTo返回int类型