首页 > 编程语言 >《java解惑》--字符串之谜

《java解惑》--字符串之谜

时间:2023-11-09 12:02:25浏览次数:47  
标签:字符 java String 程序 length 字符串 解惑 main 之谜


1.字符拼接:

问题:

程序员几乎在每天编程中都遇到和处理字符串拼接的问题,但是是否对其了解的足够深入,且看下面的程序:

public static void main(String[] args) {  
"H" + "a");  
'H' + 'a');  
    }


很多人觉得输出结果应是:HaHa,但是真实的程序运行结果是:Ha169。

原因:

程序第一个输出是两个字符串拼接,所以结果毫无疑问。

第二个输出是字符相加而非字符串拼接,因此会使用字符的ASCII码(H是72,a是97)进行相加然后将char类型的结果进行数据类型拓宽为int类型输出,因此输出结果是169.

结论:

很多人认为字符串和字符是一样的,其实这是个错误认识,字符char是个无符号的16位整数,而字符串是将一系列字符以unicode方法处理。

因此,对于字符拼接可以使用下面的方法:

方法一:

使用StringBuffer,StringBuilder等的append方法拼接字符,代码如下:



StringBuffer sb = new StringBuffer();  
sb.append('H');  
sb.append('a');  
System.out.println(sb);


方法二:

在字符拼接中拼接中以一个空的字符串开头,代码如下:



System.out.println("" + 'H' + 'a');


方法三:

使用格式化的打印输出printf,代码如下:



System.out.printf("%c%c", 'H', 'a');


方法四:

使用字符串API-String.valueOf(char c),代码如下:


System.out.printf(String.valueOf('H') + String.valueOf('a'));


2.字符数组打印:

问题:

很多人使用下面的小程序打印字符数组:



public static void main(String[] args) {  
"ABC";  
char[] numbers = {'1', '2', '3'};  
" easy as " + numbers);  
    }


本来期望程序输出结果为:ABC easy as 123,但是真实程序运行结果类似为:ABC easy as [C@1db05b2。

原因:

尽管字符是一个16位的无符号整数类型,但是它通常表示的是字符而不是整数,因此很多程序对其进行了特殊处理,输出其Unicode字符而非其ASCII码,System.out.println,String.valueOf和StringBuffer.append会将字符数组中所包含的所有字符打印输出,而字符串链接操作符+没有在这些方法中定义,因此会现将要拼接的两个操作数转换为字符串(调用toString方法),然后执行字符串拼接,因此字符数组在没有重写toString方法时,将会打印其Object的默认toString,由此产生上述的结果。

结论:

解决上述问题有如下方法:

方法1:

将字符串分开打印,使用JDK API的重载方法,代码如下:



public static void main(String[] args) {  
"ABC";  
char[] numbers = {'1', '2', '3'};  
" easy as ");  
        System.out.print(numbers);  
    }


方法2:

使用String.valueOf(char[])方法将字符数组转化为字符串,代码如下:



public static void main(String[] args) {  
"ABC";  
char[] numbers = {'1', '2', '3'};  
" easy as " + String.valueOf(numbers));  
    }


当字符数组和字符串进行拼接时,一定千万注意,很多时候结果并不是我们所期望的。

3.字符串比较问题:

测测一下下面程序的输出结果:



public static void main(String[] args) {  
final String pig = "length: 10";  
final String dog = "length: " + pig.length();  
"Animals are equal:" + pig == dog);  
    }


有人可能觉得应该输出:Animals are equals:true,因为dog字符串也是“length: 10”,并且两个字符串都是final类型的,java中相同的字符串会保存在字符串常量池中,因此是同一个对象,因此比较应该为true。

也有人可能局的应该输出:Animals are equals:false,因为java中字符串是不可变的,dog字符串是由两个字符拼接的,隐私dog是另一个对象,因此比较应该为false。

但是程序真实运行结果为:false,没有Animals are equals:字符串打印出来。

原因:

+不论用做加法还是字符串拼接运算符,它都比==操作符优先级更高,因此上面的println语句是按照如下的方式运算:



System.out.print(("Animals are equal:" + pig) == dog);


这个表达式当然输出的结果是false。

结论:

解决上面问题的方法有:

方法1:

使用括号显式指定操作符优先级,代码如下:



public static void main(String[] args) {  
final String pig = "length: 10";  
final String dog = "length: " + pig.length();  
"Animals are equal:" + (pig == dog));  
    }


该程序输出结果为:Animals are equals:false。

但是这种做法使用了JVM字符串常量池限制,如果dog字符串直接使用了字符串常量池,则有可能会输出Animals are equals:true的结果,程序不应该依赖与JVM字符串常量池限制,因此不推荐使用该方法。


方法2:

使用equals方法比较字符串,代码如下:


public static void main(String[] args) {  
final String pig = "length: 10";  
final String dog = "length: " + pig.length();  
"Animals are equal:" + pig.equals(dog));  
    }


该程序输出结果为:Animals are equals:true。


当对字符串比较时,最好使用equals方法,除非是比较两个对象是否相等时才使用==,另外使用==时特别要注意运算符优先级。

4.转义字符:

问题:

下面的程序输出结果应该是什么:



public static void main(String[] args) {  
"a\u0022.length() + \u0022b".length());  
    }


\u0022是unicode转义字符双引号,有人觉得应该输出26,因为在两个双引号直接有26个字符,有人觉得是16,因为一个转义字符\u0022表示一个字符。

真实程序运行结果为:2。

原因:

将\u0022是转义字符替换为双引号,在上面程序可以被替换为如下代码:



public static void main(String[] args) {  
"a".length() + "b".length());  
    }


因此程序运行结果为2.

如果期望输出16,则使用如下代码:


public static void main(String[] args) {  
"a\".length() + \"b".length());  
    }


结论:

java中使用有很多普通转义字符:单引号(\'),换行(\n),制表符(\t),反斜线(\\)等,使用转义字符比使用Unicode的转义字符更清楚,因此在程序中优先选用普通转义字符。

5.注释中的特殊字符:

注意Java注释中特殊字符,例如”\u“表示Unicode转义字符开始。

特别注意”\u“不会出现在一个Unicode转义字符上下文之外,注释中也要特别注意,除非特别必要,否则尽量不要使用Unicode转义字符。

6.字符串的编码问题:

问题:

猜猜下面的程序运行结果是什么:



public static void main(String[] args){  
byte bytes[] = new byte[256];  
for(int i = 0; i < 256; i++){  
byte)i;  
        }  
new String(bytes);  
for(int i = 0, n = str.length(); i < n; i++){  
int)str.charAt(i) + " ");  
        }  
    }


程序的逻辑很简单,先将从0到255的正整数放入一个字节数组中,然后将字节数组转换为字符串,最后再将字符串中每位字符转换为int数值打印出来,所以程序应该打印出从0到255的数值。

很遗憾告诉你真正程序的运行结果不可预测,甚至程序不能正常终止。

原因:

java的字符串构造函数String(byte[])规范中规定:在通过解码使用平台缺省字符集的指定byte数组来构造一个新的String时,该新String的长度是字符集的一个函数,因此字符串的长度可能不等于byte数组的长度,当给定的所有字节在缺省字符集中并非全部有效时,这个构造器的行为是不确定的。

字符集从技术角度来讲是被编码的字符集合和字符编码模式的结合物,也就是说字符集和一个包,包含了字符、表示字符的数字编码以及在字符编码序列和字节编码序列之间相互转换的方式,转换模式在字符集之间存在着很大的区别:某些是在字符和字节之间做一对一的映射,但是大多数字符集都不是这样。ISO-8859-1是唯一能让上述程序按顺序打印从0到255的整数的缺省字符集。

结论:

将程序显式指定ISO-8859-1字符编码集,即可让程序达到我们期望的结果,代码如下:
 
 
 
    
 
public static void main(String[] args){  
byte bytes[] = new byte[256];  
for(int i = 0; i < 256; i++){  
byte)i;  
        }  
        String str;  
try {  
new String(bytes, "ISO-8859-1");  
for(int i = 0, n = str.length(); i < n; i++){  
int)str.charAt(i) + " ");  
            }  
catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
    }


如果不相信可以指定UTF-8,GBK等字符编码集,程序都不能顺序打印从0到255的整数。

J2SE运行是环境JRE的缺省字符编码集依赖于底层操作系统和语言,在java中获取默认字符编码集方法:

JDK5之前的版本:使用System.getProperty("file.encoding")方法来获取。

JDK5以后的版本:可以使用java.nio.charset.Charset.defaultCharset()方法来获得。

每当需要将一个byte序列转换成一个String时,不论是否显式指定字符编码集,程序都在使用某一字符集,如果想让程序的行为可预知,那么最好在每次使用的时候都显式明确第指定所使用的字符编码集。

标签:字符,java,String,程序,length,字符串,解惑,main,之谜
From: https://blog.51cto.com/u_809530/8275320

相关文章

  • JavaScript实现完整的表单验证对邮箱用户名和密码一致性检测并拦截提交-----前端
    完整的表单验证HTML网页使用JS完成用户名密码一致性和邮箱验证<!DOCTYPEhtml><!--这是HTML的注释--><htmllang="en"id="myHtml"> <head> <!--这里不是设置了编码,而是告诉浏览器,用什么编码方式打开文件避免乱码--> <metacharset="UTF-8"> <metaname......
  • 《java解惑》——库谜题
    1.不可变类:问题:下面的程序计算5000+50000+500000值,代码如下:importjava.math.BigInteger;publicclassTest{publicstaticvoidmain(String[]args){newBigInteger("5000");newBigInteger("50000");newBigInteger("500000");......
  • Java-Script 编程
    Java-Script编程目录Java-Script编程一.Js概念1.1简介1.2语法结构二.变量使用2.1定义变量2.2定义常量三.数据类型3.1数值类型(number)3.2字符类型(string)3.3.字符类型常用方法3.4布尔值(boolean)3.5null与undefined3.6数组3.7数组常用的方法3.8运算符四.流程......
  • java ip地址转换成int
    数据库存放,提高数据库使用性能我们将字符串IP转换成int类型保存!java代码如下://将127.0.0.1形式的IP地址转换成十进制整数,这里没有进行任何错误处理publicstaticlongipToLong(StringstrIp){long[]ip=newlong[4];//先找到IP地址字符串中.的......
  • Java类加载机制
    类加载机制将class文件中的二进制数据读取到内存中,并对其进行校验,解析和初始化,将类型数据存放在方法区,实例对象存放在堆,作为方法区该类的数据访问接口。这就是类加载。加载通过全限定名获取二进制字节流将字节流代表的静态存储结构转化为方法区的运行时数据结构在堆中生成......
  • 【深入理解Java虚拟机】内存分配策略
    本文内容来源于《深入理解Java虚拟机》一书,非常推荐大家去看一下这本书。本系列其他文章:【深入理解Java虚拟机】Java内存区域模型、对象创建过程、常见OOM【深入理解Java虚拟机】垃圾回收机制垃圾收集器与内存分配策略Java技术体系中所提倡的自动内存管理最终可以归结为自动......
  • 【JAVA】智慧工地信息管理系统源码 智慧大屏、手机APP、SaaS模式
    一、智慧工地可以通过安全八要素来提升安全保障,具体措施包括:  1.安全管理制度:建立科学完善的安全管理制度,包括安全标准规范、安全生产手册等,明确各项安全管理职责和要求。  2.安全培训教育:对工地人员进行安全培训和教育,提高他们的安全意识和安全素质,使其掌握必要的安全知......
  • Java实现截图和录屏
    一、截图,Javax提供的能力。importjavax.imageio.ImageIO;importjava.awt.*;importjava.awt.image.BufferedImage;importjava.io.File;publicclassDemo1{publicstaticvoidmain(String[]args)throwsException{//创建一个Robot对象......
  • Java获取Windows或Linux下的IP地址
    Java获取Linux或Windows下的IP地址,详情如下importlombok.extern.slf4j.Slf4j;importjava.net.InetAddress;importjava.net.NetworkInterface;importjava.net.SocketException;importjava.net.UnknownHostException;importjava.util.Enumeration;@Slf4jpubli......
  • Java Fastjson反序列化漏洞研究
    一、Fastjson简介Fastjson是阿里巴巴的一个开源项目,在GitHub上开源,使用Apache2.0协议。它是一个支持JavaObject和JSON字符串互相转换的Java库。Fastjson最大的特点在于它的快速,它超越了JackJson、Gson等库。据官方发布的说明,Fastjson从2011年fastjson发布1.1.x版本之后,其性能......