03章-操作符(笔记)

 

 Java中大部分的操作符如下面的表3.4中描述(还有一些特殊用法后面会进行描述)

 

03章-操作符(笔记)

1、首先要对分隔符做一下描述,这些分割符都是指英文输入法下的[] ()  . , ;  这里只对.和,这两个分隔符的使用场景进行一下说明,.一般就是用在调用方法或属性,例如:System.out,而,在extends  Person,Teacher这样的场景下使用

2、短路:逻辑于(&&)和逻辑或(||),当使用这两种操作时,会遇到一种“短路现场”。既一旦能够明确无误地确定整个表达式的值,就不再计算表达式余下部分了。因此,整个逻辑表达式靠后的部分有可能不会被运算。例如:

public class TestShortCircuit {

	public static void main(String[] args) {
		int a = 3;
		int b = 5;
		boolean result = test(b,a) && test(a,b);
		if(result) {
			System.out.println(result);
		}
		
	}
	
	public static boolean test(int a,int b) {
		if(a < b) {
			System.out.println("前面的值小于后面的值");			
		}else {
			System.out.println("前面的值不小于后面的值");
		}		
		return a < b;
	}
}

 这段代码的输出结果为:“前面的值不小于后面的值” 当test(b,a)确定为false时整个表达式的值就能明确无误地确定整个表达式的值为false,所以test(a,b)就不会执行了。

3、移位操作符

左移位操作符(<<)能按照操作符右侧指定的位数将操作符左边的数操作数向左移动(在低位补0)。

“有符号”右移位操作符(>>) 则按照操作符右侧指定的位数将操作符左边的操作数向又移动。“有符号”右移位操作符使用“符号扩展”:若符号为正,则在高位插入0;若符号位负,则在高位插入1。

“无符号”右移位操作符(>>>)它使用“零扩展”:无论正负,都在高位插入0。

4、如果对char,byte或者short类型的数值进行移位处理,那么在移位进行之前,他们会被转换为int类型,并且得到的结果也是一个int类型的值。只有数值右端的低5位才有用。这样可以防止我们移位超过int型值所具有的位数。

注释:只有数值右端的低5位才有用  指的是当对一个char,byte,short,int(当然char,byte,short也会转换为int)进行移位的时候只会取移位数的二进制表示法的低5为,因为低5位 11111 最大可以表示31,指的是int类型的移位数最大为31为,当移位数超过31位的时候,会通过 移位数%32  来获得取模后的数进行移位操作。

5、“移位”可与“等号”(<<=或>>=或>>>=)组合使用。此时,操作符左边的值会移动由右边指定的值指定的位数,再将得到的结果赋给左边的变量。但在进行“无符号”右移位结合赋值操作时,可能会遇到一个问题:如果对byte或short值进行这样的移位运算,得到的可能不是正确的结果。他们会先被转换成int类型,再进行右移操作,然后被截断,赋值给原来的类型,在这种情况下可能得到-1的结果。例如:

public class TestUnsignedRight {

	public static void main(String[] args) {
		
		short s = -1;
		System.out.println(Integer.toBinaryString(s));
		
		//这里其实进行了一次强制将int转换成short,将int进行了截取
		s >>>= 10;
		System.out.println(Integer.toBinaryString(s));
		
		s = -1;
		System.out.println(Integer.toBinaryString(s>>>10));
		
		//这种没有经过强制转换的才是我们需要的结果
		s = -1;
		//s = s >>> 10;  这句代码是编译不过的
		s = (short)(s >>> 10);
		System.out.println(Integer.toBinaryString(s));
		
		/*输出结果为
 		11111111111111111111111111111111
		11111111111111111111111111111111
		1111111111111111111111
		11111111111111111111111111111111*/
		
	}
}

 一旦进行了强制转换的话,将原本返回的int类型,进行截取后面的内容后,该short或byte的值为-1,当通过Integer.toBinaryString(s)进行打印的时候,-1的值又会被赋值给一个int的值,所以得到的最终结果为-1。

导致这种问题的根本原因还是这种 >>>=  组合操作符会对生成的结果进行一次强制类型转换,导致数据被截断导致的。

6、基本数据类型自动提升

如果对基本数据类型执行算术运算或按位运算,只要类型比int小(既char、byte、short),那么在运算之前,这些值会自动转换成int。这样一来,最终生成的结果就是int类型。通常,表达式中出现的最大的数据类型决定了表达式最终的结果的数据类型。如果将一个float值和一个double值相乘,结果就是double;如果将一个int和一个long值相加,则结果为long。例如:

public class TestUpper {

	public static void main(String[] args) {
		short s1 = 1;
		short s2 = 2;
		short s3;
		int i1;
		//s3 = s1 + s2;    这句无法编译过,因为返回的值会是一个int
		i1 = s1 + s2;	
		
		//test(3);   由于默认在不声明整数类型的情况下,默认为int,所以编译不过
		test((short)3);
	}
	
	static void test(short s) {
		System.out.println(s);
	}
}

 

注释:(1) java中默认的整数类型为int,默认的浮点类型为double。也就是说当在不声明的情况下直接使用一个整数类型它默认是int类型,在不声明的情况直接使用一个浮点类型时默认为double。(作为参数时的情况,参考上面的例子)

           (2) 在运算之前char,byte,short等数据类型都会转换成int类型,即使运算中没有出现int类型,它们在运算之前也会自动转换成int类型。 

 

7、除了上表中列出的运算符外,另外我们将 +=  -=   *=  /=  >>=  >>>=  <<=  %=  等基本这些二元操作符都可以与=操作符组合使用,在使用这些运算符时,包含了默认的强制转换过程,例如:

public class TestOther {

	public static void main(String[] args) {
		short s1 = 1;
		short s2 = 2;
		s1 += s1 + s2;
		//s1 = s1 + s2;  这句编译不过
		s1 = (short)(s1 + s2);  
		
		/*
		 由于byte、char、short在进行运算前会自动转换成int类型,所以运算后生成的类型会为int类型
		 通过上面可见 += 等这样的操作相当于在执行=操作前先进行了一次,强制类型转换将int转换成short
		 */
	}
}

不过这里会引发一些疑问,既然byte、short类型的数据在运算前都会自动转换成int类型,那么为什么还需要byte、short类型那?

这需要从以下两个方面来解释了

(1)首先单纯的从存储上来讲:当你数字为-32768~32767之间的整数时,完全可以声明为short,开辟两个字节(也就是16位)的内存空间存储这个变量,如果你声明为int,将开辟4个字节(也就是32位)的内存空间来存储这个变量,所以你会有很大的内存空间(16位)的浪费。这个内存浪费在PC上面可能无关紧要,但是JAVA本身最开始的设计初衷就是为了嵌入式/移动设备开发的语言,在这些系统上内存一般都很小,很宝贵,有的可能就几M的存储空间,当你有大量的空间浪费的时候,这将是一件很恐怖的事情

(2)再说说JAVAIO,JAVA IO为了应对不同的数据源有很多种方式,但是总的可以分为两类:字节流跟字符流,字节流是对文件的直接操作,字符流使用到缓存。而字节流直接操作的对象就是byte型的变量(封装类),因为byte刚好对应着一个存储单位。