【java学习】String字符串

2023-11-11

1,概念

1)String 不可变

不可变类:final,不可被继承。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    // 省略... 
}

①创建过程

相同的字符串存在常量池中。

String s = "Google";
System.out.println("s = " + s);

s = "Runoob";
System.out.println("s = " + s);

这里写图片描述
在实例中的 s 只是一个 String 对象的引用,并不是对象本身,当执行 s = “Runoob”; 创建了一个新的对象 “Runoob”,而原来的 “Google” 还存在于内存中。

②地址比较

在内存中,相同的字符串只存在一个实例,所以地址相同;但char[]地址不同。
只要对字符串改变,就会产生新的实例。

public void test() {
        String str1 = "hello world";
        String str2 = "hello world";
        if (str1 == str2)
            System.out.println("str1 == str2");
        else
            System.out.println("str1 != str2");
        char[] str3 = "hello world".toCharArray();
        char[] str4 = "hello world".toCharArray();

        if (str3 == str4)
            System.out.println("str3 == str4");
        else
            System.out.println("str3 != str4");
    }

结果:

str1 == str2
str3 != str4

③new String

1,new会产生新的字符串。

String i3 = "100";
String i4 = "10"+new String("0");
System.out.println(i3 == i4);           //false
String i7 = "100";
String i8 = "10" +"0";
System.out.println(i7 == i8);           //true

2,new 产生一个字符串(假设为 ”china” )时,会先去常量池中查找是否已经有了 “china” 对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中 “china” 对象的拷贝对象。

 String ss3 = new String("china");   //产生两个对象,一个在常量池一个在堆中

④为啥要设计成final类?

  1. 安全性
    用户名、密码、访问链接、类的全限定名等大量的字符串用于存储敏感信息,字符串可变会导致这些内容不再可信。
  2. 线程安全
    多个线程改变同一个字符串不会影响其它线程,而是创建一个新的字符串放在缓存中。
  3. hashCode
    String类中的hashCode被重写,不可变性保证了字符串的值不会变,只要两个字符串一致它们hashCode就一样,且第一次使用时就缓存,这样计算hashCode更快。
  4. 缓存池和性能
    因为不可变性所以字符串存储在缓存池中,作为常用的数据结构之一极大的提高了性能。

2)空串

含有一个或多个空格字符的串称为空串

3)形参传递

引用类型作为形参传递会改变实参的值,但是String是特殊的引用类型,作为形参传递不会影响实参的值。

4)字符串长度限制

  1. 编译期间字符串长度限制:65535
    CONSTANT_Utf8_info用于表示String类型的常量对象,其结构的长度限制;
  2. 运行期间长度限制:231 -1
    String的length参数是int,最大长度就是int的最大范围:java.lang.Integer#MAX_VALUE

2,String、StringBuffer和StringBuilder区别

1)String

字符串常量。
是不可变对象。每次对String对象改变时,都等同生成了一个新的String对象,然后指针指向新的String对象,从而耗内存,影响系统性能。
在一下字符串对象生成中,String效率远比StringBuffer快:

 String S1 =This is only a” + “ simple” + “ test”;
 StringBuffer Sb = new StringBuilder(This is only a”).append(“ simple”).append(“ test”);

但如果拼接的字符串来自另外的String对象,速度就会变慢,如:

String S2 =This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;

好的编码习惯:
equalsIgnoreCase()替代equals()
equalsIgnoreCase()==》不区分大小写。

2)StringBuffer(线程安全)

①概念

区别于不可变对象String,StringBuffer和StringBuilder底层是char[]数组实现的,是可变长度的。
字符串变量(线程安全),类似String字符串缓冲区。
推荐使用。每次修改对象的值都是修改对象本身,不生成新的对象。减少GC,提高效率。

②容量

StringBuffer默认初始大小为16;
StringBuffer扩容:

s = new StringBuffer(x);
s.append(y);
1.当y<x时,capacity值为x;
以下情况,容器容量需要扩展:
2.当x<y<2*x+2时,值为 2*x+2
3.当y>2*x+2时,值为y

StringBuffer和StringBuilder的默认大小为16
ArrayList和LinkedList的默认大小10

③方法

方法 说明 举例
append 追加字符串 StringBuffer之所以是线程安全的就是因为append方法是synchronized修饰的
insert 在指定点添加字符 z.insert(4, "le")//“start”-->“starlet”
length 返回当前长度
capacity 返回初始化的长度

3)StringBuilder(非线程安全)

字符串变量(非线程安全).
比StringBuffer快,但不保证同步,多用在单线程(推荐)。==》java中没有绝对的线程安全,这样说更合适一点:无状态类中使用。

字符串拼接:
java中字符串+的原理其实就是StringBuilder().append。
但是对于频繁的+字符串运算,就会频繁的new StringBuilder,频繁创建对象耗时又浪费资源,所以一般推荐用sb代替+运算。

String s1 = "aaa";
String s2 = "bbb";
String s3 = s1 + "," + s2;
//经过反编译,其实是:String s3 = new StringBuilder().append(s1).append(",").append(s2).toString();

String s4 = s1 + s2;
//经过反编译,会发现 s4="aaabbb";常量池中创建了一个新的字符串常量。因为常量池存放的值必须是编译前就确定的。对于s3中的s1和s2是变量,在编译前并不确定其值,所以并不能放入常量池中。

3,Character类

1)概念

Character 类用于对单个字符进行操作。
Character 类在对象中包装一个基本类型 char 的值

// 字符数组
char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };

Character ch = new Character('a');

// 原始字符 'a' 装箱到 Character 对象 ch 中
Character ch = 'a';
// 返回拆箱的值到 'c',原始字符 'x' 用 test 方法装箱
char c = test('x');

2) java.lang.Character API

方法 说明
isLetter() 是否是一个字母
isDigit() 是否是一个数字字符
isWhitespace() 是否是一个空格
isUpperCase() 是否是大写字母
isLowerCase() 是否是小写字母
toUpperCase() 指定字母的大写形式
toLowerCase() 指定字母的小写形式
toString() 返回字符的字符串形式,字符串的长度仅为1

4,字符串函数

1)转换

把一个基本数据类型转为字符串,基本数据类型data.toString()是最快的方式、String.valueOf(data)次之、data+""最慢。
因为String.valueOf()方法底层调用了Integer.toString()方法,但是会在调用前做空判断;Integer.toString()是直接调用了;i+""底层使用StringBuilder实现,先用append方法拼接,再用toString()方法获取字符串。

1>String 2 char[]

char[] ch = str.toCharArray();

2>String 2 String[]

将分隔符分开的字符串转换为数组

data = "aa_bb_cc";
String[] param = data.split("_");

param={“aa”,“bb”,“cc”}

3>char[] 2 String:字符数组转为字符串

String.valueOf(ch);

4>String2Uri

Uri uri = Uri.parse("skdfjlk");

5>int2String

int i = 1;  
String.valueOf(i);//方法一  
Integer.toString(i);//方法二  
String iStr = i+"";//方法三  

举例:

如果int x=20, y=5,则语句System.out.println(x+y +“”+(x+y)+y); 的输出结果是()
答案:25255

6>String2Date2Long

String dateStr = "2010-05-04 12:34:23";
        Date date = new Date();
        //注意format的格式要与日期String的格式相匹配
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            //String -> Date
            date = sdf.parse(dateStr);  //Tue May 04 12:34:23 CST 2010
            //Date -> String
            dateStr = sdf.format(date);
            //String ->Timestamp
            //String的类型必须形如: yyyy-mm-dd hh:mm:ss[.f...] 这样的格式,中括号表示可选,否则报错!!!
            Timestamp ts = Timestamp.valueOf(dateStr);
            //Timestamp -> String
            dateStr = sdf.format(ts);
            //Timestamp -> Date
            date = ts;
            //Date -> Timestamp  父类不能直接向子类转化,可借助中间的String
            //Timestamp -> Long(ms)
            Long time = ts.getTime();
            //Long(ms) -> Timestamp
            ts = new Timestamp(time);
        } catch (Exception e) {
            e.printStackTrace();
        }

获取前一天日期:

        DateFormat df = new SimpleDateFormat("YYYYMMdd");
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        date = calendar.getTime();
        return df.format(date);

各种方法获取当前时间戳(Unix Timestamp):

语言 方法
Perl time
PHP time()
Ruby Time.now (or Time.new ). To display the epoch: Time.now.to_i
Python import time first, then int(time.time())
Java long epoch = System.currentTimeMillis()/1000;
Microsoft .NET C# epoch = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
VBScript/ASP DateDiff(“s”, “01/01/1970 00:00:00”, Now())
Erlang calendar:datetime_to_gregorian_seconds(calendar:now_to_universal_time( now()))-719528243600. OR element(1, now()) * 10000 + element(2, now()).
MySQL SELECT unix_timestamp(now())
PostgreSQL SELECT extract(epoch FROM now());
Oracle PL/SQL SELECT (SYSDATE - TO_DATE(‘01-01-1970 00:00:00’, ‘DD-MM-YYYY HH24:MI:SS’)) * 24 * 60 * 60 FROM DUAL
SQL Server SELECT DATEDIFF(s, ‘1970-01-01 00:00:00’, GETUTCDATE())
JavaScript Math.round(new Date().getTime()/1000.0) getTime() returns time in milliseconds.
Unix/Linux Shell date +%s
PowerShell Get-Date -UFormat “%s” Produces: 1279152364.63599
Actionscript (new Date()).time
Other OS’s Command line: perl -e “print time” (If Perl is installed on your system)
ColdFusion (CFML) MX 6.1+ #int( getTickCount() / 1000 )#
Bash Command Line: date +%s

7>String2LocalDateTime

         DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
         LocalDateTime time = LocalDateTime.now();
         String localTime = df.format(time);
         LocalDateTime ldt = LocalDateTime.parse("2018-01-12 17:07:05",df);
         System.out.println("LocalDateTime转成String类型的时间:"+localTime);
         System.out.println("String类型的时间转成LocalDateTime:"+ldt);

8>String2int

		String s = "10";  
        int i1 = Integer.valueOf(s);//方法一  
        int i2 = Integer.parseInt(s)+1;//方法二  

9>编码方式转换

//将ISO8859-1字符串转成GB2312编码  
new String("ISO8859-1".getBytes("ISO8859-1"),"GB2312")

10>String2List

String str = "a,b,c";
List<String> list1 = Arrays.asList(str.split(",")); //[a, b, c]

11> List2String

List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
String str1 = StringUtils.join(list, ","); //a,b,c

12>String[]2List

String[] array = {"a","b","c"};
  1. 使用Arrays.asList()
List<String> resultList= new ArrayList<>(Arrays.asList(array));

注意:调用Arrays.asList()时,其返回值类型是ArrayList,但此ArrayList是Array的内部类,调用add()时,会报错:java.lang.UnsupportedOperationException,并且结果会因为array的某个值的改变而改变,故需要再次构造一个新的ArrayList。
2. 使用List.of() (java9)

List<String> resultList = List.of(array);

此方法为 Java9新增方法,定义在List接口内,并且为静态方法,故可以由类名直接调用。
3. 使用Collections.addAll()

List<String> resultList = new ArrayList<>(array.length);
Collections.addAll(resultList,array);

2) Java String API

1	char charAt(int index)
返回指定索引处的 char 值。
2	int compareTo(Object o)
把这个字符串和另一个对象比较。
o -- 可以是一个 Byte, Double, Integer, Float, LongShort 类型的参数。
如果指定的数与参数相等返回0。
如果指定的数小于参数返回 -1。
如果指定的数大于参数返回 13	int compareTo(String anotherString)
按字典顺序比较两个字符串。
4	int compareToIgnoreCase(String str)
按字典顺序比较两个字符串,不考虑大小写。
5	String concat(String str)
将指定字符串连接到此字符串的结尾。(也可以使用+,它可以连接任何数据)
6	boolean contentEquals(StringBuffer sb)
当且仅当字符串与指定的StringButter有相同顺序的字符时候返回真。
7	static String copyValueOf(char[] data)
返回指定数组中表示该字符序列的 String8	static String copyValueOf(char[] data, int offset, int count)
返回指定数组中表示该字符序列的 String9	boolean endsWith(String suffix)
测试此字符串是否以指定的后缀结束。
10	boolean equals(Object anObject)
将此字符串与指定的对象比较。
11	boolean equalsIgnoreCase(String anotherString)
将此 String 与另一个 String 比较,不考虑大小写。
12	byte[] getBytes()
 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
13	byte[] getBytes(String charsetName)
使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
14	void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
将字符从此字符串复制到目标字符数组。
15	int hashCode()
返回此字符串的哈希码。
16	int indexOf(int ch)
返回指定字符在此字符串中第一次出现处的索引。
17	int indexOf(int ch, int fromIndex)
返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
18	int indexOf(String str)
 返回指定子字符串在此字符串中第一次出现处的索引。
19	int indexOf(String str, int fromIndex)
返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
str1.IndexOf("字")//查找“字”在str1中的索引值(位置)
str1.IndexOf("字串")//查找“字串”的第一个字符在str1中的索引值(位置)
str1.IndexOf("字",start,end)//从str1第start+1个字符起,查找end个字符,查找“字”在字符串STR1中的位置[从第一个字符算起]注意:start+end不能大于str1的长度
20	String intern()
 返回字符串对象的规范化表示形式。
21	int lastIndexOf(int ch)
 返回指定字符在此字符串中最后一次出现处的索引。
22	int lastIndexOf(int ch, int fromIndex)
返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
23	int lastIndexOf(String str)
返回指定子字符串在此字符串中最右边出现处的索引。
24	int lastIndexOf(String str, int fromIndex)
 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
25	int length()
返回此字符串的长度。
26	boolean matches(String regex)
告知此字符串是否匹配给定的正则表达式。
27	boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等。
28	boolean regionMatches(int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等。
29	String replace(char oldChar, char newChar)
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
30	String replaceAll(String regex, String replacement
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
31	String replaceFirst(String regex, String replacement)
 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
32	String[] split(String regex)
根据给定正则表达式的匹配拆分此字符串。
33	String[] split(String regex, int limit)
根据匹配给定的正则表达式来拆分此字符串。
将“abc*ad*ac”换为“abc”,“ad”,"ac"
String[] str_split = new String[3];
str_split = str.split("\\*")
34	boolean startsWith(String prefix)
测试此字符串是否以指定的前缀开始。
35	boolean startsWith(String prefix, int toffset)
测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
36	CharSequence subSequence(int beginIndex, int endIndex)
 返回一个新的字符序列,它是此序列的一个子序列。
37	String substring(int beginIndex)
返回一个新的字符串,它是此字符串的一个子字符串。
38	String substring(int beginIndex, int endIndex)
返回一个新字符串,它是此字符串的一个子字符串。
str.substring(3);//"Hello world!"-->"lo world!"
str.substring(3,7);//"Hello world!"-->"lo w"
str = str.substring(0,str.length()-1) 去掉最后一位
39	char[] toCharArray()
将此字符串转换为一个新的字符数组。
40	String toLowerCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
41	String toLowerCase(Locale locale)
 使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。
42	String toString()
 返回此对象本身(它已经是一个字符串!)。
43	String toUpperCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
44	String toUpperCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
45	String trim()
返回字符串的副本,忽略前导空白和尾部空白。
RTrim: s = s.ToString().RTrim(',') ; //直接trim掉一些字符 
类似的还有TrimEndTrimStart,LTrimchar[] MyChar = {'5',','};  s = s.TrimEnd(MyChar); 
46	static String valueOf(primitive data type x)
返回给定data type类型x参数的字符串表示形式。

3)格式化字符串(字符串拼接)

①对整数进行格式化

%[index$][标识][最小宽度]转换方式

格式化字符串由4部分组成:

  1. 特殊的格式:以%index$开头,index从1开始取值,表示将第index个参数拿进来进行格式化
  2. 标识:
符号 说明
- 在最小宽度内左对齐,不可以与"用0填充"同时使用
# 只适用于8进制和16进制,8进制时在结果前面增加一个0,16进制时在结果前面增加0x
+ 结果总是包括一个符号(一般情况下只适用于10进制,若对象为BigInteger才可以用于8进制和16进制)
正值前加空格,负值前加负号 一般情况下只适用于10进制,若对象为BigInteger才可以用于8进制和16进制
0 结果将用零来填充
, 只适用于10进制,每3位数字之间用","分隔
( 若参数是负数,则结果中不添加负号而是用圆括号把数字括起来(同’+'具有同样的限制)
  1. [最小宽度]:最终该整数转化的字符串最少包含多少位数字。
  2. 转换方式:d-十进制 o-八进制 x或X-十六进制
    举例:
System.out.println(String.format("%1$,09d", -3123));//-0003,123
System.out.println(String.format("%1$9d", -31));//      -31
System.out.println(String.format("%1$-9d", -31));//-31
System.out.println(String.format("%1$(9d", -31));// (31)

②对浮点数进行格式化:

%[index$][标识][最少宽度][.精度]转换方式

转换方式:

'e', 'E' -- 结果被格式化为用计算机科学记数法表示的十进制数
'f' -- 结果被格式化为十进制普通表示方式
'g', 'G' -- 根据具体情况,自动选择用普通表示方式还是科学计数法方式
'a', 'A' -- 结果被格式化为带有效位数和指数的十六进制浮点数

③对字符进行格式化

对字符进行格式化是非常简单的,c表示字符,标识中’-'表示左对齐,其他就没什么了。

5,数据结构-串

1)概念

字符位置:字符在序列中的序号(从1开始)
子串位置:第一个字符在主串的位置。

2)串的模式匹配:KMP算法(克努特—莫里斯—普拉特操作)

①概念

串的模式匹配:子串的定位操作通常称做模式匹配,是各种串处理系统中最重要的操作之一。
KMP算法:给定两个字符串O和f,长度分别为n和 m,判断f是否在O中出现,如果出现则返回出现的位置。常规方法是遍历O的每一个位置,然后从该位置开始和f进行匹配,但是这种方法的复杂度是 O(nm)。kmp算法通过一个O(m)的预处理,使匹配的复杂度降为O(n+m)。

②KMP算法核心

每次匹配失败就隔N-X个字符进行下一次匹配(因为N的大小是N,没有N个字符是不可能匹配成功的)(X指的是在上一段字符中能匹配成功的字符数)

③复杂度分析

最好情况:每趟匹配不成功都是在第一个字符,即每趟都只需匹配一次就知道该趟是否匹配。O(m+n)
最坏情况:每趟匹配不成功都是在最后一个字符。时间复杂度O(m*n)

④计算

计算前缀 Next[i] 的值:
我们令 next[0] = -1 。从 next[1] 开始,每求一个字符的 next 值,就看它前面是否有一个最长的"字符串"和从第一个字符开始的"字符串"相等(需要注意的是,这2个"字符串"不能是同一个"字符串")。如果一个都没有,这个字符的 next 值就是0;如果有,就看它有多长,这个字符的 next 值就是它的长度。

计算修正后的 Nextval[i] 值:
我们令 nextval[0] = -1。
从 nextval[1] 开始,如果某位(字符)与它 next 值指向的位(字符)相同,则该位的 nextval 值就是指向位的 nextval 值(nextval[i] = nextval[ next[i] ]);
如果不同,则该位的 nextval 值就是它自己的 next 值(nextvalue[i] = next[i])。

举例:
这里写图片描述
计算前缀 Next[i] 的值:(next数组里面就是最长重复子串字符串的个数)
next[0] = -1;定值。
next[1] = 0;s[1]前面没有重复子串。
next[2] = 0;s[2]前面没有重复子串。
next[3] = 0;s[3]前面没有重复子串。
next[4] = 1;s[4]前面有重复子串s[0] = 'a’和s[3] = ‘a’。
next[5] = 2;s[5]前面有重复子串s[01] = 'ab’和s[34] = ‘ab’。
next[6] = 3;s[6]前面有重复子串s[012] = 'abc’和s[345] = ‘abc’。
next[7] = 4;s[7]前面有重复子串s[0123] = 'abca’和s[3456] = ‘abca’。

计算修正后的 Nextval[i] 值:
nextval[0] = -1;定值。
nextval[1] = 0; ( s[1] = b ) != ( s[ next[1] ] = s[0] = a ),nextval[1] = next[1] = 0。
nextval[2] = 0; ( s[2] = c ) != ( s[ next[2] ] = s[0] = a ),nextval[2] = next[2] = 0。
nextval[3] = -1; ( s[3] = a ) == ( s[ next[3] ] = s[0] = a ),nextval[3] = nextval[ next[3] ] = nextval[0] = -1。
nextval[4] = 0; ( s[4] = b ) == ( s[ next[4] ] = s[1] = b ),nextval[4] = nextval[ next[4] ] = nextval[1] = 0。
nextval[5] = 0; ( s[5] = c ) == ( s[ next[5] ] = s[2] = c ),nextval[5] = nextval[ next[5] ] = nextval[2] = 0。
nextval[6] = -1; ( s[6] = a ) == ( s[ next[6] ] = s[3] = a ),nextval[6] = nextval[3] = -1。
nextval[7] = 4; s[7] != s[4],nextval[7] = next[7] = 4。

注意:下标可以从1开始,那么nextval各位加1,应该为:0,1,1,0,1,1,0,5

再举个例子感受下next的计算:

i        0  1  2  3  4  5  6  7  8
s        a  b  a  b  a  a  b  a  b
next    -1  0  0  1  2  3  1  2  3 
nextval -1  0 -1  0 -1  3  0 -1  0

6,其他应用

1)判断字符串是否为数字

public class TypeJudgeUtil {  
  
    /** 
     * 判断字符串是否是数字 
     * @param s 
     * @return 
     */  
    public static boolean isNum(String s){  
          
        boolean result = false;  
          
        if ( null == s || s.equals("")) {  
            result = false;  
        }  
        else {  
            try {  
                Integer.parseInt(s);  
                result = true;  
            } catch (Exception e) {  
                result = false;  
            }  
        }  
        return result;  
    }  
}  

2)SpannableString

①设置分段字的颜色

 SpannableStringBuilder builder=new SpannableStringBuilder("");
        builder.setSpan(new ForegroundColorSpan(Color.RED),0,1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

②设置分段字的大小

//分段设置字的大小(第一个字号为12sp,第二个字号为13sp)
SpannableStringBuilder builder = new SpannableStringBuilder("¥" + str);
builder.setSpan(new AbsoluteSizeSpan(ChangeView.dip2px(context, 12)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new AbsoluteSizeSpan(ChangeView.dip2px(context, 13)), 2, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv_price.setText(builder);

③设置分段点击事件

SpannableString spanableInfo = new SpannableString("温馨提示:为注册订易点账号的手机号,登录是将自动注册,且代表您已同意" + "《用户服务协议》");
spanableInfo.setSpan(new Clickable(clickListener), 34, 42, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

④文字中添加图片

drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM); 
SpannableString spannableString = new SpannableString(" "); 
spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

3)字符串智能截取

package luo.StringCut;
/**
 * 字符串截取函数
 * 要求:
 * 1,输入一个字符串和字节数,输出为按字节截取的字符串。
 * 2,保证汉字不被截半个,例如("人ABC",4)="人AB",("人ABC们EF",6)="人ABC"
 * @author luo
 *
 *分析:
 *java语言中,默认使用Unicode编码方式,即每个字符占两个字节,
 *因此可以用来存储中文。
 *虽然String是由char组成,但存储时,每个英文占一个字符,中文2个字符。
 */
public class StringCut {

	/**
	 * 判断字符c是否是中文字符,如果是返回true
	 * @return
	 */
	private static boolean isChinese(char c){
		String s = String.valueOf(c);
		return s.getBytes().length>1 ? true : false;
	}
	public static String StringCut(String str, int len){
		if(null == str || 0 == len){
			return "";
		}
		if(str.length() < len){
			System.out.println("非法信息:截取长度大于字符串长度!");
			return "";
		}
		char[] charArr = str.toCharArray();
		StringBuilder sb = new StringBuilder("");
		int count = 0;//用来记录当前截取字符的长度
		for(char cc:charArr){
			if(count < len){
				if(isChinese(cc)){
					//如果要截取子串的长度只差一个字符,但是接下来的字符是中文,则截取结果子串中不保存这个中文字符
					if(count + 1 == len){
						return sb.toString();
					}
					count = count + 2;
					sb = sb.append(cc);
				}else{
					count = count + 1;
					sb = sb.append(cc);
				}
			}else{
				break;
			}
		}
		return sb.toString();
	}
}

package luo.StringCut;

public class Main {

	public static void main(String[] args){
		//("人ABC",4)="人AB",("人ABC们EF",6)="人ABC"
		System.out.println(StringCut.StringCut("人ABC",4));
		System.out.println(StringCut.StringCut("人ABC们EF",6));
	}
}

4)字符串翻转

不利用java类库,实现字符串翻转

package luo.StringReverse;
/**
 * 不利用java类库,实现字符串翻转
 * @author luo
 *
 *分析:很多种方法可以实现。
 *1,数组翻转法:
 *将字符串转换为字符数组,然后对数组进行翻转,然后再翻转为字符串。
 *2,逆序遍历法:
 *把字符串转换为字符数组,逆向遍历数组,然后拼接遍历到的字符即可。
 *3,递归法:(高水平代码)
 *递归地把字符移动到字符串的最后一个位置。
 */
public class StringReverse {

	/**
	 * 1,数组翻转法:
	 *将字符串转换为字符数组,然后对数组进行翻转,然后再翻转为字符串。
	 */
	public static String reverse1(String str){
		char[] ch = str.toCharArray();
		char c;//交换中间值
		int len = ch.length;
		for (int i = 0; i < len/2; i++) {
			c = ch[i];
			ch[i] = ch[len - i - 1];
			ch[len - i - 1] = c;
		}
		return String.valueOf(ch);
	}
	
	/**
	 *2,逆序遍历法:
	 *把字符串转换为字符数组,逆向遍历数组,然后拼接遍历到的字符即可。
	 */
	public static String reverse2(String str){
		StringBuilder sb = new StringBuilder();
		char[] ch = str.toCharArray();
		for (int i = ch.length-1; i >=0; i--) {
			sb.append(ch[i]);
		}
		return sb.toString();
	}
	
	/**
	 *3,递归法:
	 *递归地把字符移动到字符串的最后一个位置。
	 */
	public static String reverse3(String str){
		
		if(str.length() < 1){
			return str;
		}
		return reverse3(str.substring(1)) + str.charAt(0);
	}
	/**
	*使用栈
	*①将字符串转换为char数组
	*②将char数组中的字符依次压入栈中
	*③将栈中的字符依次弹出赋值给char数组
	*/
	public static String strReverseWithStack(String string){
	    if(string==null||string.length()==0)return string;
	    Stack<Character> stringStack = new Stack<>();
	    char [] array = string.toCharArray();
	    for(Character c:array){
	        stringStack.push(c);
	    }
	    int length = string.length();
	    for(int i= 0;i<length;i++){
	        array[i] = stringStack.pop();
	    }
	    return new String(array);
	}

另一种写法,利用StringBuffer:

String src = "ABCDEF ";
String dst = new StringBuffer(src).reverse().toString();

5)把一个字符串转换成整数

java源码:

    public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        /*
         * WARNING: This method may be invoked early during VM initialization
         * before IntegerCache is initialized. Care must be taken to not use
         * the valueOf method.
         */

        if (s == null) {
            throw new NumberFormatException("null");
        }
        
		//如果是空字符串,或者进制低于能解析的最小进制(2)或者高于能解析的最大进制(36),则抛出异常;
        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }
        if (radix > Character.MAX_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " greater than Character.MAX_RADIX");
        }

        int result = 0;
        boolean negative = false;//是否是负数
        int i = 0, len = s.length();
        int limit = -Integer.MAX_VALUE;
        int multmin;
        int digit;

        if (len > 0) {
            char firstChar = s.charAt(0);
            //根据第一个字符去判断字符串代表的数字是正的还是负的,通过flag negative标记
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);

                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            multmin = limit / radix;
            //取出字符串中的每一位字符,按照进制radix转化为数字,倘若不是数字,则返回值为-1,抛出异常。
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(s.charAt(i++),radix);
                if (digit < 0) {
                    throw NumberFormatException.forInputString(s);
                }
                
                //Java中整数值都是32位的,它是有范围的。我们需要验证字符串转化之后是不是在这个范围以内,即[Integer.MIN_VALUE, Integer.MAX_VALUE]。这里并不存在统一设置上限的写法,因为-Integer.MIN_VALUE > Integer.MAX_VALUE!
                if (result < multmin) {//确保result * radix不会超出界限
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                if (result < limit + digit) {//判断最终是否超出界限
                    throw NumberFormatException.forInputString(s);
                }
                
                result -= digit;//最后返回的时候,值如果是负数直接返回,否则返回-result
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }

6)替换空格

请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
解题思路:

①从后往前打

复杂度为O(n)的解法:首先计算原字符串长度,空格个数;然后计算替换之后的长度;从字符串后面开始替换:设置两个指针分别指向原、新字符串的尾部,逐个赋值;

public void replaceSpace(char[] str) {
        if (str.length <= 0)
            return;

        int original_length = str.length;
        int number_of_space = 0;
        for (int i = 0; i < str.length; i++) {
            if (str[i] == ' ')
                ++number_of_space;
            ++i;
        }

        if (number_of_space <= 0)
            return;

        int new_length = original_length + 2 * number_of_space;

        char[] new_str = new char[new_length];
        while (original_length > 0 && new_length >= original_length) {
            if (str[original_length - 1] == ' ') {
                new_str[new_length-- - 1] = '0';
                new_str[new_length-- - 1] = '2';
                new_str[new_length-- - 1] = '%';
            } else {
                new_str[new_length-- - 1] = str[original_length - 1];
            }
            --original_length;
        }
        System.out.print(new_str);
    }

②用StringBuilder、StringBuffer类

public String replaceSpace(StringBuffer str) {
        if (str == null)
            return null;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            if (String.valueOf(str.charAt(i)).equals(" ")) {
                sb.append("%20");
            } else {
                sb.append(str.charAt(i));
            }
        }
        return String.valueOf(sb);
    }

7)大数运算

一般用字符串或数组表达大数。

①打印1到最大的n位数

思路:
n可能是大数。所以要用string。打印的时候,也要注意过滤掉String中前几位无用的000.
如果在数字前面补0,我们会发现n位所有十进制其实就是n各从0到9的全排列。
全排列的递归很容易表达,数字的每一位都可能是0~9中的一个数,然后设置下一位。递归结束条件:我们已经设置了数字的最后一位。

    public void printToMaxOfNDigits(int n) {
        int[] array=new int[n];
        if(n <= 0)
            return;
        printArray(array, 0);
    }
    private void printArray(int[] array,int n) {
        for(int i = 0; i < 10; i++) {
            if(n != array.length) {
                array[n] = i;
                printArray(array, n+1);
            } else {
                boolean isFirstNo0 = false;
                for(int j = 0; j < array.length; j++) {
                    if(array[j] != 0) {
                        System.out.print(array[j]);
                        if(!isFirstNo0)
                            isFirstNo0 = true;
                    } else {
                        if(isFirstNo0)
                            System.out.print(array[j]);
                    }
                }
                System.out.println();
                return ;
            }
        }
    }

②一个函数,实现任意两个整数的加法。

考虑大数问题。考虑输入的数字有负数问题。

③其他


    //n-m
    public static String sub(String n, String m){

        int n1 = getPart0(n);
        int m1 = getPart0(m);
        int n2 = getPart1(n);
        int m2 = getPart1(m);
        if (n2 >= m2){
            return String.valueOf(n1-m1) + String.valueOf(n2-m2);
        }else{

            int result = 10;
            while ((n2 /= 10) != 0){
                result *= 10;
            }
            return String.valueOf(n1-m1-1) + String.valueOf(n2+result-m2);
        }
    }

    /**
     * 判断n<m
     * @param n
     * @param m
     * @return
     */
    public static boolean big(String n , String m){
        if (n.length() < m.length()) return true;
        if (n.length() == m.length()){

            if (n.equals(m)) return true;

            int n1 = getPart0(n);
            int m1 = getPart0(m);
            if (n1 < m1 ) return true;
            else{

                int n2 = getPart1(n);
                int m2 = getPart1(m);
                if (n2 <m2) return true;
            }
        }
        return false;
    }

    /**
     * n*2
     * @param n
     * @return
     */
    public static String mul2(String n){

        int n1 = getPart0(n);
        int n2 = getPart1(n);
        String n1Str = String.valueOf(n1*2);
        String n2Str = String.valueOf(n2*2);
        if (n2Str.length() == (n.length() - n.length()/2)) return n1Str+n2Str;
        else return String.valueOf(n1*2 + 1) + n2Str.substring(1,n2Str.length());
    }

    /**
     * 获取前半部分
     * @param n
     * @return
     */
    public static int getPart0(String n){
        if (n.length() <2) return 0;
        return Integer.valueOf(n.substring(0,n.length()/2));
    }

    /**
     * 获取后半部分
     * @param n
     * @return
     */
    public static int getPart1(String n){
        if (n.length() <2) return 0;
        return Integer.valueOf(n.substring(n.length()/2, n.length()));
    }


    /**
     * n/2
     * @param n
     * @return
     */
    public static String div2(String n){

        int n1 = getPart0(n);
        int n2 = getPart1(n);
        if (n1 % 2 == 0){
            return String.valueOf(n1/2) + String.valueOf(n2/2);
        }
        int result = 5;
        while ((n2 /= 10) != 0){
            result *= 10;
        }
        return String.valueOf(n1/2) + String.valueOf(n2/2 + result);
    }

8)字符串排列(全排列)

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

解题思路:将当前位置的字符和前一个字符位置交换,递归。
如下图所示,把字符串分为两部分:一部分是字符串第一个字符,一部分是第一个字符之后的字符排列。接下来我们需要知道阴影部分的字符串排列。
这里写图片描述


import java.util.ArrayList;
import java.util.TreeSet;

    public ArrayList<String> Permutation(String str) {
        ArrayList<String> result = new ArrayList<String>();
        if (str == null || str.length() == 0)
            return result;
        char[] chars = str.toCharArray();
        TreeSet<String> temp = new TreeSet<>();
        Permutation(chars, 0, temp);
        result.addAll(temp);
        return result;
    }

    public void Permutation(char[] chars, int index, TreeSet<String> result) {
        if (chars == null || chars.length == 0)
            return;
        if (index < 0 || index > chars.length - 1)
            return;
        if (index == chars.length - 1) {
            result.add(String.valueOf(chars));
        } else {
            for (int i = index; i <= chars.length - 1; i++) {
                swap(chars, index, i);
                Permutation(chars, index + 1, result);
                // 回退
                swap(chars, index, i);
            }
        }
    }

    public void swap(char[] c, int a, int b) {
        char temp = c[a];
        c[a] = c[b];
        c[b] = temp;
    }

9)第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写)。

思路:利用LinkedHashMap保存字符和出现次数。

import java.util.LinkedHashMap;

   public int FirstNotRepeatingChar(String str) {
        
        if (str == null || str.length() == 0)
            return -1;
        char[] c = str.toCharArray();
        LinkedHashMap<Character,Integer> hash=new LinkedHashMap<Character,Integer>();
        for(char item : c) {
            if(hash.containsKey(item))
                hash.put(item, hash.get(item)+1);
            else
                hash.put(item, 1);
        }
        for(int i = 0;i < str.length(); i++){
            if (hash.get(str.charAt(i)) == 1) {
                return i;
            }
        }
        return -1;
    }

10)翻转字符串

如将“I am a student”,转为“student a am I”。

思路:先将整个字符串翻转,然后将每个单词翻转。


    public String ReverseSentence(String str) {
        if (str == null || str.length() == 0)
            return str;
        if (str.trim().length() == 0)
            return str;
        StringBuilder sb = new StringBuilder();
        String re = reverse(str);
        String[] s = re.split(" ");
        for (int i = 0; i < s.length - 1; i++) {
            sb.append(reverse(s[i]) + " ");
        }
        sb.append(reverse(s[s.length - 1]));
        return String.valueOf(sb);
    }

    public String reverse(String str) {
        StringBuilder sb = new StringBuilder();
        for (int i = str.length() - 1; i >= 0; i--) {
            sb.append(str.charAt(i));
        }
        return String.valueOf(sb);
    }

12)String2Int 自定义

public static int stringToInt(String str) {
        int result=0;
        char[] ch=str.toCharArray();
        int len=ch.length;
        for(int i=0;i<len;i++) {
            result+=(((int)ch[i]-'0')*Math.pow(10, len-1-i));
        }
       
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【java学习】String字符串 的相关文章

随机推荐

  • Kali Linux 2020.1修改Root用户密码

    背景信息 多年以来 Kali从BackTrack继承了默认的root用户策略 作为对Kali工具和策略的评估的一部分 因此Kali 决定对此进行更改 并将Kali移至 传统默认非根用户 模型 那如果我们因某些情况想开启Root用户这应该如何
  • facebook stetho Android调试工具

    什么是Stetho 官网简介 Stetho is a debug bridge for Android applications enabling the powerful Chrome Developer Tools and much m
  • 如何利用matlab神经网络进行水量预测

    数据收集 百度搜索EPS数据库登陆 我们选择进入城市数据库 我们的目的是要进行某年水量预测 我们的目的是知道了某一年的土地 人口等信息 就可以预测出该年的用水量 因此我们需要搜集一些信息用来训练 可以多选几年如2003 2017 然后点击下
  • 13 集成测试之自顶向下集成测试方法

    自顶向下集成测试方法 前言 深度优先集成方法 宽度优先集成方法 总结 前言 自顶向下集成方法可以采取深度优先或者宽度优先策略 深度优先集成方法 深度优先从最左边分支自上而下开始测试并向上结合 测试完一个分支后再测试下一个分支 如图测试顺序为
  • 渗压计工作原理及选型

    渗压计适合埋设在水工建筑物和基岩内 或安装在测压管 钻孔 堤坝 管道或压力容器中 以测量孔隙水压力或液位 主要部件均采用特殊钢材制造 适合在各种恶劣环境中使用 一般型号后缀为标准型 可以为低量程型和为通气 差压 型 另可根据客户要求提供高压
  • Hypertable 简介 一个 C++ 的Bigtable开源实现

    1 Introduction 随着互联网技术的发展 尤其是云计算平台的出现 分布式应用程序需要处理大量的数据 PB级 在一个或多个云计算平台中 成千上万的计算主机 如何保证数据的有效存储和组织 为应用提供高效和可靠的访问接口 并且保持良好的
  • scss中的样式复用:继承;占位符;混合宏

    文章目录 一 使用 extend实现样式复用 继承 二 使用占位符实现样式复用 占位 三 使用混合宏实现样式复用 混合宏 四 参数运算符 待更新 类名复用 未验证 待更新 react中使用sass 了解css in js解决方案 在reac
  • 【Pandas 数据查找函数 详解】

    本文介绍了Pandas数据查找常用函数 掌握了这些函数的应用 让你在数据处理时 手到擒来 游刃有余 目录 一 查找数据位置 s str find 和s str index 函数 二 数据的查找判断 1 判断开头或结尾是否是指定字符串s st
  • 保姆级Obsidian学习教程【超完整,小白必备】

    前言 本篇文章学习视频来源 沙牛obsidian优质课程 学 习 软 件 obsidian 课 程 对 应 资 源 云盘资源 说 明 Obsidian是基于Markdown文件的本地知识管理软件 并且开发者承诺Obsidian对于个人使用者
  • java integer long 转换_long(Long)与int(Integer)之间的转换

    1 将long型转化为int型 这里的long型是基础类型 long a 10 int b int a 2 将Long型转换为int 型的 这里的Long型是包装类型 Long a 10 int b a intValue 3 将Long型转
  • 编译GDB --enable-targets=all --enable-64-bit-bfd

    这次尝试才用一种新的BLOG发帖 大家都可以把要发到BLOG的文章投递到MAILLIST 然后大家REVIEW 等REVIEW的差不离了 再发到BLOG上 欢迎大家帮忙review 编译GDB teawater hellogcc 1 取得源
  • 2.1python中的赋值运算符和比较运算符

    在程序中 使用赋值运算符可以帮助我们更加高效的完成一些需要多行程序完成的工作 使用比较运算符可以让程序员通过比较更加明白所编程序是否与自己的所思考的相同 1 首先 我们先看一下赋值运算符的具体内容 如下 赋值运算符符号 含义 a b b a
  • 微信H5(公众号)跳转微信小程序实现及其传参

    1 使用微信开放标签 wx open launch weapp 跳转
  • Linux车机平台pulseaudio多alsasink配置

    https www freedesktop org wiki Software PulseAudio 官网上的介绍是这样的 pulseaudio 是一个POSIX操作系统上的声音系统 是音频应用的代理 它允许你对音频数据 在从应用传递到硬件
  • Java版企业电子招标采购系统源码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

    项目说明 随着公司的快速发展 企业人员和经营规模不断壮大 公司对内部招采管理的提升提出了更高的要求 在企业里建立一个公平 公开 公正的采购环境 最大限度控制采购成本至关重要 符合国家电子招投标法律法规及相关规范 以及审计监督要求 通过电子化
  • 【java】maven引用外部 jar 包,以RXTXcomm.jar为例

    目录 1 作为资源文件夹内的资源引用 2 将jar包手动安装到maven仓库 工具 IntelliJ IDEA 2020 2 3 x64 1 作为资源文件夹内的资源引用 1 在项目根路径新建文件夹lib 将资源文件复制到该文件夹 2 将文件
  • python处理压缩文件

    Zip 模块安装 pip install zipfile 使用 import zipfile 打开zip文件 zipfileObj zipfile ZipFile tmp zip with上下文 with zipfile ZipFile t
  • C语言实现的 通讯录管理系统

    通讯录 C语言实现 文章目录 通讯录1 静态 通讯录2 动态 通讯录3 动态 储存 前言 本文讲解如何用C语言来创建一个通讯录 这是一个小项目 非常适合新手上手 同时也可以提高自己的代码能力 里面用到了 结构体传参 枚举常量 文件 动态内存
  • 惠普服务器开机系统密码,惠普(hp)各型号打印机冷复位,清零,回复出厂设置方法 以及 服务菜单(service menu)密码...

    惠普 hp 各型号打印机冷复位 清零 回复出厂设置方法 以及 服务菜单 service menu 密码 由会员分享 可在线阅读 更多相关 惠普 hp 各型号打印机冷复位 清零 回复出厂设置方法 以及 服务菜单 service menu 密码
  • 【java学习】String字符串

    1 概念 1 String 不可变 不可变类 final 不可被继承 public final class String implements java io Serializable Comparable