Java基础:编码的相关解释

本文深入探讨了GBK与UTF-8编码之间的转换原理及乱码产生的原因,并通过实例演示了如何正确处理不同编码下的字符串。

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

简单的编码介绍:
字符串 --> 字节数组:编码
字节数组 --> 字符串:解码

GBK编码: 汉字用两个字节表示,
第一种情况:
第一个字节是负数,第二字节负数
第二种情况:
第一个字节是负数,第二字节正数 eg:琲

UTF-8编码:汉字的编码都是 用 负数 表示
UTF-8会动态分配字节数,可能是 一个字节,两个字节,三个字节。
相关格式:低八位
在这里插入图片描述
上面这张图,可能大家会看不懂,那么我就在这里解释以下:
用UTF-8编码时:
对于汉字而言,至少用二个字节表示。
总之就是,

当用一个字节时,
字节一 的前一位是 0

当用二个字节时
字节一 的前三位是 110
字节二的前两位是 10

当用三个字节时
字节一 的前三位是 1110
字节二的前两位是 10
字节三的前两位是 10

相关代码如下:

import java.io.UnsupportedEncodingException;

public class Encode {

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

		/*
			你好的UTF-8
			11100100
			10111101
			10100000
			11100101
			10100101
			10111101
			
			你好的GBK
			11000100
			11100011
			10111010
			11000011

		 */		
		String str = "你好";
		byte[] buf = null;
		buf = str.getBytes("utf-8");
		printByte(buf);
	}
	private static void printByte(byte[] buf) {
		// TODO Auto-generated method stub
		
		for(byte b : buf) {
			System.out.println( Integer.toBinaryString(b & 255) );
		}
		System.out.println();
	}
}

我们可以看到
你好的UTF-8
11100100
10111101
10100000
11100101
10100101
10111101
满足上面的表达模式

你好的GBK
11000100
11100011
10111010
11000011
GBK不满足

**iso8859-1:**无法编码汉字
这是欧洲那边的编码。

乱码时:
如果你编错了,解不出来。
如果编对了,解错了,有可能有救。
现在我们验证 如果编对了,解错了,有可能有救。

import java.io.UnsupportedEncodingException;

public class BianMa {

	public static void main(String[] args) throws UnsupportedEncodingException {
		// TODO Auto-generated method stub
	
		String str = "你好";
		
		byte[] buf = null;	
		buf = str.getBytes("GBK");		
		printByte(buf);
		
		String s = new String(buf,"iso8859-1");
		
		System.out.println(s);
		
		buf = s.getBytes("iso8859-1");
		printByte(buf);
		System.out.println(new String(buf,"GBK"));
		
	}

	private static void printByte(byte[] buf) {
		// TODO Auto-generated method stub
		
		for(byte b : buf) {
			System.out.println( Integer.toBinaryString(b & 255) );
		}
		System.out.println();
	}
}

输出结果是:
在这里插入图片描述
虽然出现了乱码,但是任然可以解析出来。

下面我们在来看看另一个例子:

import java.io.UnsupportedEncodingException;

public class BianMa {

	public static void main(String[] args) throws UnsupportedEncodingException {
		// TODO Auto-generated method stub
	
		String str = "你好";
		
		byte[] buf = null;	
		buf = str.getBytes("GBK");		
		printByte(buf);
		
		String s = new String(buf,"UTF-8");
		
		System.out.println(s);
		
		buf = s.getBytes("UTF-8");
		printByte(buf);
		System.out.println(new String(buf,"GBK"));
		
	}

	private static void printByte(byte[] buf) {
		// TODO Auto-generated method stub
		
		for(byte b : buf) {
			System.out.println( Integer.toBinaryString(b & 255) );
		}
		System.out.println();
	}

}

输出结果:
在这里插入图片描述
我们可以发现,这次我们使用跟上面相似的思路去解决上面的问题,发现不起任何作用,下面我来说说这是为什么?
原因如下:
愿因一:
当“你好”用GBK编码好的二进制数,然后用UTF-8去编码时,发现这个不符合,自己的编码规则,于是,就用其他替换了,所以出现了乱码,
愿因二:
GBK用两个字节表示汉字,而UTF-8表示汉字至少两个字节。

当我们换成“谢谢”时是可以成功的。
在这里插入图片描述
原因:这时的GBK编码出来的二进制,符合UTF-8,所以是成功的。

当我们换成“联通”这两个字时:
在这里插入图片描述
发现GBK编码后的二进制是符合UTF-8的规则的,但还是没有解码成功,这是因为UTF-8进一步解码后,发现没有找到对应的字符,所以用其他代替,从而产生乱码。

相关测试:

在java中,字符串“abcd”与字符串“ab你好”的长度是一样,都是四个字符。
但对应的字节数不同,一个汉字占两个字节。
定义一个方法,按照最大的字节数来取子串。
如:对于“ab你好琲ab琲”,如果取三个字节,那么子串就是ab与“你”字的半个,
那么半个就要舍弃。如果去四个字节就是“ab你”,取五个字节还是“ab你”.

import java.io.IOException;

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

		String str = "ab你好琲ab琲";
		
		System.out.println("GBK");
		for(int i=0;i<str.getBytes("GBK").length;i++)		
			System.out.println("截取"+(i+1)+"个字节: "+cutStringByGBK(str,(i+1)));
		System.out.println("UTF-8");
		for(int i=0;i<str.getBytes("UTF-8").length;i++)		
			System.out.println("截取"+(i+1)+"个字节: "+cutStringByUTF8(str,(i+1)));		
	}

	private static String cutStringByUTF8(String str, int len) throws IOException {		
		byte[] buf = str.getBytes("UTF-8");
		int count = 0;
		for(int x = len -1 ;x>=0;x--) {
			
			if(buf[x] < 0)
				count++;
			if(buf[x] > 0)
				break;		
		}		
		if(count % 3 == 0)
			return new String(buf,0,len,"UTF-8");
		else if(count % 3 == 1)
			return new String(buf,0,len-1,"UTF-8");
		else
			return new String(buf,0,len-2,"UTF-8");
	}
	private static String cutStringByGBK(String str,int len) throws IOException {

		byte[] buf = str.getBytes("GBK");
		int count = 0;
		for(int x = len -1 ;x>=0;x--) {
			
			if(buf[x] < 0)
				count++;
			if(buf[x] > 0)
				break;		
		}		
		if(count % 2 == 0)
			return new String(buf,0,len);
		else
			return new String(buf,0,len-1);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值