Java基本的程序结构设计 字符类型

char类型

char是2个字节,和short一样。

char用单引号来表示。

char可以通过数字来表示,也可以通过字母来表示,也可以通过unicode编码单元来表示,特殊字符还可以通过\+字符来表示。如下:

  1. package com.zjf;
  2.  
  3. public class Test {
  4.  
  5.    public static void main(String[] args) {
  6.  
  7.       char c1 = 'A';
  8.       System.out.println(c1);
  9.       char c2 = 65;
  10.       System.out.println(c2);
  11.       char c3 = '\u0041';
  12.       System.out.println(c3);
  13.       char c4 = '\n';
  14.       System.out.println(c4);
  15.    }
  16. }

输出:

unicode编码

要想理解java 的char类型,必须要先了解unicode编码:

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。

Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。目前的Unicode字符分为17组编排,0x0000 至 0xFFFF,每组称为平面(Plane),而每平面拥有65536个码位,共1114112个。然而目前只用了少数平面。Unicode 用数字-0x000000 -0x10FFFF来映射这些字符,其实原来uncode编码是0x0000 至 0xFFFF,也就是说2个字节,16位,后来不够了,又加了8位,也就是1个字节,不知道为什么,加的这一个字节本来可以使用ox00-oxFF中变化的,也就是说256种,不知道为什么只用了17种。也就是0x00-0x10。不过这17中已经只用了很少一部分,如果要有256中,估计要把外星人语言加进来才行了。

Unicode是编码规范,UTF-8UTF-16UTF-32都是将数字转换到程序数据的编码方案。UTF是"UCS Transformation Format"的缩写,可以翻译成Unicode字符集转换格式,即怎样将Unicode定义的数字转换成程序数据。对于字符'字',Unicode编码使用数字23383,也就是0x5b57。不论是使用UTF-8UTF-16UTF-32哪种编码,最终都要生成数字23383,只是采用不同的规则。

 

UTF-8:

UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如 下:
Unicode编码(16进制) ║ UTF-8 字节流(二进制) 

  • 000000 - 00007F ║ 0xxxxxxx 
  • 000080 - 0007FF ║ 110xxxxx 10xxxxxx
  • 000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx 
  • 010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数 字。Unicode的最大码位0x10FFFF也只有21位。

对于字符'字',Unicode编码使用数字23383。使用UTF-8进行存储的时候,是oxE5AD97,三个字节。

它的二进制是:111001011010110110010111,可以按照上面的1110xxxx 10xxxxxx 10xxxxxx的规则进行拆分,拆分后把所有的x排成一行,就是:

0101101101010111

转换成10进制就是数字23383。

UTF-16

UTF-16编码以16位无符号整数为单位。我们把Unicode编码记作U。编码规则如下:
如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(为书写简 便,下文将16位无符号整数记作WORD)。 
如果U≥0x10000,我们先计算U'=U-0x10000,然后将U'写成二进制形 式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。 

对于字符字符'字',使用数字23383,也就是ox5b57。

也就是你说UTF-16的大部分字符都是2个字节(16位),生僻字可能是4个字节(2个16位)。

也就是说16位是一个单元,并不是说每个字符都是16位。

java中的char是采用的UTF-16编码来描述一个代码单元的。

UTF-16有Big Endian Little Endian两种,代表在内存中,是高地址在前还是低地址在前,java采用的是Big Endian。对于字符字符'字',在内存中是101101101010111。如果是Little Endian,应该是反过来。

 

字符串型

从概念上讲,java的字符型就是unicode字符序列。

不可变:

一旦定义了一个字符串,就没有方法修改它。java没有提供修改字符串的方法,对于C程序来说,字符串相当于是个数组,你可以改变任何一个下标的值。但是Java不可以。

如果要对java字符串修改下标,只能新建一个字符串,然后通过substring和拼接来实现,这样一定程度上效率很低。

但是java设计者认为字符串修改操作很少,对于字符串的操作,大多是比较,和合并等操作。所以java设计者将字符串设置为不可变,然后实现了共享。

没有字符串是可变的,就不能实现共享:

可以想象将字符串放在一个公共的池中,字符串变量指向池中的值,如果复制一个字符串,源字符串和复制的字符串共享相同的位置。

java设计者认为共享带来的高效率远远胜过可修改的字符串。

检测相等:

因为不可变,所以不能用==,只能用equals。

因为String是对象,对于对象的比较,==在java中是用来比较对象指向的堆中的位置是否相同。

虽然如此,如果我们用=比较对象指向的堆中的位置是否一样,也是不可以。

  1. package com.zjf;
  2.  
  3. public class Test {
  4.  
  5.    public static void main(String[] args) {
  6.  
  7.       String s1 = "zhang";
  8.       String s2 = "zhang";
  9.       System.out.println(s1 == s2);
  10.    }
  11. }

结果为true。对我们来说,并没有做s1=s2的操作,结果却是true,这不是我们想要的结果。虽然说Sting a = b;那么用a == b是可以的,但是如果没有a=b,也可以a==b,这样对我们来说,会有不可预知的结果。

那么如果我们想用=来比较两个字符串的内容是否一致呢?也不行。

  1. package com.zjf;
  2.  
  3. public class Test {
  4.  
  5.    public static void main(String[] args) {
  6.  
  7.       String s1 = "zhang";
  8.       String s2 = "zhangjianfeng".substring(0, 5);
  9.       System.out.println(s1);
  10.       System.out.println(s2);
  11.       System.out.println(s1 == s2);
  12.    }
  13. }

结果为:

zhang

zhang

false

 

两个字符串都是zhang,使用=却没有比较成功。

原因是因为java虚拟机只对字符串常量进行共享,对于+和substring等操作产生的结果,是不会共享的。

使用==进行字符串比较,程序会出现bug,而且这种bug在一定程度上是随机的。不要使用。

代码点和代码单元

Java字符串由char序列组成,char是采用UTF-16编码表示Unicod代码点的代码单元。

代码点就是我们生活中面对的一个字,因为UTF-16的存储方式,对于某些代码点需要32位,也就是说两个代码单元来存储,在java中,一个char是一个代码单元。

这样就会造成一些误解。

首先,length方法返回的是代码单元的数量。而不是代码点的数量。

其次,charAt方法获取的是代码单元,不是代码点。如果想获取代码点,string提供的有codepoint方法,

如下代码:

作者说,避免使用char,因为这太低级了。其实,虽然很少见到这些特殊字符,使用char的场景还是要慎重。

构建字符串:

使用较短的字符串构建字符串:

  • StringBuilder
  • StringBuffer 线程安全

包引入问题

像Sting,Integer,StringBuilder这种包,位于java.lang目录下,不需要import引入,也能识别。

posted on 2017-06-17 19:16  张小贱1987  阅读(295)  评论(0编辑  收藏  举报

导航