动手动脑问题和课后实验性问题

一  动手动脑,枚举类型

enum Size{ SMALL , MEDIUM , LARGE }

使用:

1 Size s=Size.SMALL;

2 从字串转换为枚举 :Size t=Size.valueof(“SMALL”);

3 枚举值的foreach迭代:

private enum MyEnum{
		ONE, TWO, THREE
}
public static void main(String[] args) {
		for(MyEnum value:MyEnum.values()){
			System.out.println(value);
		}
}

 4 枚举还可用于switch语句中。

 5 示例:

package test1;

public class EnumTest {

	public static void main(String[] args) {
		Size s = Size.SMALL;
		Size t = Size.LARGE;
		// s和t引用同一个对象?
		System.out.println(s == t); //
		// 是原始数据类型吗?
		System.out.println(s.getClass().isPrimitive());
		// 从字符串中转换
		Size u = Size.valueOf("SMALL");
		System.out.println(s == u); // true
		// 列出它的所有值
		for (Size value : Size.values()) {
			System.out.println(value);
		}
	}

}

enum Size {
	SMALL, MEDIUM, LARGE
};

 输出:

false
false
true
SMALL
MEDIUM
LARGEf

 分析:枚举类型是引用类型,不是原始数据类型,所以 s.getClass().isPrimitive() 结果为false

每个枚举值都引用一个特定的对象,所以比较 s==t 结果为false

相同的枚举值引用相同的对象,所以比较 s==u 结果为true

可以使用==和equals()比较枚举类型的值,相同的枚举值引用相同对象,有一样的地址值,不同的枚举值引用对象不同,地址值不同,所以可以使用==进行比较

 

二  动手动脑:原码,反码,补码相关知识

对于正数:

反码、补码都与原码一样。


对于负数:

反码:原码中除去符号位,其他的数值位按位取反,即0变1,1变0
补码:反码+1
示例:

40:

原码:00101000
反码:00101000
补码:00101000
-30

原码:10011110
反码:11100001
补码:11100010

 

那么,计算机中为什么要设计补码这一概念呢?通过搜索资料,了解到相关原因。因为直接用原码涉及到减法操作,这就增加了计算机底层电路涉及的复杂性。而用补码操作时,当减去一个数时,可以看做加上一个负数,然后转变位加上这个负数的补码。即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.

通过计算机存储的发展历程也可看出补码的优势。在计算机中,利用补码的方式进行运算,就可以解决直接用原码来计算得到的结果是错误的问题,也解决了减法的问题。而根据所给的负数去得到它对应的补码的过程,就是找到一个正数来代替其负数的过程。如果用原码表示,让符号位也参与计算,对于减法来说,结果是不正确的。这也是计算机内部在存储数据时不使用原码的原因,为了解决这一问题,出现了反码。通过计算我们发现用反码计算减法,结果的真值部分是正确的。而唯一的问题出现在"0"这个特殊的数值上,虽然人们理解上**+0和-0**是一样的,但是0带符号是没有任何意义的,而且会有[0000 0000]原和[1000 0000]原两个编码表示0。为了解决这一问题,出现了补码。

又因为补码能多存储一个-128,而且在计算机底层中存储的是补码,所以在计算机中一个8位的二进制数的存储范围是用补码表示的[-128,127],而不是用原码或反码表示的[-127,127]。这也可以解释为什么计算机中一个字节的取值范围是[-128,127]。

总结来说,原码、反码、补码的使用,是人们为了让符号位能参与运算并让计算机底层运算更加简单而设计出来的数据存储表示方式。

 

示例程序,对正数,负数进行位运算

package test1;

public class EnumTest {
	public static void main(String[] args) {
		System.out.println("2&3的运算结果是:" + (2&3));
		System.out.println("2|3的运算结果是:" + (2|3));
		System.out.println("2^3的运算结果是:" + (2^3));
		System.out.println("2>>3的运算结果是:" + (2>>1));
		System.out.println("2<<3的运算结果是:" + (2<<3));
		System.out.println("~2的运算结果是:" + (~2));
		
		System.out.println("~(-2)的运算结果是:" + ~(-2));
	}

}
 
结果:
2&3的运算结果是:2
2|3的运算结果是:3
2^3的运算结果是:1
2>>3的运算结果是:1
2<<3的运算结果是:16
~2的运算结果是:-3
~(-2)的运算结果是:1

 

Java中的数是采用补码表示的

三  动手动脑:同名变量的屏蔽原则

每个变量都有一个“有效”的区域(称为“作用域”),出了这个区域,变量将不再有效,同名的变量在指定的范围内有自动屏蔽的原则。即局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。

示例:

package test1;

public class EnumTest {

	private static int num = 1;

	public static void main(String[] args) {
		int num = 2;
		System.out.println(num);
	}

}

 

四 Java中数据类型及数据类型转换

1 java中每个数据类型所占的位数,和表示数值的范围:

byte:1字节 -128~127
short:2字节 -2^15~2^15-1
int :4字节 -2^31~2^31-1
long:8字节 -2^63~2^63-1
boolean:1字节 true false(java中不能以0或非0代替)
float: 4字节 -3.403E38~3.403E38
double:8字节 -1.798E308~- 4.9E324
char:2字节 ’\u0000‘~' ’\uffff '(16进制的,换算过来即0~65535)

2 数据类型转换规则:

  (1)  布尔型和其它基本数据类型之间不能相互转换;

(2)byte型可以转换为short、int、long、float和double;

(3)short可转换为int、long、float和double;

(4)char可转换为int、long、float和double;

(5)int可转换为long、float和double;

(6)long可转换为float和double;

(7)float可转换为double;

注:(其中除了float类型转换为double类型为无精度损失,其他类型转换为double类型都是有精度损失)

 

五  动手实验

package test1;

public class TestDouble {

    public static void main(String args[]) {
        System.out.println("0.05 + 0.01 = " + (0.05 + 0.01));
        System.out.println("1.0 - 0.42 = " + (1.0 - 0.42));
        System.out.println("4.015 * 100 = " + (4.015 * 100));
        System.out.println("123.3 / 100 = " + (123.3 / 100));
    }
}

结果:

0.05 + 0.01 = 0.060000000000000005
1.0 - 0.42 = 0.5800000000000001
4.015 * 100 = 401.49999999999994
123.3 / 100 = 1.2329999999999999

可以看出使用double类型的数值进行计算, 其结果是不精确的

那么为什么double类型的数值进行运算得不到“数学上精确”的结果?

这个涉及到二进制与十进制的转换问题。N进制可以理解为:数值×基数的幂,例如我们熟悉的十进制数123.4=1×10²+2×10+3×(10的0次幂)+4×(10的-1次幂);其它进制的也是同理,例如二进制数11.01=1×2+1×(2的0次幂)+0+1×(2的-2次幂)=十进制的3.25。

double类型的数值占用64bit,即64个二进制数,除去最高位表示正负符号的位,在最低位上一定会与实际数据存在误差(除非实际数据恰好是2的n次方)。

举个例子来说,比如要用4bit来表示小数3.26,从高到低位依次对应2的1,0,-1,-2次幂,根据最上面的分析,应当在二进制数11.01(对应十进制的3.25)和11.10(对应十进制的3.5)之间选择。

简单来说就是我们给出的数值,在大多数情况下需要比64bit更多的位数才能准确表示出来(甚至是需要无穷多位),而double类型的数值只有64bit,后面舍去的位数一定会带来误差,无法得到“数学上精确”的结果。

 

六  动手动脑:字符串

示例:

package test1;

public class test {
	public static void main(String[] args) {
		int X=100;
		int Y=200;
		System.out.println("X+Y="+X+Y);
		System.out.println(X+Y+"=X+Y");
	}
	
} 

结果:

X+Y=100200
300=X+Y

使用运算符 + 连接字面量“The sum is” 和计算结果 sum将String 和其它数据类型相加,结果是一个新的String

代码中只有与字符串直接相连的“+”才会都被定义成连接符,“X+Y=”字符串与变量X之间用+连接,+做连接符,此时将变量X的值作为字符串直接连接,连接后仍是字符串,通过+与Y连接,同样将Y作为字符串连接。

代码从左往右执行,先遇到X+Y两个变量相加,+做运算符,进行加法运算,然后结果遇到+与字符串连接

 

posted @ 2022-09-11 21:20  ashuai~  阅读(81)  评论(0)    收藏  举报