前言

  在2019年的时候,公司就开始提倡让Domino技术线的同事对Java相关的技术进行学习。其实,由于各种项目上的杂事,我并未按公司的要求投入精力去研究与工作任务不相关的技术。
  这并不能说明我抵触公司的技术学习建议,也不是我不喜欢学习新东西。也就是在这2020年初疫情严重,居家隔离的日子里,我开始了Java基础技能的学习(也可以叫做“唤醒”吧,十年之前也接触过很长一段的Java开发)。
  为了简单,我从w3school在线站点中找到了Java相关的信息,学了起来,在 《Java 基本数据类型》中,读到

byte:
byte数据类型是8位、有符号的,以二进制补码表示的整数;
最小值是-128(-2^7);
最大值是127(2^7-1);
默认值是0;
byte类型用在大型数组中节约空间,主要代替整数,因为byte变量占用的空间只有int类型的四分之一;
例子:byte a = 100,byte b = -50。

时,发现了一些东西似懂非懂的,我也不想囫囵吞枣地草草学习。如
为什么short类型的变量可以表示的最小值是-128,不是说首位是符号位吗?(我想着最小位还是(11111111)2)呢!!
注:其实,long、int、short、byte在表示数值范围方面的规律都是相通的,本文中我就以byte类型为例阐述。

byte类型基础知识

javadouble极限 java数值上限_System时,也就相当于在内存中申请了长度为8的内存块——每一位只能放0或1,这样一来就有2^8种组合状态
(0000 0000)2
(0000 0001)2
… …
(1111 1101)2
(1111 1110)2
(1111 1111)2
  如果将这些二进制数转为十进制,那么它的范围将是[0,255]。可惜的是,在byte类型中,也要对负数进行表示。而在Java语言中,byte类型做为带符号数,将8位中的第一位用作符号(+或-)位,剩余的7位表示数值。

正值的表示

  8位二进制的第一位为0时,表示正数,用原码表示正数。像下面这样:
(0000 0001)2
(0111 0000)2

  都是正数,分别表示了十进制中的1和112。这样,对于序列(0111 1111)2(2^7-1)就是byte类型能表示的最大值了。
特别一点:(0000 0000)2 就是十进制的0

负值的表示

  8位二进制的第一位为1时,表示负数,用补码表示负数。像下面这样:
(1000 0001)2
(1111 1110)2
(1111 1111)2

  都是负数,分别表示了十进制中的-127、-2和-1。是怎么计算出来的呢?拿(1111 1110)2为例分析:

  1. 二进制的第一位,表示这个数字是负的;
  2. 再减1,得到(1111 1101)2
  3. 再按位取反,得到(0000 0010)2(注意,此时第1位已不再表示符号,所以这个值是2),这个2你可以理解为原始十进制负数的绝对值。
  4. 将第一步与第三步得到的信息合并一下,可以知道(1111 1110)2表示的值是-2

  这时候说说,byte能表示的最小值吧。我们看看(1000 0000)2这个二进制数。与下面的分析过程一一对应,我们来一遍。

  1. 二进制的第一位,表示这个数字是负的;
  2. 再减1,得到(0111 1111)2
  3. 再按位取反,得到(1000 0000)2(注意,此时第1位已不再表示符号,所以这个值是2^7,即128)
  4. 将第一步与第三步得到的信息合并一下,可以知道(1000 0000)2表示的值是-128

最后

  闲着无聊,写一段代码。输出一个整数的二进制序列吧!
代码:

package com.tianyq;

public class ClsOutputBinaryStr {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		//printBinaryStr(new Byte((byte) -117));
		System.out.println("byte类型的数值-117在计算机中的二进制表示为:" + printBinaryStr(new Byte((byte) -117)));
		// printBinaryStr(new Short((short)3));
		System.out.println("short类型的数值-20000在计算机中的二进制表示为:" + printBinaryStr(new Short((short)-20000)));
		// printBinaryStr(new Integer(3));
		System.out.println("int类型的数值12580在计算机中的二进制表示为:" + printBinaryStr(new Integer(12580)));
		// printBinaryStr(new Long(3));
		System.out.println("long类型的数值823742430859l在计算机中的二进制表示为:" + printBinaryStr(new Long(823742430859l)));
	}

	// 泛型方法 printArray
	public static <E> String printBinaryStr(E input) {

		String result = "";
		int byteLen = -1;
		long from = 0;
		switch (input.getClass().toString()) {
		case "class java.lang.Byte": // 一个字节 8 位
			System.out.println("Byte");
			Byte b = (Byte) input;

			from = b.byteValue();
			byteLen = 8;
			break;
		case "class java.lang.Short": // 二个字节 16 位
			System.out.println("Short");
			Short s = (Short) input;

			from = s.shortValue();
			byteLen = 16;
			break;
		case "class java.lang.Integer": // 四个字节 32位
			System.out.println("Integer");
			Integer i = (Integer) input;

			from = i.intValue();
			byteLen = 32;
			break;
		case "class java.lang.Long": // 八个字节 64位
			System.out.println("Long");
			Long l = (Long) input;

			from = l.longValue();
			byteLen = 64;
			break;
		default:
			System.out.println(input.getClass().toString());
			break;
		}

		if (byteLen == -1) {
			return result;
		}

		long formCp = Math.abs(from);

		StringBuffer sb = new StringBuffer();

		//以下代码会计算出from绝对值的原码
		do {
			sb.append(formCp % 2);
			formCp = formCp >> 1;
		} while (formCp != 0);
		
		//补0
		for(int index = sb.length(); index < byteLen - 1; index ++){
			sb.append("0");
		}
	
		//如果是正数
		if(from >= 0){
			sb.append("0");
		}else{
			sb.append("1");
		}
		
		//以下是原码
		//原码:一个正数,按照绝对值大小转换成的二进制数;一个负数按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。
		sb = sb.reverse();
		//System.out.println(from + " 的绝对值的二进制原码 " + sb.toString());
		result = sb.toString();
		//负数复杂一点,因为 在计算机中,负数以原码的补码形式表达
		if(from < 0){
			//得到反码 - 反码:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反
			
			//每一位取反(除符号位)
			for(int index = 1; index < byteLen; index ++){
				if(sb.charAt(index) == '1'){
					sb.setCharAt(index, '0');
				}else{
					sb.setCharAt(index, '1');
				}
			}
			//System.out.println(from + " 的二进制反码 " + sb.toString());
			//补码:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1
			//通过从尾部查找字符,模拟二进制加法
			for(int index = byteLen - 1; index > 0; index --){
				if(sb.charAt(index) == '0'){
					sb.setCharAt(index, '1');
					break;
				}else{
					sb.setCharAt(index, '0');
				}
			}
			//System.out.println(from + " 的二进制补码 " + sb.toString());
			result = sb.toString();
		}

		return result;
	}
}

以上代码的执行结果如下:

Byte
byte类型的数值-117在计算机中的二进制表示为:10001011
Short
short类型的数值-20000在计算机中的二进制表示为:1011000111100000
Integer
int类型的数值12580在计算机中的二进制表示为:00000000000000000011000100100100
Long
long类型的数值823742430859l在计算机中的二进制表示为:0000000000000000000000001011111111001010110111111111111010001011

OK,文章写到这里就结束了。