java字符串编程
㈠ 用java编写一程序:从键盘输入多个字符串到程序中,并将它们按逆序输出在屏幕上。
代码如下:
import java.util.Scanner;
public class ScannerDemo{
public static void main(String[] args) throws Exception{
Scanner scan=new Scanner(System.in);
System.out.println("请输入内容:");
String str=scan.nextLine();
char[] s=str.toCharArray();
for(int i=s.length-1;i>=0;i--){
System.out.print(s[i]);}}}
(1)java字符串编程扩展阅读
字符串
通常以串的整体作为操作对象,如:在串中查找某个子串、求取一个子串、在串的某个位置上插入一个子串以及删除一个子串等。
两个字符串相等的充要条件是:长度相等,并且各个对应位置上的字符都相等。设p、q是两个串,求q在p中首次出现的位置的运算叫做模式匹配。串的两种最基本的存储方式是顺序存储方式和链接存储方式。
基本数据结构
在Java中有8种数据类型来存储数值、字符和布尔值。
整数类型
整数型用来存储整数数值,即没有小数部分的数值。可以是正数,也可以是负数。整数数据在Java程序中有3种表示形式,分别为十进制、八进制和十六进制。
㈡ Java工具类(一)Guava操作字符串
在Java编程中,处理字符串是一个常见任务,从简单的空值判断到复杂的拆分和连接操作,都需要高效、简便的解决方案。为简化这类任务,Google开发了Guava库,提供丰富的集合工具和高效字符串处理功能。本文将深入探讨Guava库的字符串操作能力,重点关注连接器、拆分器、字符匹配器、字符集和大小写格式工具。
Guava连接器(Joiner)是一个强大的字符串连接工具,能够优雅地处理空值问题。其使用方式分为三步:使用`on`方法设置连接符,调用`useForNull`方法为`null`值设定默认处理,最后使用`join`方法处理集合。例如:
java
Joiner joiner = Joiner.on(", ");
String result = joiner.join(Arrays.asList("apple", null, "banana"));
Guava拆分器(Splitter)允许以模式、字符、字符串或字符匹配器进行复杂拆分,返回`Iterable`对象。其创建和配置过程同样遵循不可变设计原则,确保线程安全。
字符匹配器(CharMatcher)则提供了一种简单而强大的方式来处理特定类型的字符,如数字或空白字符。它实现了一个布尔判断接口,并提供了多种方法来操作匹配字符,如修剪、折叠、移除、保留等。
Charsets为Java平台提供的六种标准字符集提供了常量引用,确保了跨平台兼容性。使用这些常量而非名称获取实例能避免潜在的不兼容性问题。
大小写格式(CaseFormat)工具用于方便地在不同ASCII大小写规范间转换字符串,支持多种格式。例如,转换字符串以适应编程语言的命名规范。
总结而言,Guava的字符串处理工具集不仅简化了常见字符串操作,还提供了高性能、灵活的解决方案,适用于大规模数据处理。在使用时,需根据具体需求和场景合理选择工具和参数,以实现性能优化。Guava库的高效设计和丰富功能,为Java开发者提供了强大的支持,有助于提高开发效率和代码质量。
㈢ 浅谈Java中字符串的初始化(详细图解)
前言在深入学习字符串类之前,我们先搞懂JVM是怎样处理新生字符串的。当你知道字符串的初始化细节后,再去写Strings="hello"或Strings=newString("hello")等代码时,就能做到心中有数。
首先得搞懂字符串常量池的概念,下面进入正文吧。
常量池把经常用到的数据存放在某块内存中,避免频繁的数据创建与销毁,实现数据共享,提高系统性能。
八种基础数据类型除了float和double都实现了常量池技术。在近代的JDK版本中(1.7后),字符串常量池被实现在Java堆内存中。
下面通过三行代码让大家对字符串常量池建立初步认识:
publicstaticvoidmain(String[]args){Strings1="hello";Strings2=newString("hello");System.out.println(s1==s2);//false}先来看看第一行代码Strings1="hello";
直接通过双引号(Strings1="hello")声明字符串的方式,虚拟机首先会到字符串常量池中查找该字符串是否已经存在。如果存在会直接返回该引用,如果不存在则会在堆内存中创建该字符串对象,然后到字符串常量池中注册该字符串。
上面的代码中(Strings1="hello")虚拟机首先会到字符串常量池中查找是否有存在hello字符串对应的引用。发现没有后会在堆内存创建hello字符串对象(内存地址0x0001),然后到字符串常量池中注册地址为0x0001的hello对象,也就是添加指向0x0001的引用。最后把字符串对象返回给s1。
下面看Strings2=newString("hello");
当我们使用new关键字创建字符串对象的时候,JVM将不会查询字符串常量池,它将会直接在堆内存中创建一个字符串对象,并返回给所属变量。
所以s1和s2指向的是两个完全不同的对象,判断s1==s2的时候会返回false。
再来看下面的示例:
publicstaticvoidmain(String[]args){Strings1=newString("hello")+newString("world");s1.intern();Strings2="helloworld";System.out.println(s1==s2);//true}第一行代码Strings1=newString("hello")+newString("world");的执行过程是这样子的:
依次在堆内存中创建hello和world两个字符串对象;
然后把它们拼接起来(底层使用StringBuilder实现);
在拼接完成后会产生新的helloworld对象,这时变量s1指向新对象helloworld。
执行完第一行代码后,内存是这样子的:
第二行代码s1.intern();
当调用intern()方法时,首先会去常量池中查找是否有该字符串对应的引用,如果有就直接返回该字符串;
如果没有,就会在常量池中注册该字符串的引用,然后返回该字符串。
由于第一行代码采用的是new的方式创建字符串,所以在字符串常量池中没有保存helloworld对应的引用,虚拟机会在常量池中进行注册,注册完后的内存示意图如下:
第三行代码Strings2="helloworld";
首先虚拟机会去检查字符串常量池,发现有指向helloworld的引用。然后把该引用所指向的字符串直接返回给所属变量。
执行完第三行代码后,内存示意图如下:
如图所示,s1和s2指向的是相同的对象,所以当判断s1==s2时返回true。
总结:
当用new关键字创建字符串对象时,不会查询字符串常量池;
当用双引号直接声明字符串对象时,虚拟机将会查询字符串常量池。
说白了就是:字符串常量池提供了字符串的复用功能,除非我们要显式创建新的字符串对象,否则对同一个字符串虚拟机只会维护一份拷贝。
反编译代码验证字符串初始化操作下面我们再来看一个示例:
publicclassMain{publicstaticvoidmain(String[]args){Strings1="hello";Strings2="world";Strings3=s1+s2;Strings4="helloworld";System.out.println(s3==s4);}}首先第一行和第二行是常规的字符串对象声明,它们分别会在堆内存创建字符串对象,并会在字符串常量池中进行注册。
影响我们做出判断的是第三行代码Strings3=s1+s2;,我们不知道s1+s2在创建完新字符串helloworld后是否会在字符串常量池进行注册。
简单点说:我们不知道这行代码是以双引号形式声明字符串,还是用new关键字创建字符串。
那么我们看下这端代码的反编译后的代码:
PSD:codejavaSE argetclassesdemo>javap-c.Main.classCompiledfrom"Main.java"publicclassdemo.Main{publicdemo.Main();Code:0:aload_01:invokespecial#1//Methodjava/lang/Object."<init>":()V4:returnpublicstaticvoidmain(java.lang.String[]);Code:0:ldc#2//Stringhello2:astore_13:ldc#3//Stringworld5:astore_26:new#4//classjava/lang/StringBuilder9:p10:invokespecial#5//Methodjava/lang/StringBuilder."<init>":()V13:aload_114:invokevirtual#6//Methodjava/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;17:aload_218:invokevirtual#6//Methodjava/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;21:invokevirtual#7//Methodjava/lang/StringBuilder.toString:()Ljava/lang/String;24:astore_325:ldc#8//Stringhelloworld27:astore429:getstatic#9//Fieldjava/lang/System.out:Ljava/io/PrintStream;32:aload_333:aload435:if_acmpne4238:iconst_139:goto4342:iconst_043:invokevirtual#10//Methodjava/io/PrintStream.println:(Z)V46:return}直接看重点:
21:invokevirtual#7//Methodjava/lang/StringBuilder.toString:()Ljava/lang/String;
24:astore_3
虚拟机调用StringBuilder的toString()方法获得字符串helloworld,并存放至s3。
下面是我们追踪StringBuilder的toString()方法源码:
@OverridepublicStringtoString(){//Createa,don'tsharethearrayreturnnewString(value,0,count);}通过以上源码可以看出:s3是通过new关键字获得字符串对象的。
回到题目,也就是说字符串常量表中没有存储helloworld的引用,当s4以引号的形式声明字符串时,由于在字符串常量池中查不到相应的引用,所以会在堆内存中新创建一个字符串对象。所以s3和s4指向的不是同一个字符串对象,结果为false。
总结阅读完本文,相信你对于字符串的初始化的了解又更上一层了。关注我,一个专注分享Java知识的新时代农民工。
作者:初念初恋