- 浏览: 375595 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
surpassno:
很不错,学习了
一个对象占用多少字节? -
ysyzww:
你这么牛逼,你父母知道吗
maven使用技巧 -
妖人不要跑:
JDK中反序列化对象的过程(ObjectInputStream#readObject) -
lanhz:
谢楼主,构建成功了
Mac OSX 10.9 上build openjdk8和openjdk7 -
zqb666kkk:
通过了吗 ?????
淘宝北京专场java面试题(2011-12-31)
首先要了解,java里边,String是以char数组的形式存储的,而char字符是16 bits的Unicode字符。
1、当执行new String("i am a 字符ゅ").getBytes()的时候,是把内存中的char数组,转化成Charset.defaultCharset()这种字符集的字符数组,而这种字符集是提取的系统属性里边"file.encoding"属性的值,参见Charset的源代码:
(我本机就是utf-8)然后会创建一个StringEncoder而StringEncoder会创建一个CharsetEncoder:UTF-8$Encoder,创建UTF-8$Encoder时在调到CharsetEncoder的构造函数时会传入一个new byte[]{(byte)'?'}用来在解析到不能解析的字符的时候,把不能解析的字符替换成'?'(63,0x3F)(当然utf-8编码格式是可以表示java的char可以表示的所有字符的,这个在后边讲到iso-8859-1的时候会用到)。接下来就用StringEncoder#encode(),最终还是调用CharsetEncoder-UTF_8$Encoder来encode。而真正一个一个char解析的地方是UTF_8$Encoder#encodeArrayLoop(CharBuffer src, ByteBuffer dst)方法中:
以上代码是判断当前char字符的int值的范围,然后确定是需要一个、两个或是三个字节,这个可以根据utf-8编码规则来确定:
UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
即小于1000 0000(0x80)需要一个字节(0xxxxxxx),小于0000 1000 0000 0000(0x200)需要两个字节(110xxxxx 10yyyyyy),其余最多占满16位的需要三个字节(1110xxxx 10yyyyyy 10zzzzzz)。以上代码根据这些规则进行了移位和按位操作,把两个字节的unicode字符编码成了utf-8格式的字节数组,这个时候,占用两个字节的字符不会丢失信息。
2、当执行new String("i am a 字符ゅ").getBytes("iso-8859-1")的时候,StringEncoder也会创建一个CharsetEncoder:ISO_8859_1$Encoder,创建的时候已然会传入一个new byte[]{(byte)'?'}用来在解析到不能解析的字符的时候,把不能解析的字符替换成'?'(63,0x3F),来看看ISO_8859_1$Enoder的encodeArrayLoop方法:
这里可以看到如果遇到unicode值大于'\u00FF'(1111 1111, 0xFF,即一个字节)的字符,全部当做不可映射字符(unmappable-input),在CharsetEncoder#encode()调用过encodeLoop()后替换不可映射的字符为replacement,即我们传入的new byte[]{(byte)'?'}
这样就是为什么我们在运行如下代码的时候
结果是:This is a ??? String!
当然这也就是涉及到了把byte[]按照某种编码格式解析成String(java的unicode字符集合char[])的问题,本质跟上边原理是相反的。
3、new String("i am a 字符ゅ").getBytes("XXX")按照如上的过程,再根据XXX编码规则(不知为何参数类型叫做Charset),就可以解析出来了。
1、当执行new String("i am a 字符ゅ").getBytes()的时候,是把内存中的char数组,转化成Charset.defaultCharset()这种字符集的字符数组,而这种字符集是提取的系统属性里边"file.encoding"属性的值,参见Charset的源代码:
public static Charset defaultCharset() { if (defaultCharset == null) { synchronized (Charset.class) { java.security.PrivilegedAction pa = new GetPropertyAction("file.encoding"); String csn = (String)AccessController.doPrivileged(pa); Charset cs = lookup(csn); if (cs != null) defaultCharset = cs; else defaultCharset = forName("UTF-8"); } } return defaultCharset; }
(我本机就是utf-8)然后会创建一个StringEncoder而StringEncoder会创建一个CharsetEncoder:UTF-8$Encoder,创建UTF-8$Encoder时在调到CharsetEncoder的构造函数时会传入一个new byte[]{(byte)'?'}用来在解析到不能解析的字符的时候,把不能解析的字符替换成'?'(63,0x3F)(当然utf-8编码格式是可以表示java的char可以表示的所有字符的,这个在后边讲到iso-8859-1的时候会用到)。接下来就用StringEncoder#encode(),最终还是调用CharsetEncoder-UTF_8$Encoder来encode。而真正一个一个char解析的地方是UTF_8$Encoder#encodeArrayLoop(CharBuffer src, ByteBuffer dst)方法中:
if (c < 0x80) { // Have at most seven bits if (dp >= dl) return overflow(src, sp, dst, dp); da[dp++] = (byte) c; } else if (c < 0x800) { // 2 bytes, 11 bits if (dl - dp < 2) return overflow(src, sp, dst, dp); da[dp++] = (byte) (0xc0 | ((c >> 06))); da[dp++] = (byte) (0x80 | (c & 0x3f)); } else if (Surrogate.is(c)) { // Have a surrogate pair if (sgp == null) sgp = new Surrogate.Parser(); int uc = sgp.parse((char) c, sa, sp, sl); if (uc < 0) { updatePositions(src, sp, dst, dp); return sgp.error(); } if (dl - dp < 4) return overflow(src, sp, dst, dp); da[dp++] = (byte) (0xf0 | ((uc >> 18))); da[dp++] = (byte) (0x80 | ((uc >> 12) & 0x3f)); da[dp++] = (byte) (0x80 | ((uc >> 06) & 0x3f)); da[dp++] = (byte) (0x80 | (uc & 0x3f)); sp++; // 2 chars } else { // 3 bytes, 16 bits if (dl - dp < 3) return overflow(src, sp, dst, dp); da[dp++] = (byte) (0xe0 | ((c >> 12))); da[dp++] = (byte) (0x80 | ((c >> 06) & 0x3f)); da[dp++] = (byte) (0x80 | (c & 0x3f)); } sp++;
以上代码是判断当前char字符的int值的范围,然后确定是需要一个、两个或是三个字节,这个可以根据utf-8编码规则来确定:
UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
即小于1000 0000(0x80)需要一个字节(0xxxxxxx),小于0000 1000 0000 0000(0x200)需要两个字节(110xxxxx 10yyyyyy),其余最多占满16位的需要三个字节(1110xxxx 10yyyyyy 10zzzzzz)。以上代码根据这些规则进行了移位和按位操作,把两个字节的unicode字符编码成了utf-8格式的字节数组,这个时候,占用两个字节的字符不会丢失信息。
2、当执行new String("i am a 字符ゅ").getBytes("iso-8859-1")的时候,StringEncoder也会创建一个CharsetEncoder:ISO_8859_1$Encoder,创建的时候已然会传入一个new byte[]{(byte)'?'}用来在解析到不能解析的字符的时候,把不能解析的字符替换成'?'(63,0x3F),来看看ISO_8859_1$Enoder的encodeArrayLoop方法:
while (sp < sl) { char c = sa[sp]; if (c <= '\u00FF') { if (dp >= dl) return CoderResult.OVERFLOW; da[dp++] = (byte) c; sp++; continue; } if (sgp.parse(c, sa, sp, sl) < 0) return sgp.error(); return sgp.unmappableResult(); }
这里可以看到如果遇到unicode值大于'\u00FF'(1111 1111, 0xFF,即一个字节)的字符,全部当做不可映射字符(unmappable-input),在CharsetEncoder#encode()调用过encodeLoop()后替换不可映射的字符为replacement,即我们传入的new byte[]{(byte)'?'}
if (action == CodingErrorAction.REPLACE) { if (out.remaining() < replacement.length) return CoderResult.OVERFLOW; out.put(replacement); }
这样就是为什么我们在运行如下代码的时候
new String("This is a 中文的 String!".getBytes("iso-8859-1"),"utf-8").toString();
结果是:This is a ??? String!
当然这也就是涉及到了把byte[]按照某种编码格式解析成String(java的unicode字符集合char[])的问题,本质跟上边原理是相反的。
3、new String("i am a 字符ゅ").getBytes("XXX")按照如上的过程,再根据XXX编码规则(不知为何参数类型叫做Charset),就可以解析出来了。
发表评论
-
springboot程序错误排查
2016-12-12 10:37 12072.0.0版本的springboot程序,在eclipse中 ... -
debug Java进程的debug参数
2016-08-25 21:13 1616前几天给java应用设置debug参数,发现有两个参数:- ... -
Java NIO Socket通信需要考虑的问题(持续更新)
2016-04-27 19:57 281. NIO 多个线程同时往 ... -
Fastjson反序列化泛型类型时候的一个问题
2015-01-21 15:34 32298import static org.junit.Asser ... -
HTTP 50X code实例
2014-10-31 19:24 01、500 Internal Server Err ... -
一次Direct buffer memory引发的OutOfMemoryError问题排查
2014-10-28 17:22 0留坑位 -
netty3.6.2中写数据的过程,以及写数据写不出去后怎么处理
2014-08-11 17:37 3139netty写数据的时候,会先放到一个缓存队 ... -
在用Netty 3.6.2发数据,发现内核缓冲区满的时候.....
2014-08-11 16:06 2218用nettys收发网络数据的时候,一般不会注 ... -
JDK中反序列化对象的过程(ObjectInputStream#readObject)
2014-06-10 20:10 4179此处,对象描述信息即ObjectStre ... -
Mac OSX 10.9 上build openjdk8和openjdk7
2014-03-29 18:29 14295先分享下自己build出来的fastdeb ... -
内存充足情况下应用一直CMS GC的问题分析
2014-03-26 22:39 0前几天日常上线发布后,收到大量的CMS GC ... -
查看java对象在内存中的布局
2014-03-20 22:39 13072接着上篇《一个对象占用多少字节?》中遇到的 ... -
一个对象占用多少字节?
2014-03-18 21:56 35132老早之前写过一篇博客,是关于一个Integ ... -
maven使用技巧
2014-03-18 15:34 39461、pom打jar包的时候设置MANIFEST.MF的ke ... -
cpu字长、操作系统字长和jvm中各数据类型占用的字节数关系
2014-03-16 02:05 4722cpu字长是指cpu同时参与运算的二进制位 ... -
比反射更高效的修改字段值的方法
2014-03-13 20:49 1383开发过程中,不少情况下都会遇到需要通过反射 ... -
cache line对内存访问的影响
2014-03-12 20:48 1382cache line对内存访问的影响很早就 ... -
Java Web应用Web层异步化应该考虑的问题
2014-01-25 17:45 5834之前做了一 ... -
jvisualvm jmx方式远程监控tomcat
2013-10-10 20:38 19851、如果用jmx方式监控,不需运行服务器上的jstatd进 ... -
一些数据切分、缓存、rpc框架、nosql方案资料
2013-10-07 23:48 14751、数据切分 ...
相关推荐
ehlo xxx auth login 用户名 密码 mail from:<aaa@sohu.com> rcpt to:<bbb@sina.com> data from:<aaa@sohu.com> to:<bbb@sina.com> subject:test xxxxxx . quit ``` #### POP3接收协议 POP3协议主要用于从邮件...
private static final String twoUrlString = "http://xxx.action"; public String getSessionId() { String sessionId = ""; try { URL url = new URL(oneUrlString); hc = (HttpURLConnection) ...
Class c = XXX.class; InputStream is = c.getResourceAsStream("aa.txt"); try { int len = is.available(); byte[] bs = new byte[len]; // ... } catch (IOException e) { e.printStackTrace(); } } }...
`getBytes(String charsetName)` **功能描述**:按照指定的字符集获取当前字符串的字节表示。 **示例**: ```scala val str = "Hello" println(str.getBytes("UTF-8")) // 输出字节数组 ``` #### 14. `getChars...
xxx.dtoptname=中文参数 String strPtname = request.getParameter("ptname"); strPtname = new String(strPtname.getBytes("ISO-8859-1"), "UTF-8"); 方法三:使用 JSP页的 charset 属性 这种方法是通过在 JSP 页...
if (e.Url.ToString().ToLower().IndexOf("xxx.htm") > 0) //判断是否为登录页面 { HtmlDocument doc = webBrowser1.Document; for (int i = 0; i < doc.All.Count; i++) { if (doc.All[i].TagName.ToUpper() ...
String str = "name=xxx&age=12"; OutputStream os = conn.getOutputStream(); os.write(str.getBytes("UTF-8")); os.flush(); // 获取响应码 if (conn.getResponseCode() == 200) { // 读取输入流 ...
4. **静态包含与动态包含**:`<%@include file="xxx.jsp"%>`是静态包含,编译时合并到当前JSP页面;`<jsp:include>`是动态包含,运行时根据请求动态加载页面。 5. **List与Map的区别**:List是有序集合,元素可以...
File file1=new File("d:\\xxx\\yyy\\zzz"); file1.mkdirs(); File file2=new File(file1,"1.txt"); file2.createNewFile(); String s="I like java."; byte[] b=s.getBytes(); FileOutputStream out=new...
public static void main(String[] args) { Properties properties = new Properties(); properties.put(PropertyKeyConst.ProducerId, "XXX"); // Producer ID properties.put(PropertyKeyConst.AccessKey, ...
Message msg = new Message("TopicTestMQ", "TagA", "Hello MQ".getBytes()); producer.send(msg); } producer.shutdown(); } } ``` 在实际应用中,可以根据业务需求选择合适的发送方式。同步发送保证消息发送...
- 使用`new String("XXX".getBytes("ISO-8859-1"), "UTF-8")`解码。其中,“XXX”是前台传递过来的含有中文的参数值,“UTF-8”为指定的字符集编码,可根据实际需求进行调整。 **注意事项**: - 该方案中,后端...
byte b[] = s.getBytes(); FileOutputStream file = new FileOutputStream("test.txt", true); file.write(b); file.close(); ``` - **结果分析**:每次运行上述代码都会将字符串“ABCDE”追加到文件`test.txt`的...
str = new String(str.getBytes("ISO-8859-1"), "UTF-8"); ``` #### 二、数据库中的乱码处理 **1. 数据库字符集配置** - 如果数据库中存储的中文字符出现乱码,首先需要检查数据库的字符集设置是否正确。 - ...
题目问的是:当某一线程正处于休眠状态,而另一个线程用`Thread`类中的`interrupt()`方法中断它时,抛出的异常类型是什么? - 正确答案是:**C) InterruptedException**。 ### 2. 文件操作与路径创建 **知识点概述...
使用BlobByteArrayType字段类型后,为什么我们就可以象一般的字段类型一样操作Blob字段呢?可以确定的一点是:BlobByteArrayType不可能逾越Blob天生的操作方式,原来是BlobByteArrayType数据类型本身具体数据访问...
<%=new String(request.getParameter("chineseVar").getBytes("iso-8859-1"), "UTF-8")%> ``` 这段代码中,首先使用`request.getParameter()`方法获取名为`chineseVar`的URL参数。然后,使用`getBytes("iso-8859-1...
3. **状态码(Status Code)**:服务器返回的状态码,用于指示请求是否成功或者出现了什么问题。 #### 三、实现HTTP POST请求的方法 在Java中,可以通过多种方式实现HTTP POST请求,包括使用`HttpURLConnection`和`...
String key = new String(request.getParameter("key").getBytes("ISO-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ``` ### 进一步优化 除了以上提到的解决方案外...
String value = config.getInitParameter("xxx"); // 输出到响应流 response.getOutputStream().write(value.getBytes()); // 获取所有初始化参数的名字 Enumeration<String> e = config....