在最底层,java中的数据是通过使用操作符来操作的。
操作符接受一个或多个参数,并生成一个新值。有些操作符可能会改变操作数自身的值,这被称为“副作用”(因为在产生新值的同时自己也被改变了),除了“=”、“==”和“!=”能操作所有的对象外,其他操作符只能操作“基本类型”。
一、赋值操作符-------“=”
赋值的意思就是把右边的值复制给左边,右边的值可以是任何常数、变量或者表达式,但左边的值必须是一个明确的已命名的变量,也就是说必须有一个物理空间可以存储等号右边的值。但是不能把任何东西赋给一个常数,常数不能在左边例如 0=a 是错误的,赋值可以划分为两种情况:
1.基本数据类型赋值
基本类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方。例如 a=b,那么b的内容就复制给a,若接着又修改了a,而b根本不会这种修改的影响
2.对象的赋值
对一个对象进行操作时,我们真正操作的是对对象的引用,所以将一个对象赋值给另一个对象,实际是将引用从一个对象赋值给另一个对象,实际将引用从一个地方复制到另一个地方。如果对对象使用c=d,那么都指向原本只有d指向的那个对象。
通过下面这个例子可以说明这个问题
class Tank { int level; } public class Assignment { public static void main(String[] args) { Tank t1 = new Tank(); Tank t2 = new Tank(); t1.level = 9; t2.level = 47; System.out.println("1: t1.level: " + t1.level + ", t2.level: " + t2.level); t1 = t2; System.out.println("2: t1.level: " + t1.level + ", t2.level: " + t2.level); t1.level = 27; System.out.println("3: t1.level: " + t1.level + ", t2.level: " + t2.level); } }程序输出的结果是
1: t1.level: 9, t2.level: 47
2: t1.level: 47, t2.level: 47
3: t1.level: 27, t2.level: 27
在这个程序中,创建了两个Tank类的实例,并对每个实例的level赋予了不同的值,然后将t2赋给t1,接着又修改了t1,但由于赋值操作的是一个对象的引用,所以修改t1的同时也修改了t2! 这是由于t1和t2包含的是相同的引用,他们指向相同的对象(原本t1包含的对对象的引用,是指向一个值9的对象。在对t1赋值的时候,这个引用被覆盖,也就是丢失了,而那个不再被引用的对象由“垃圾回收器”自动清理)
这种特殊的现象通常称作“别名现象”,是Java操作对象的一种基本方式。
3.方法调用中的别名问题
其实在方法中也会产生这种别名现象
class Letter { char c; } public class PassObject { static void f(Letter y) { y.c = 'z'; } public static void main(String[] args) { Letter x = new Letter(); x.c = 'a'; System.out.println("1: x.c: " + x.c); f(x); System.out.println("2: x.c: " + x.c); } }
1: x.c: a
2: x.c: z
二、关系运算符
主要讲一下==和!=以及equals方法。
先看一个程序
public class Equivalence { public static void main(String[] args) { Integer n1 = new Integer(47); Integer n2 = new Integer(47); System.out.println(n1 == n2); System.out.println(n1 != n2); } }程 序的输出结果是
false
true
尽管两个对象的内容相同,但是==和!=比较的是对象的引用,两个对象的引用是不同的,所以一个输出false一个输出true,如果想要比较对象的值就得需要用equals方法,但是这个方法不适合基本类型数据的比较,基本类型还是用==和!=来比较。
public class EqualsMethod { public static void main(String[] args) { Integer n1 = new Integer(47); Integer n2 = new Integer(47); System.out.println(n1.equals(n2)); } }这个程序的输出结果就是true,因为比较的是对象的值而不是对象的引用,因此值相等就输出true。
但是并不是所有的equals方法都管用,就像下面这个例子
class Value { int i; } public class EqualsMethod2 { public static void main(String[] args) { Value v1 = new Value(); Value v2 = new Value(); v1.i = v2.i = 100; System.out.println(v1.equals(v2)); } }这个程序的输出结果是false,可能会令你大吃一惊,这是由于equals的默认行为是比较引用,所以除非在自己的新类中覆盖equals()方法,否则不可能表现出我们希望的行为。大多数的java类库都实现了equals()方法,以便用来比较对象的内容,而非比较对象的引用。
三、位运算
位运算符的细节 |
|
<< |
空位补0,被移除的高位丢弃,空缺位补0。 |
>> |
被移位的二进制最高位是0,右移后,空缺位补0; 最高位是1,空缺位补1。 |
>>> |
被移位二进制最高位无论是0或者是1,空缺位都用0补。 |
& |
二进制位进行&运算,只有1&1时结果是1,否则是0; |
| |
二进制位进行 | 运算,只有0 | 0时结果是0,否则是1; |
^ |
相同二进制位进行 ^ 运算,结果是0;1^1=0 , 0^0=0 不相同二进制位 ^ 运算结果是1。1^0=1 , 0^1=1 |
|
&&(短路与):当左边为假时,右边不参加运算 |
|
&(单与)两边都运算不论结果咋样(|和||也是同样的道理) |
移位运算 |
向左移动几位就是该数乘以2的几次幂 |
|
向右移动几位就是该数除以2的几次幂 |
|
移位运算比普通的运算要简单方便,局限性只能对2的次幂进行运算 |
|
>>>无符号右移,无论高位是什么都用0补位 |
用途:
1.用&运算获取某个字段内的二进制最后几位数是啥
2.如果取中间的某一段则先将其后面的通过>>>运算将其舍掉
3.一个数抑或另外一个数两次后结果还是这个数(加密运算可以用)
四、类型转换