Java编码原理与字符集编码转换

本文深入讲解Java中的位运算,包括按位非、按位与、按位或、按位异或等操作及其应用场景。同时介绍了Java中数字的表示方法及补码的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[list]
[*][b]数字运算与位运算[/b]
在2进制里面,一个位只可能是0,或者1。 java里面支持的位运算有:

~ 按位非(NOT)
& 按位与(AND)
| 按位或(OR)
^ 按位异或(XOR

位操作需要跟逻辑操作区分开(逻辑运算符AND(&&)、OR(||)以及NOT(!)能生成一个布尔值(true或false) ——以自变量的逻辑关系为基础) ,这里的区分的重点是敲代码不要敲错了。。。。
[*][b]数字的表示[/b]
计算机数字有原码、反码、补码三种存储格式,通常都是补码(方便减运算),java也不例外的使用补码。

补码:一个数如果为正,则它的原码、反码、补码相同;一个数如果为负,则符号位为1,其余各位是对原码取反,然后整个数加1。

+7的补码为: 00000111 -7的补码为: 第一步:11111000,第二步+1=11111001

补码求具体值也概括两句话:

正数补码的值就是本身值,负数补码的值分两步:

已知一个负数的补码,将其转换为十进制数,步骤:
1、先对各位取反;
2、将其转换为十进制数;
3、加上负号,再减去1。

Java代码
11111010,最高位为1, 是负数,先对各位取反得00000101,转换为十进制数得5,加上负号得-5, 再减1得-6。
[*][b]具体运算解析[/b]
可参考:[url]http://www.itwis.com/html/java/j2se/20090223/3407.html[/url]

[*][b]~ 按位取反操作符,对每个二进制位的内容求反,即1变成0,0变成1[/b]

测试负数:
int a = -5;//101;
System.out.println(~a);
打印:4
过程是这样的,首先表示出来这个负数
1111 1111 1111 1111 1111 1111 1111 1011(上面已经提到为什么这样表示)
各位取反得到
0000 0000 0000 0000 0000 0000 0000 0100
转为10进制得到4

[*][b]测试正数:[/b]
int a = 5;//101;
System.out.println(~a);
打印:-6
首先表示出来这个正数:
0000 0000 0000 0000 0000 0000 0000 0101
各位取反得到:
1111 1111 1111 1111 1111 1111 1111 1010
这个代表的就是-6了,至于为什么看最上面

[*][b]& 位与操作符,对应的二进制位进行与操作,两个都为1才为1,其他情况均为0[/b]
测试:
System.out.println(5&6);
打 印:4
过程:
5表示成:0000 0000 0000 0000 0000 0000 0000 0101
6表示成:0000 0000 0000 0000 0000 0000 0000 0110
进行 & :0000 0000 0000 0000 0000 0000 0000 0100
得到:4

[*][b]| 位或操作符,对应的二进制位进行或操作,两个都为0才为0,其他情况均为1[/b]
测试:
System.out.println(5|6);
打 印:7
过程:
5表示成:0000 0000 0000 0000 0000 0000 0000 0101
6表示成:0000 0000 0000 0000 0000 0000 0000 0110
进行 | :0000 0000 0000 0000 0000 0000 0000 0111
得到:7

[*][b]^ 异或操作符 当对应二进制位值相同,该位为0 否则为1[/b]
测试:
System.out.println(5^6);
打 印:3
过程:
5表示成:0000 0000 0000 0000 0000 0000 0000 0101
6表示成:0000 0000 0000 0000 0000 0000 0000 0110
进行 ^ :0000 0000 0000 0000 0000 0000 0000 0011
得到:3

在Java中是左移、有符号右移和无符号右移运算 符。位移运算符只对int值进行操作,如果不是int,编译器会报错。在Java中,一个int的长度始终是 32bit,也就是4个字节。

[*][b]<< 逻辑左移,右边补0[/b]

左移后低位空出来的不论符号全部补0,最高位由于挪动可能导致0/1更替使得数字颠倒了正负。

[*][b]>>带符号右移运算:[/b]
把操作数向右移动,移动的位个数同样由操作数指定。如果原值是正数, 则高位补上0;如果原值是负数,高位补1。由于高位补0还是1跟正负有关,所以叫带符号右移

[*][b]>>>无符号的右移运算[/b]
类似>>,区别在于:无论是正号还是负号,都在 高位补0。

[/list]

[b]字节码与16进制间的转换[/b]

//字节码转换成16进制字符串
public static String byte2hex(byte bytes[]){
StringBuffer retString = new StringBuffer();
for (int i = 0; i < bytes.length; ++i)
{
retString.append(Integer.toHexString(0x0100 + (bytes[i] & 0x00FF)).substring(1).toUpperCase());
}
return retString.toString();
}

//将16进制字符串转换成字节码
public static byte[] hex2byte(String hex) {
byte[] bts = new byte[hex.length() / 2];
for (int i = 0; i < bts.length; i++) {
bts[i] = (byte) Integer.parseInt(hex.substring(2*i, 2*i+2), 16);
}
return bts;
}

* Convert byte[] to hex string.这里我们可以将byte转换成int,然后利用Integer.toHexString(int)来转换成16进制字符串。
* @param src byte[] data
* @return hex string
*/
public static String bytesToHexString(byte[] src){
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
/**
* Convert hex string to byte[]
* @param hexString the hex string
* @return byte[]
*/
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
/**
* Convert char to byte
* @param c char
* @return byte
*/
private byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}

[b]JAVA UNICODE 与 字节字符串 互相转换[/b]

public static String unicodeEncode(String strText) {
char c;
String strRet = "";
int intAsc;
String strHex;
for (int i = 0; i < strText.length(); i++) {
c = strText.charAt(i);
intAsc = c;
if (intAsc > 128) {
strHex = Integer.toHexString(intAsc);
strRet += "\\u" + strHex;
} else {
strRet = strRet + c;
}
}
return strRet;
}

public static String unicodeDecode(String strText) {
StringBuilder sb = new StringBuilder();
int i = 0;
char c;
while (i < strText.length()) {
c = strText.charAt(i);
if (c == '\\' && (i + 1) != strText.length() && strText.charAt(i + 1) == 'u') {
sb.append((char) Integer.parseInt(strText.substring(i + 2, i + 6), 16));
i += 6;
} else {
sb.append(c);
i++;
}
}
return sb.toString();
}

[b]下面是我作得测试代码[/b]

package com.zhengtian.test;

import java.io.UnsupportedEncodingException;

/**
* 由于JDK是国际版的,在编译的时候,如果我们没有用-encoding参数指定我们的JAVA源程序的编码格式,则javac.exe首先获得我们操作系统默认采用的编码格式,也即在编译java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数(
* 它保存的就是操作系统默认的编码格式
* ,如WIN2k,它的值为GBK),然后JDK就把我们的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格式放入内存中。然后,javac把转换后的unicode格式的文件进行编译成.class类文件,此时.class文件是UNICODE编码的
* ,它暂放在内存中,紧接着,JDK将此以UNICODE编码的编译后的class文件保存到我们的操作系统中形成我们见到的.class文件。对我们来说,我们最终获得的.class文件是内容以UNICODE编码格式保存的类文件,它内部包含我们源程序中的中文字符串,只不过此时它己经由file.
* encoding格式转化为UNICODE格式了。当我们不加设置就编译时,相当于使用了参数:javac -encoding gbk XX.java,当然就会出现不兼容的情况。
*
* 解决办法是:应该使用-encoding参数指明编码方式:javac -encoding UTF-8 XX.java
*
* 获取系统默认编码: System.getProperty("file.encoding");
*
* @author zhengtian
*
* @date 2011-6-16 下午09:18:23
*/
@SuppressWarnings("all")
public class test {
public static void main(String[] args) {
try {
/**
* 测试一个汉字采用不同的编码格式占用几个字节
*/
String s = "我";
System.out.println("一个汉字用gbk编码后的所占的字节数:" + s.getBytes("GBK").length);
System.out.println("一个汉字用utf-8编码后的所占的字节数:" + s.getBytes("UTF-8").length);
System.out.println("一个汉字用ISO-8859-1编码后的所占的字节数:" + s.getBytes("ISO-8859-1").length);
/**
* 操作系统默认的编码格式与操作系统的区域语言有关系,下面为中文不同地区的操作系统默认的编码格式
* 标准和格式 JVM默认字符集
* 中文(中国) GBK
* 中文(新加坡) GBK
* 中文(香港特别行政区) MS950
* 中文(澳门特别行政区) MS950
* 中文(台湾) MS950
* JVM是从系统变量file.encoding中读取操作系统的默认编码的字符集,来设置JVM的字符集编码。
* 注意:如果在eclipse中认为设定过编码格式后,获取的值会根据当前文件设置的编码的变化而变化
*
*/
System.out.println(System.getProperty("file.encoding"));
/**
* 输出字符的长度,也就是输出char[]数组的长度
*/
System.out.println(s.length());
System.out.println(s.toCharArray().length);
System.out.println(s.getBytes("ISO-8859-1").length);
for (byte b : s.getBytes()) {
/**
* 将字符串转换为字节数组后,存储在内存中,此时的编码格式为unicode
*/
System.out.println(b);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}

}


[color=red][b]需要注意的是:[/b]
每种基本类型都有对应的包装类,且包装类有自己的编码格式,如下所示:
[table]
|主类型 |大小 |最小值 |最大值 |封装器类型
|boolean |- | - |- |Boolean
|Char |16-bit |Unicode 0 |Unicode 216- 1 |Character
|byte |8-bit | -128 | +127 |Byte
|Short |16-bit | -215 |+215?1 |Short
|Int |32-bit |-231 | +231?1 | Integer
|Long |64-bit |-263 |+263?1 |Long
|Float |32-bit |IEEE754 |IEEE754 | Float
|double |64-bit |IEEE754 |IEEE754 | Double
|Void |- |- |- |Void
[/table]
将字符型变量转换为数值型变量实际上有两种对应关系,在我们在第一部分所说的那种转换中,实际上是将其转换成对应的ASCII码,但是我们有时还需要另一种转换关系,例如,‘1’就是指的数值1,而不是其ASCII码,对于这种转换,我们可以使用Character的 getNumericValue(char ch)方法。
因此在上述的test类中如果将字符串1,先转换成字符,然后再转换成byte,然后在利用System.out.println(b);将其输出的时候,其实println函数接受的参数为int,之所以能够输出byte,是因为内部将byte已经转为int,所以输出1的值为对应的ascii码值。[/color]


下面是ASCII码对照表,原文地址为:[url]http://www.weste.net/tools/ASCII.asp[/url]

下表列出了字符集中的 0 - 127。

[table]
|代码|字符|代码|字符|代码|字符|代码|字符|
|0| | 32|[空格]| 64| @| 96| `
|1| | 33| !| 65| A| 97| a
|2| | 34| "| 66| B| 98| b
|3| | 35| #| 67| C| 99| c
|4| | 36| $| 68| D| 100| d
|5| | 37| %| 69| E| 101| e
|6| | 38| &| 70| F| 102| f
|7| | 39| '| 71| G| 103| g
|8| **| 40| (| 72| H| 104| h
|9| **| 41| )| 73| I| 105| i
|10| **| 42| *| 74| J| 106| j
|11| | 43| +| 75| K| 107| k
|12| | 44| ,| 76| L| 108| l
|13| **| 45| -| 77| M| 109| m
|14| | 46| .| 78| N| 110| n
|15| | 47| /| 79| O| 111| o
|16| | 48| 0| 80| P| 112| p
|17| | 49| 1| 81| Q| 113| q
|18| | 50| 2| 82| R| 114| r
|19| | 51| 3| 83| S| 115| s
|20| | 52| 4| 84| T| 116| t
|21| | 53| 5| 85| U| 117| u
|22| | 54| 6| 86| V| 118| v
|23| | 55| 7| 87| W| 119| w
|24| | 56| 8| 88| X| 120| x
|25| | 57| 9| 89| Y| 121| y
|26| | 58| :| 90| Z| 122| z
|27| | 59| ;| 91| [| 123| {
|28| | 60| <| 92| \| 124| [竖杠]
|29| | 61| =| 93| ]| 125| }
|30| -| 62| >| 94| ^| 126| ~
|31| | 63| ?| 95| _| 127|
[/table]
下表列出了字符集中的 128 - 255。
[table]
|代码| 字符| 代码| 字符| 代码| 字符| 代码| 字符
|128| €| 160| [空格] 192 À| 224| à
|129| | 161| ¡| 193| Á| 225| á
|130| ‚| 162| ¢| 194| Â| 226| â
|131| ƒ| 163| £| 195| Ã| 227| ã
|132| „| 164| ¤| 196| Ä| 228| ä
|133| …| 165| ¥| 197| Å| 229| å
|134| †| 166| ¦| 198| Æ| 230| æ
|135| ‡| 167| §| 199| Ç| 231| ç
|136| ˆ| 168| ¨| 200| È| 231| ç
|137| ‰| 169| ©| 201| É| 232| è
|138| Š| 170| ª| 202| Ê| 233| é
|139| ‹| 171| «| 203| Ë| 234| ê
|140| Œ| 172| ¬| 204| Ì| 235| ë
|141| | 173| | 205| Í| 236| ì
|142| Ž| 174| ®| 206| Î| 237| í
|143| | 175| ¯| 207| Ï| 238| î
|144| | 176| °| 208| Ð| 239| ï
|145| ‘| 177| ±| 209| Ñ| 240| ð
|146| ’| 178| ²| 210| Ò| 241| ñ
|147| “| 179| ³| 211| Ó| 242| ò
|148| ”| 180| ´| 212| Ô| 243| ó
|149| •| 181| µ| 213| Õ| 244| ô
|150| –| 182| ¶| 214| Ö| 245| õ
|151| —| 183| ·| 215| ×| 246| ö
|152| ˜| 184| ¸| 216| Ø| 247| ÷
|153| ™| 185| ¹| 217| Ù| 248| ø
|154| š| 186| º| 218| Ú| 249| ù
|155| ›| 187| »| 219| Û| 250| ú
|156| œ| 188| ¼| 220| Ü| 251| û
|157| | 189| ½| 221| Ý| 252| ü
|158| ž| 190| ¾| 222| Þ| 253| ý
|159| Ÿ| 191| ¿| 223| ß| 254| þ
[/table]
** 数值 8、9、10 和 13 可以分别转换为退格符、制表符、换行符和回车符。这些字符都没有图形表示,但是对于不同的应用程序,这些字符可能会影响文本的显示效果。

"空" 表示在当前平台上不支持的字符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值