实在没什么自信觉得自己能把这个Character能写好,让我和大家都能对她有个透彻的认识,因为我觉得更需要一个专题来说明她,但我还是决定尝试写一点东西。

因为API带来的困惑,所以在此之前,请先阅读几个术语:

Unicode:Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码
UnicodeData:指定了各种属性,其中包括每个已定义 Unicode 代码点或字符范围的名称和常规类别
BasicMultilingual Plane(BMP) : 从 U+0000 到 U+FFFF 的字符集
代 码 点: char 的int值
高代理项:(\uD800-\uDBFF)
低代理项:(\uDC00-\uDFFF)
增补字符: 代码点大于 U+FFFF 的字符称为增补字符
ASCII码:可以用unicode表示,但unicode会占两个字节
UTF-8:UTF-8是UNICODE的一种变长字符编码又称万国码(用1到6个字节编码UNICODE字符)

不用着急完全明白上面的表述,在我后面的阐述中会把这些连贯起来,自然就明白了。

API注解中有句话: Java 2 平台在 char 数组以及 String 和 StringBuffer 类中使用 UTF-16 表示形式。在这种表现形式中,增补字符表示为一对 char 值,第一个值取自高代理项 范围,即 (\uD800-\uDBFF),第二个值取自低代理项 范围,即 (\uDC00-\uDFFF)。 

那就让我们从这句话开始。首先,读懂这句话,表达的意思:
1. char是占2个字节,而char数组以及其衍生物(String等)用到一对char(4个字节);
2. 高代理项指的是一对char的高位,低代理项即第二个char,他们叫做增补字符。
3. Unicode 代码点 用于作为 UTF-16 编码的代码单元的 16 位 char 值,char恒占2个字节
 

对于增补字符我再说下:
1.(源自:维基百科)Unicode在范围D800-DFFF中不存在任何字符,基本多文种平面中约定了这个范围用于UTF-16扩展标识辅助平面(两个UTF-16表示一个辅助平面字符)。当然,任何编码都是可以被转换到这个范围,但在unicode中他们并不代表任何合法的值。
2.二进制中增补字符总是以“110”开头,以至于在jdk中可能作为一种判定增补字符的方式。

 

--你可以从这里开始阅读
先说下基础:
char的包装类:Character
char的表现方式:
1. char c1 = ‘c’
2. char c2 = 0(-0),c3 = 65535,c4 = Short.MAX_VALUE*2+1;
3. char c5 = ‘\uFFFF’
(注:c5的表现方式,以‘\u’开头是16进制的表现方式,能且只能有4个字符,而大于c5的值为增补字符。)
char占位:2个字节(16位)

 

简单介绍几个方法,不过看明白我之前的东西,会更容易理解这些方法。

method:charCount(int codePoint) |static|int

确定表示指定字符(Unicode 代码点)所需的 char 值的数量。如果指定字符等于或大于 0x10000,则该方法返回的值为 2

 

method:digit(int codePoint, int radix) |staic|int

返回使用指定基数的字符 ch 的数值。稍微描述的说:

1. isDigit(codePoint) 为true,并且codePoint的Unicode十进制数<指定的基数(radix)

2. 字母范围的话,例如'A':ch - 'A' + 10

3. 2<=radix<=36

我先给个例子:

int z=46; 
while(z++<120) 
{ 
  print(z); 
  println(Character.digit(z, 16));
 } 
//以后默认声明z 
//print = System.out.print

out: 发现打印了0-9,a-f,A-F的数值 字符的数值。
OK,那你尝试着把16进制改成36进制试试.
那我们来更通俗的解释这个方法就是: codePoint代表的是字符unicode码int值,通过raidx转换,将返回此codePoint在该进制下代表的数值。

 

举例:

char c = '0'; 
int ci = c ;//ci=48
int ca = ’a’; // ca = 97>
println(Character.digit(48,11));// 0
println(Character.digit(97,11));// 10

 由此推理:在36进制情况下,a-z是不是都代表数字呢?还记得 基本类型-int 篇中提到Integer.parseInt("Kona", 27)吗?这里可以作为思考,后面讲forDigit会揭晓。还有个digit(char,int),这个方法直接传入char值,不支持增补码。

举例:

char c = '\u0061';//a的10进制为97,在16进制a代表10
//c = 'a'; //也能得到
println(Character.digit(c,16));// 10

 

method:forDigit(int digit, int radix) |static|int

确定使用指定基数的特定数字的字符表示形式。
这个方法与digit相反
见例子:

int i = 36; 
 while(z++<i){//init z = 0 ; 
  print("--"+(int)
  Character.forDigit(z-1, i));
  println(Character.forDigit(z-1, i)); 
 }

out : 0-9,a-z 在36进制之下, a-z代表了10-35的值,Integer.parseInt("Kona", 27)的问题也就不是问题了。

 

method:getNumericValue(char ch) static|int

返回指定的 Unicode 字符表示的 int 值。

 z = 0x007A;
 while(z++<0XFFFF) 
 { int i = Character.getNumericValue(z);
   if(i!=-1)println(Integer.toHexString(z)+"--";+i);
 }

//改造一下:
 z = 0x0000;
 while(z++<0XFFFF) {
  int i = Character.getNumericValue(z);
  if(i==10) {
   char c = (char)z;
   print(c);
   println(Integer.toHexString(z)+"--"+i);
 }
 }

你能看到你所有感兴趣的字符了。 

method:isUpperCase(char ch) |static|boolean

确定指定字符是否为大写字母
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
'\u00C0' '\u00C1' '\u00C2' '\u00C3' '\u00C4' '\u00C5' '\u00C6' '\u00C7' '\u00C8' '\u00C9' '\u00CA' '\u00CB' '\u00CC' '\u00CD' '\u00CE' '\u00CF' '\u00D0' '\u00D1' '\u00D2' '\u00D3' '\u00D4' '\u00D5' '\u00D6' '\u00D8' '\u00D9' '\u00DA' '\u00DB' '\u00DC' '\u00DD' '\u00DE'

method:isLowerCase(char ch) |static|boolean

确定指定字符(Unicode 代码点)是否为小写字母。

method:isTitleCase(int ch) |static|boolean

确定指定字符是否为首字母大写字符。

之前很可能质疑,isUpperCase、isLowerCase需要说明吗?目的就是为了这个方法。

看API的描述:

1. 如果通过 Character.getType(ch) 提供的字符的常规类别类型为 TITLECASE_LETTER,则字符为首字母大写字符。

  验证起来很简单:

  z = 0x0000;
  while(z++<0XFFFF) {
     int i = Character.getType(z);   
     if(i==Character.TITLECASE_LETTER) {
   	print(Integer.toHexString(z)); 
        print((char)z); 
       println(Character.isTitleCase(z));   
   }
  }

2. 一些字符看似成对的 Latin 字母。例如,有一个看起来像“LJ”的大写字母和一个看起来像“lj”的对应小写字母。第三种形式看起来像“Lj”,这是呈现首字母大写的小写单词时使用的适当形式,比如用于书籍的标题。

但是第2个描述带来了极强的困惑。
为了理解这个,搜集了不少资料。发现其实也很简单。
见实例:http://www.fileformat.info/info/unicode/char/1c5/index.htm

以此Dz为例。

看说明:

Upper case U+01C4
Lower case U+01C6
Title case U+01C5
如果按照这个unicode说明,那么
Character.isLowerCase('\u01C6')应该是true

而且 Integer.toHexString(Character.toTitleCase('\u01C6')) out: 1c5

果然,除了我们认知的大写小写外,其实还有更多表达upper/lower。就像小时候盐就是吃了,学了化学才知道完全不是那么回事。

这也就验证了jdk在进行字符比较时,出现先转换成大写,再转换成小写进行比较时有意义的。

 

isSpaceChar(char ch)

确定指定字符是否为 Unicode 空白字符。当且仅当根据 Unicode 标准将字符指定为空白字符时,才认为字符是一个空白字符。如果字符的常规类别的类型为以下类型中的任意一种,则该方法返回 true:

  • SPACE_SEPARATOR
  • LINE_SEPARATOR
  • PARAGRAPH_SEPARATOR

 

isWhitespace(char ch)

确定指定字符依据 Java 标准是否为空白字符。

  • 它是一个 Unicode 空白字符(SPACE_SEPARATOR,LINE_SEPARATOR 或 PARAGRAPH_SEPARATOR),但不是一个不间断空格('\u00A0'、'\u2007' 和 '\u202F')。
  • '\u0009',水平制表符。
  • '\u000A',换行。
  • '\u000B',纵向制表符。
  • '\u000C',换页。
  • '\u000D',回车。
  • '\u001C',文件分隔符。
  • '\u001D',组分隔符。
  • '\u001E',记录分隔符。
  • '\u001F',单元分隔符。
    z = 0x0000
    while(z++&lt;0XFFFF) {
    int i = Character.getType(z);
    if(i==Character.SPACE_SEPARATOR) {
      print("@SPACE: "+Integer.toHexString(z));
      println(Character.isWhitespace(z));
     //println(Character.isSpaceChar(z));
    }else
    if(i==Character.LINE_SEPARATOR)
      println("@LINE: "+Integer.toHexString(z));
    else if(i==Character.PARAGRAPH_SEPARATOR)
      println("@PARAGRAPH: "+Integer.toHexString(z));
} println(Character.isWhitespace('\u0009'));

可以验证 '\u00A0'、'\u2007' 和 '\u202F' 是否如API所描述。
注:我习惯在自己打印的说明参数前加"@",后面加":", 例如:@LINE:

 

method:hashCode() |int

得到的是char的代码点。 唯一。

 

method:equal() |void

比较的是value.

这里说明一下。
Character cob1 = 'c';
char va = 99;
cob1.equal(va); //out :true
cob1.equal(99); //out : false 因为99是整型

 

method:compareTo(Character anotherCharacter) | int

根据数字比较两个 Character 对象。返回:

(this.value – anotherCharacter.value)
好比 cob1.compareTo('0') = 99-48 = 51
而cob1.compareTo((char)0) = 99 

不知不觉还是写了很多,但其实并没有把编码问题,以及和String的交互讲明白。争取在后面的String等部分能时候讲明白。

注:对于打印会出现?无法显示的问题,我争取在后面补上关于font.properties的说明。

 

依然做个小结:

1. 我们了解了ascii码,unicode,UTF-8,UTF-16的一些知识。char知识unicode表示的一部分。
2. 在36进制下,a-z代表10-35, 11进制下只有a被代表。
3. unicode代码点是唯一的,可以用作hashcode
4. 以字符a为例。 a的unicode代码点为97 ,但是a在11-36基数上代表10.
5. 尝试着习惯unicode 16进制的表达方式。正如 a 等价 97 等价 ‘\u0061’