本文介绍java中整数的3种进制表现形式,对进制间转换方法进行了总结。
进制及进制由来
1. Java中,整数有3种表现形式:
十进制:0~9,满10进1
八进制:0~7,满8进1,用0开头表示
十六进制:0~9,A~F,满16进1,用0x开头表示
2. 进制的由来:任何数据在计算机中都是以二进制的形式存在,一个整数在内存也是二进制的,但是使用一大串1或0组成的数值很麻烦,所以将二进制中的3位或4位用一位表示,就出现了八进制和十六进制,进制越大,表现形式越短。这个由来也是后面进制间转换的算法基础。
进制间转换
进制间的转换是很常见的,下面列出了十进制转换成二进制、八进制、十六进制的3种方法,为了完整性,后面补充其它进制转换成十进制的2种方法。
1. 普通方法
也就是进行循环除法,先说十进制转换成二进制,十进制转换成二进制的原理就是进行除2运算,用while循环实现:
public class Test{
public static void main(String[] args) {
toBin(60);
}
public static void toBin(int num){
StringBuffer sb=new StringBuffer();
while(num!=0){
sb.append(num%2);
num=num/2;
}
System.out.println(sb.reverse());
}
}//运行结果为打印111100
类似地,十进制转换成八进制或十六进制就是循环进行除8或16运算,因除8或16运算很麻烦,耗费资源较多,考虑将十进制数转换成二进制数,二进制数的每3或4位用一个数表示即可,因位运算与(&)、或(|)、异或(^)运算实际就是将数据转换成二进制数在内存中进行运算,所以此处考虑用位运算,使用&可以达到每次读出二进制数的后3位或4位进行依次转换。以十六进制为例,代码如下:
public class Test2{
public static void main(String[] args) {
toHex(60);
}
public static void toHex(int num){
StringBuffer sb=new StringBuffer();
while(num!=0){
int temp=num&15;
if(temp>9){
sb.append((char)(temp-10+'a'));
}else{
sb.append(temp);
}
num=num>>>4;//无符号右移,这样程序就对负整数也是适用的
}
System.out.println(sb.reverse());
}
}
2. 查表法
十进制转换成二进制、八进制、十六进制,可以用一种通用的查表法来实现。
查表法思想:当一组数据与一个数组中的元素间存在对应关系,且这种关系有数组角标规律时,可以用查表法,这样能提高效率,简化代码。
public class Test3{
public static void main(String[] args) {
toBin(6);
toBin(-6);
toBa(60);
toBa(-60);
toHex(60);
toHex(-60);
}
//十进制——>二进制
public static void toBin(int num){
trans(num,1,1);
}
//十进制——>八进制
public static void toBa(int num){
trans(num,7,3);
}
//十进制——>十六进制
public static void toHex(int num){
trans(num,15,4);
}
public static void trans(int num,int base,int offset){
char[] chs={'1','2','3','4','5','6','7','8',
'9','A','B','C','D','E','F'};
StringBuffer sb=new StringBuffer();
while(num!=0){
int temp=num&base;
sb.append(chs[temp]);
num=num>>>offset;
}
System.out.println(sb.reverse());
}
}
另一个很容易想到的可使用查表法解决的问题是:输入一串阿拉伯数字,将其转换成汉字大写表示。代码不在这里贴了,个人觉得这也是查表法思想的一个典型例子。
3. 使用Integer类中的静态方法
Integer类是整数基本数据类型int的封闭,类中提供了现成的静态方法可以实现进制间的转换。
public class Test4 {
public static void main(String[] args) {
String s1=Integer.toBinaryString(60);//十进制转二进制
String s2=Integer.toOctalString(60); //十进制转八进制
String s3=Integer.toHexString(60); //十进制转十六进制
System.out.println("60的二进制表示是: "+s1);
System.out.println("60的八进制表示是: "+s2);
System.out.println("60的十六进制表示是 "+s3);
}
}
上面说了十进制转成其它进制的3个方法,那其它进制怎么转换成十进制呢?可以使用Integer类的现成方法,也可以自己写一个~
Integer类中还提供了其它进制转换成十进制的方法,就是parseInt()方法:
/*
Interger类的方法: static int parseInt(String str, int base), str是待转换成十进制的字符串,base表示进制
*/
public class Test5{
public static void main(String[] args) {
int t1=Integer.parseInt("111100", 2);//将字符串形式的二进制数转换为十进制数
int t2=Integer.parseInt("74", 8); //将字符串形式的八进制数转换成十进制数
int t3=Integer.parseInt("3c", 16);
System.out.println("111100的十进制值是: "+t1);
System.out.println("74的十进制值是: "+t2);
System.out.println("3c的十进制值是: "+t3);
}
}
其实我们可以手动写一个效果类似于parseInt()方法的,按照其它进制转成十进制的计算原理手动编写,比如十六进制0x23c转换成十进制数计算过程是:2*16^2+3*16+12=572。下面是我自己写的~:
public class Test6 {
public static void main(String[] args) {
System.out.println(transTen("fffffff1"));
}
public static int transTen(String str){
String regex="[0-9a-f]{8}";
if(str.matches(regex)){
return trans(str);
}else{
throw new RuntimeException("输入的字符串不合法,请重新输入");
}
}
public static int trans(String str){
int sum=0;
int len=str.length();
for(int i=0;i<len;i++){
char ch = str.charAt(i);
if(ch>='a'&&ch<='f'){
sum=sum+(ch-87)*(int) Math.pow(16,len-1-i);
}else{
sum=sum+(int)(Integer.parseInt(ch+"")*Math.pow(16, len-1-i));
}
}
return sum;
}
}//运行结果是-15
进制转换就总结到这。
负数的二进制
负数在内存的二进制表现是对应正数的二进制取反加1;反之,一个以1开头的二进制取反再加1就是对应的正数二进制表示
Int类型数据在内存中占4个字节,也就是32位,第1位是符号位,所以int型整数的最大值是2^31-1,按负数取反加1是对应正数的算法,最小值就是第1位为1,其余31位全为0的数,也就是-2^31,这样Int型整数的取值范围就是[-2^31,
2^31-1]。
Integer类中也有静态常量表示Int型整数的最大值和最小值,分别是Integer.MAX_VALUE,Integer.MIN_VALUE。
public class Test7{
public static void main(String[] args) {
int max=Integer.MAX_VALUE;
int min=Integer.MIN_VALUE;
System.out.println("int整数最大值是: "+max);//结果是2147483647
System.out.println("int整数最小值是: "+min);//结果是-2147483648
int a=max+1;
System.out.println("int型整数溢出,最大值加1是: "+a);/*结果是-2147483648*/
}
}
注:max在计算机二进制表示中第一位为0,其余31位为1,加1后,满2进一位,直到最高位,从而变成第一位为1,其余31位为0,这个值就是min的二进制表示;计算机只会按照其内部既有的规定运算,一个int整数占32位是不会改变的,正数和负数的计算机二进制表示也是不会变的,超过int最大值时就发生溢出。
类似地,byte,short,long都是有符号整数,分别占1个字节、2个字节、8个字节,对应的封装类分别为Byte,Short,Long.
byte型整数取值范围为[-128,127],对应Byte类有静态常量Byte.MAX_VALUE,Byte.MIN_VALUE.
short型整数取值范围为[-32768,32767],对应Short类有静态常量Short.MAX_VALUE,Short.MIN_VALUE.
long型整数取值范围为[-2^63,2^63-1],对应Long类有静态常量Long.MAX_VALUE,Long.MIN_VALUE.