明确一下正负数的补码及其内存中的补码表示
正数的补码和原码相同。
负数的补码为“其绝对值的补码”。
已知内存中补码,先根据最高位0或1判定为负数还是正数,若正数,直接计算其值;若负数,计算该补码的“补码”,其值为该负数的绝对值。
位运算:使用符号有:& | ^ ~
“~”它有点类似于NOT操作符,不过NOT操作符的操作数只能是boolean 类型,而“~”用在int类型!
~3 //= -4
位移运算
-20>>3 结果是3,并不是-20/8 = -2
byte b =127;
b=b<<1;
运算结果比原来的数据类型所能表示的范围还大,上面byte操作时,结果超过了byte类型的最大值,所以Java会把它自动转化为int类型,而b声明的是byte类型,int-->byte:编译器就会出现错误信息。
int i=1;
i=i<<31;
1会跑到最左边的那个位,表示负数。
一般情况下,
byte y = 8 ;
y=y>>3;
这样语句会报错,错误信息“possible loss precision;found :int ;required:byte ”~~
Java对位移超过32位的运算做处理,称为“减次运算”,把要左移的位数先mod 32(%32) 然后再去做位移运算。对于右移也是一样会做减次的处理。
无符号位移“<<<”
不管正负数,全在左边缺少的地方补上0。这个无符号的右移操作符,只能用在int或long类型中,如果操作数是byte或者short类型时,自动类型转化为int.
为什么有些数据类型的数值后面,要加上一个英文字母:0.0f、1223L。
这跟java对字面值默认的数据类型有关,整数默认为int类型,浮点数的字面值默认为double类型。
可以理解为强制类型转换的一种。就如对于byte或short,
比较运算:
大于,小于,大于等于,小于等于优先级一样的,而等于与不等于优先级比前面四种低。
1>2==3<4
boolean 类型不能转化为其他的数据类型。同样其他类型数据不能转化为boolean类型。
boolean c =false;
c=1; //error incompatible types
运算符的优先权
一般规律:
单目运算符 大于 双目运算符 大于 三目运算符
算术运算符 大于 位移运算符 大于 比较运算符 大于 位运算符 大于 逻辑运算符
这些运算符最低:
= += -= *= /= %= &= |= ^= ~= <<= >>= >>>=
详细参考: http://jyasa.iteye.com/blog/409610
break 与continue
continue 是强迫跳回到循环的条件判断式,
标签
<标签名称>:
虽然在程序中的任何地方可以使用标签,但是如果在循环中使用到break和continue的话,则两者用到的那个标签必须紧邻着循环语句。
loop1:
int i =0 ;
for(i=1;i<=10;i++)
continue loop1;
java不允许这样的写法,这样写造成运行的程序无法控制。
java中的switch-case
switch-case 的两种流程:switch-case with break 和 switch -case without break 。
原则:跳后顺序执行
只能接受byte,short,int ,char 类型变量的判定,如果使用long类型编译出错。简单的一句:能够自动转型成int类型的数据类型都可以。
switch的简单写法:
switch(A) {
case B;
}
首先,A部分值必须是int型的,或者是能够自动进行转换成int型的表达式。也就是说A部分可以是 byte\short\char\int型的。
其次,B部分的值必须是单个byte\short\char\int型的值,或者是final型的变量,或者表达式(结果必须满足前面的四种类型)
但是final型的变量是有要求的,它必须是编译时的常量,怎么讲呢,看下面的程序段:
final int a = 0;
final int b;
第二个语句就是在编译时不能够被识别出值的变量,因为它没有初始化,当然,这条语句也是错误的。
所以case后的值可以是常数值或final型的值或表达式。
构造函数中this和super关键字的使用
this和super只能使用构造函数的第一行,作为第一句。这也限定了在构造函数中只能使用两者中的其中一个。
当一个构造函数中,没有this和super的时候,java编译器会自动帮你加上super()的调用。
Java中三种现象:重载、遮蔽、重写
遮蔽:如果在子类中定义了与父类中相同名字的属性的话,那么当你直接使用时,就是使用自己的属性。而不是继承自父类的属性。
当如果你想要在子类(或实例)中使用父类的属性时,通过使用super这个关键字。
super.<属性名字>
当然this也可以使用,但是this.i和i没区别。只有这种情况下才体现了this.i的价值:当在方法中声明了和属性相同名称的变量时。
//强制类型:子类转换为父类
//A为B的父类
this.i ; //B类中的i
((A)this).i ; // A类中的i
另外两者就不用说,经常使用到的两个概念。
改写需要注意的地方:
类方法不能被改写。
修饰符的使用权限只能越开放,不能越封闭。(父母总是望子成龙,望女成凤嘛)
final
对类:类不能被继承
对方法:方法不能改写(重写)
对变量:在第一次指定变量值之后就不能再修改
这个变量一旦被初始化便不可改变,这里不可改变的意思 对基本类型 来说是其值不可变,而对于对象变量 来说其引用不可再变。然而,对象其本身却是可以被修改的, Java 并未提供使任何对象恒定不变的途径。这一限制同样适合数组,它也是对象。
final引用指该引用不能指向另外的一个对象。
GC的回收顺序与GC的何时运行
回收的顺序跟对象实例产生的顺序有关。
就算我们手动调用了System.gc(),GC也不一定会真正运行,就算我们不手动调用Gc,GC也会在适当的时候自动运行。
那System.gc()的作用是什么呢?只是建议系统应该去打开GC,而不是强迫系统一定要打开GC。
注意:如果程序运行的时间太短,GC将来不及打开。取消某对象(“null”)时对象并没有马上被回收。
线程安全
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
hashcode()和equals()方法的理解
1,两者是不同的方法,在Object中如下
method, then calling the hashCode method on each of
the two objects must produce the same integer result.
Object 类中的 hashcode() 方法,它是一个本地方法 , 比较的是对象的地址(引用地址)。而Object类的equals方法比较的就是对象的地址直。很明显了,equals得到true说明地址相同,对相同的地址求哈希直肯定相等咯,所以hashcode返回值相同;hashcode相等,地址一般情况下 是相等的,所以equals方法返回true。
public boolean equals(Object obj) {
return (this == obj);
}
如果没有重写类的equals和hashcode方法,则该类的这两个方法存在如下关系:
hashcode() 返回的直相等与否和 equals()返回值真假是一致的 。
===========================
在实际应用中,为什么要重写类的hashcode方法和equals方法. 参见《java编程思想》494页.
=============================
设计hashCode()一个重要的因素是:无论何时,对同一个对象调用hashCode都应该生成同样的值。
HashMap中hashcode的使用,只是为了提高查询的速度。
hashcode并不是唯一的,不同的对象可以有相同的hashcode。
“槽位”slot 或者桶位“bucket” ,为linkedList。
Map 中put方法的实际过程是: 首先根据key计算出hashcode,然后根据hashcode定位到某个桶位,在桶位中你使用equals方法比较key,如果存在相同的key就将value值替换,如果不存在相同的key,则添加到LinkedList的末尾。
set中的put方法是通过HashMap来实现的。value值是Object对象。
======================
String对象重写hashcode方法和equals方法,为了比较字符串(不关心对象)。