这篇博文主要是记录了 Java 语言部分的一些容易被忽视的问题,对于自己来说是一个梳理,也是一个备忘。

  • 关于 char 类型的赋值:可以将一个0到65535之间的整数值直接赋给 char 类型变量,但是超出范围的数值则会引起错误;不能将两个单引号直接赋给 char 类型变量(尽管对于字符串变量可以使用两个双引号直接赋值);
public class CharAssignment {

	public static void main(String[] args) {
		char c1=200; //正确。
		char c2='';  //错误:这样会得到编译时错误。
	}
	
}
  • 对于 byte 和 short 类型赋值:可以将在其范围内的数值直接赋给他们,而不用强制转换,但是超出范围则报错;
  • 对于 float 类型赋值:可以直接将整数赋给它,但是不能奖小数直接赋给它,一定要再小数后面加字母 f,例如:3.14f。

  •  Java 中变量间的赋值:对于基本数据类型的变量赋值给其他变量时,是将其内容复制一份到其他变量;对于对象进行这样的操作时,是将“引用”从一个地方复制到另一个地方。当然在方法调用中也是如此的传递值或引用。

  • 基本类型与包装器类型会自动地相互转换:
public class WrapperAndBasicDataType {
	public static void main(String[] args) {
		char c='a';
		Character C=new Character('b');
		
		c=C;//Character 可以直接赋给 char;
		C=c;//char 也可以直接赋给 Character;
		
	}
}

  •  整数除法会直接去掉结果的小数位,而不是四舍五入;
  • 求余运算的符号只与第一个数字的符号相关:
System.out.println(-8%3); //-2
	System.out.println(-8%-3);//-2
	System.out.println(8%-3); //2
	System.out.println(8%3);  //2
  • 关系操作符:== 和 != 适用于所有的基本数据类型,而其他比较符吧适用于 boolean 类型的,因为 boolean 值只有 true 和 false,比较大小没有意义;== 和 != 也适用于所有对象。关于 == 和 equals() 方法:对于 == 比较对象的时候,永远都是比较对象的引用,在比较基本类型的时候是比较值;对于 equals() 方法用于比较对象时,默认情况下也是比较对象的引用,然而如果对象的类重写了 equals() 方法,那就需要考虑其 equals() 方法实际比较的是什么。事实上对于包装器类、String 类等 equals() 方法都进行了重写,比较的是对象的内容,而不是对象的引用。
  • 逻辑操作符:逻辑“与”(&&)、“或”(||)、“非”(!)只可应用于布尔值。注意这与 C 语言是不同的。
  • 按位操作符:是用来操作整数基本类型中的单个 bit,包括:与(&)、或(|)、异或(^)、非(~)。值得注意的是,布尔值可以被看做是一种单比特的值对待,从而可以执行与(&)、或(|)、异或(^)操作,但是不能执行非(~)操作,可能是为了避免与逻辑非混淆。还有一点,按位操作是没有“短路”。
  • 移位操作符:只可用来处理整数类型。如果对 char 、byte 或者 short 类型的值进行移位操作,那么在移位进行之前将被先转换成 int 类型,再进行移位操作。倘若还要将结果赋给相应的 char、byte 或者 short 类型则需要进行截断,当然截断都是截取右边的部分相应的位数。
  • 只要类型比 int 小(char、byte 或者 short 类型),那么在运算之前这些值都会被自动转换成 int。这样生成的结果值就是 int。如果想要将结果赋给较小的类型就必须使用强制类型转换。
  • 逗号操作符:注意不是逗号分隔符。Java 里唯一用到逗号操作符的地方就是 for 循环的控制表达式。这也就隐含着在一个控制表达式中,定义多个变量的这种能力只限于 for 循环使用,在其它任何选择或者迭代语句中都不能使用这种方式。

  •  将整数值转化成其二进制形式的字符串,可以使用 Integer 类或 Long 类的静态方法 toBinaryString()。需要注意的是将比较小的类型传递给 Integer 的 toBinaryString() 方法时会被先自动转换为 int 然后再输出对应的 int 数值的二进制形式字符串。例如若是 short 类型的-1,则本来是16个1,可是在输出结果中我们将看到32个1。对于 Long 类也是一样。
public class Literals {

	public static void main(String[] args) {
		int i=0x2f;
		System.out.println(Integer.toBinaryString(i));
		char c=0xffff;
		System.out.println(Integer.toBinaryString(c));
		byte b=0x7f;
		System.out.println(Integer.toBinaryString(b));
		short s=0x7fff;
		System.out.println(Integer.toBinaryString(s));
		long l1 = 200L;
		//System.out.println(Integer.toBinaryString(l1));这行代码是行不通的
		System.out.println(Long.toBinaryString(l1));
		long l2 = 200;
		//System.out.println(Integer.toBinaryString(l2));这行代码是行不通的
		System.out.println(Long.toBinaryString(l2));
		short s2=-1;
		System.out.println(Integer.toBinaryString(s2));

}}

  •  将一个浮点值转换成整型值:如果是使用 int 执行强制类型转换,则一定是截尾,而不是进行四舍五入。如果要进行舍入,可以使用 Math.round() 方法:
public class CastingNumbers {

	public static void main(String[] args) {
		double above=0.5,below=0.4;
		double negab=-0.5,negbe=-0.4;
		double negab2=-0.6;
		System.out.println((int)above);//0
		System.out.println((int)below);//0
		System.out.println((int)negab);//0
		System.out.println((int)negbe);//0
		
		System.out.println(Math.round(above));//1
		System.out.println(Math.round(below));//0
		System.out.println(Math.round(negab));//0
		System.out.println(Math.round(negbe));//0
		System.out.println(Math.round(negab2));//-1
	}

}

注意:这里有一个很奇葩的事情,就是如果是0.5则舍入值为1,而如果是-0.5摄入值却是0。也就是说对于正数是加0.5再截断,而对于负数是减0.4再截断。但也可以从另外一个角度理解:就是将数值都加0.5,再向下取整。


  • Java 的作用域和 C 一样是有花括号的位置决定的:
{
		int x=12;
		//x 可见
		{
			int q=96;
			//x 和 q 可见
		}
		//x 可见
	}

但是值得注意的是,如下程序在 C 中是正确的,而在 Java 中时错误的:

{
		int x=2;
		{
			int x=3;
		}
	}

在 C 中可以将交大作用域的变量“隐藏”起来的做法,在 Java 里是不允许的。还有一点对于 Java 对象,它可以存活于作用域之外,只不过是对象的引用在作用域的终点消失。


  • Java 中的标签与 break 和 continue。这主要是应用在多层循环中。
label:
outer-iteration {
    inner-iteration {
        //...
        break;//(1)
        //...
        continue;//(2)
        //...
        continue label1;//(3)
        //...
        break label1;//(4)
    }
}

在(1)中是中断内部迭代,回到外部迭代。在(2)中,continue 的执行点略过后面的语句移回到内部迭代处起始处,继续下一步的迭代。在(3)中,执行点略过后面的语句移回到外部迭代(label1 标签所指的循环)起始处,继续外部迭代的下一步迭代。在(4)中,会终止外部迭代,也就是终止所有迭代。


  • switch 语句的选择因子必须是 int 或 char 那样的整数值,而不能是字符串或浮点数。对于这种限制请将 enum 和 switch 结合,参见后面的博客。

  • 初始化默认值:在 Java 中,对于类的成员变量,会确保它们得到初始化,初始化值如下表:

 

基本类型

默认值

boolean

false

char

'\u0000'(null)

byte

0

short

0

int

0

long

0

float

0.0

double

0.0

 

上面只给出了基本类型的情况,而对于对象则初始化为 null。值得注意的是,确保初始化的方法并不适用于“局部”变量(即并非某个类的字段),例如在某个方法定义的变量,若初始化,Java 会在编译时报错。


其它:

  •  如何获取系统环境的信息:
System.getProperties().list(System.out);
System.out.println(System.getProperty("user.name"));

System.getProperties 返回的是一个 Properties 对象,它是继承自 Hashtable<Object, Object>。详见 JDK 文档。

  • 产生0到1(不包括)之间的一个 double 值:
Math.random()
  • 判断字符是不是小写字母:
Character.isLowerCase()
  • 将字符串转为字符数组(非静态方法),例如:
"hello".toCharArray()