Java修炼之路——基础篇——String

String

1:字符串的不可变性
什么是不可变对象?不可变对象是指创建后无法变更的对象
String为什么是不可变的?String类为final,并且内部字符数组也为final。所以String对象是不可变对象。
String类为什么要设计为不可变?
主要出于对效率和安全的考量。
当你复制一个对象的时候,如果你知道它是不可变的,那么你只需要复制此对象的引用即可,一般引用会比对象小很多,所以能提高效率;String是不可变的,所以字符串常量池才可以存在,减少很多heap内存的占用;因为String的不可变性,所以在创建的时候hashcode就可以缓存,很适合作为map的key值;
安全方面:不可变对象是线程安全的。在多线程情况下,可变对象的内部状态可能会被其他线程改变,导致不可预期的结果。比如数据库连接,socket连接的IP PORT,类加载器等,都是通过String传参的,如果String是可变的,那会引起很大的安全问题。

2:JDK 6和JDK 7中substring的原理及区别
subString(int beginIndex, int endIndex)方法用来截取字符串

String x = "qwertt";x = x.substring(1,2);System.out.println(x);

结果输出:

w

JDK6中的subString
String类有三个属性:
char[] value:字符数组
int offset:起始位置
int count:字符串长度
对于subString方法,生成的String对象,value相同,只是改变了offset和count。这样会导致一个严重的问题:本来只需要很短的字符串,但是因为指向了一个很长的字符串,导致这个长字符串无法回收,存在内存泄漏的风险。
jdk6执行subString的描述

//JDK 6
String(int offset, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;
}public String substring(int beginIndex, int endIndex) {//check boundaryreturn  new String(offset + beginIndex, endIndex - beginIndex, value);
}

jdk6中,为解决上述问题,一般生成一个新的字符串并引用它:

x = x.substring(x, y) + ""

JDK7中的subString
在jdk7中,对上述问题进行了优化。每次执行subString的时候,都会去生成一个新的char[] ,从而避免了上述问题
jdk7执行subString的描述
jdk7源码如下:

//JDK 7
public String(char value[], int offset, int count) {//check boundarythis.value = Arrays.copyOfRange(value, offset, offset + count);
}public String substring(int beginIndex, int endIndex) {//check boundaryint subLen = endIndex - beginIndex;return new String(value, beginIndex, subLen);
}

3:replaceFirst、replaceAll、replace区别

先看一个示例:
String s = "my.test.txt";
System.out.println(s.replace(".", "#"));
System.out.println(s.replaceAll(".", "#"));
System.out.println(s.replaceFirst(".", "#"));
System.out.println(s.replaceFirst("\\.", "#"));

执行结果:

my#test#txt
###########
#y.test.txt
my#test.txt

原因:
replace方法有两个实现,一个是传入字符,循环匹配;一个是传入字符串,使用Pattern的逐个按字符进行匹配;
replaceFirst和replaceAll是使用Pattern,进行正则表达式的匹配。因为“.”在正则表达式中,表示任一字符,所以出现了“###########”的结果。

附源代码实现(jdk1.8版)

replace():

public String replace(char oldChar, char newChar) {if (oldChar != newChar) {int len = value.length;int i = -1;char[] val = value; /* avoid getfield opcode */while (++i < len) {if (val[i] == oldChar) {break;}}if (i < len) {char buf[] = new char[len];for (int j = 0; j < i; j++) {buf[j] = val[j];}while (i < len) {char c = val[i];buf[i] = (c == oldChar) ? newChar : c;i++;}return new String(buf, true);}}return this;}

replace():

public String replace(CharSequence target, CharSequence replacement) {return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));}

replaceAll():

public String replaceAll(String regex, String replacement) {return Pattern.compile(regex).matcher(this).replaceAll(replacement);}

replaceFirst():

public String replaceFirst(String regex, String replacement) {return Pattern.compile(regex).matcher(this).replaceFirst(replacement);}

4:String对“+”的重载、字符串拼接的几种方式和区别
字符串的拼接方式:“+”、StringBuffer、new String().concat、StringBuilder
“+”:底层是使用StringBuilder实现。如:

String s1 = "11";
String s2 = "22";
String s = s1+s2;
System.out.println(s);

其实此段代码基本等价于:

String s1= "11";
String s2= "22";
StringBuilder sb = new StringBuilder();
sb.append(s1);
sb.append(s2);
String str = sb.toString();
System.out.println(str);

在大量使用“+”进行字符串拼接的时候,会产生大量的StringBuilder和String对象,会严重影响效率

concat:
concat其实是申请一个新的数组,进行数组的拷贝,然后用来创建新的String对象。底层是调用:System.arraycopy()

public String concat(String str) {int otherLen = str.length();if (otherLen == 0) {return this;}int len = value.length;char buf[] = Arrays.copyOf(value, len + otherLen);str.getChars(buf, len);return new String(buf, true);}

StringBuffer & StringBuilder
两者调用的父类方法如下,区别在于StringBuffer 方法用了synchronized,是线程安全的
与concat的区别在于:
扩容逻辑不同,concat为需要多少扩多少,StringBuilder等是指数级扩容;
concat每次会生成新的String对象,而StringBuilder不会

public AbstractStringBuilder append(String str) {if (str == null)return appendNull();int len = str.length();ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}

5:String.valueOf和Integer.toString的区别

直接看源代码就好

public static String valueOf(int i) {return Integer.toString(i);
}//对null进行了处理
public static String valueOf(Object obj) {return (obj == null) ? "null" : obj.toString();} public static String toString(int i) {if (i == Integer.MIN_VALUE)return "-2147483648";int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);char[] buf = new char[size];getChars(i, size, buf);return new String(buf, true);}

6:switch对String的支持
Java JDK7中switch添加了对String的支持,之前仅支持(short、int、byte、char),并且底层最终都会转为int类型。那么对于String,是如何支持的呢?
请看以下代码:

public static void test(String status) {switch (status) {case "INIT":System.out.println("INIT");	break;case "PAY_ING":System.out.println("PAY_ING");	break;case "PAY_SUCCESS":System.out.println("PAY_SUCCESS");	break;case "PAY_FAIL":System.out.println("PAY_FAIL");	break;default:System.out.println("default");	break;}}

反编译class文件得到:

public void test(String status){String str;switch ((str = status).hashCode()){case -2113017739:if (str.equals("PAY_FAIL")) break label129; break;case -68158581:if (str.equals("PAY_ING")) break label107; break;case 2252048:if (str.equals("INIT")) break label96; break;case 1643683628:if (!(str.equals("PAY_SUCCESS"))) { break label140:System.out.println("INIT");return;System.out.println("PAY_ING");return;}System.out.println("PAY_SUCCESS");return;label129: System.out.println("PAY_FAIL");label140: break;default:label96: label107: System.out.println("default");}}

虽然看不懂有些带标签的break语句(break label;)但是很明显可以看出来支持String的方式:
将String转为了int类型的hashCode,因为hashCode可能会冲突,又加入了equals判断。

7:字符串池、常量池(运行时常量池、Class常量池)、intern
偷个懒,先放个链接,后续再慢慢完善
https://www.cnblogs.com/tiancai/p/9321338.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P3338 [ZJOI2014]力(FFT)

P3338 [ZJOI2014]力 Fj∑i1j−1qiqj(i−j)2−∑ij1nqiqj(i−j)2Ej∑i1j−1qi(i−j)2−∑ij1nqi(i−j)2f(i)qi,g(i)1i2,f(0)0,g(0)0Ej∑i0jf(i)g(j−i)−∑ijnf(i)g(i−j)F_j \sum_{i 1} ^{j - 1} \frac{q_i \times q_j}{(i - j) ^ 2} - \sum_{i j 1} ^{n} \frac{q_i \times…

CF755G PolandBall and Many Other Balls(多项式/倍增fft)

CF755G PolandBall and Many Other Balls 倍增fft模版题 这种问题关键在于两个状态转移&#xff0c;一个是单点加1&#xff0c;还有一个是乘2&#xff0c;这样我们就相当于拥有了二进制下的左移操作和加1操作&#xff0c;那么可以在O(logn)的时间内表示出任何一个数。 然后对…

VS, VS Code, VS Online, VS xxx, 你都分清了吗?

首先说说部分童鞋容易混淆的 Visual Studio 和 Visual Studio Code 吧。其实&#xff0c;它们俩的关系&#xff0c;就相当于 Java 和 JavaScript&#xff0c;没啥关系。再说说 Visual Studio Online。这就复杂了。历史上&#xff0c;出现过两个 Visual Studio Online&#xff0…

Java修炼之路——基础篇——Java关键字

1&#xff1a;transient 当对象被序列化时&#xff0c;transient阻止其修饰的对象进行序列化&#xff1b;当反序列化时&#xff0c;此对象的值不会被恢复。 2&#xff1a;instanceof 判断引用指向的对象&#xff0c;是不是某个类及其子类的实例对象&#xff1b; class Person …

.NetCore从零开始使用Skywalking分布式追踪系统

将本文从0开始搭建两个webapi项目&#xff0c;使用Skywalking来追踪他们之间的调用关系及响应时间。开发环境为VisualStudio20191&#xff1a;安装Skywalking,可参考&#xff1a;https://www.cnblogs.com/sunyuliang/p/11422576.html&#xff0c;本列中搭建好后的Skywalking服务…

P3723 [AH2017/HNOI2017]礼物(FFT)

P3723 [AH2017/HNOI2017]礼物 式子化简 ∑i1n(xi−yj)2\sum_{i 1} ^{n} (x_i- y_j) ^2\\ i1∑n​(xi​−yj​)2 我们对第一个手环ccc&#xff0c;相当于(xic−yi)2(x_i c - y_i) ^ 2(xi​c−yi​)2&#xff0c;对第二个手环ccc相当于(xi−yi−c)2(x_i - y_i - c) ^2(xi​−…

CF623E Transforming Sequence(多项式/倍增fft/动态规划)

CF623E Transforming Sequence 经典的倍增NTT题目&#xff0c;但是由于万恶的模数导致这道题变成了倍增MTT 要求n个数前缀或严格递增的序列个数&#xff0c;一共有k位。 然后我们考虑进行dp&#xff0c;然后我的思路就是fi,jf_{i,j}fi,j​表示前i位在k位中有j位的方案数&…

2019-02-26-算法-进化(字符串转换成整数)

题目描述&#xff1a; 请你来实现一个 atoi 函数&#xff0c;使其能将字符串转换成整数。 首先&#xff0c;该函数会根据需要丢弃无用的开头空格字符&#xff0c;直到寻找到第一个非空格的字符为止。 当我们寻找到的第一个非空字符为正或者负号时&#xff0c;则将该符号与之后…

通过Service访问应用 (1)

目录通过Service访问应用 通过Pod IP访问应用 通过ClusterIP Service在集群内部访问 通过Service访问应用通过之前的操作&#xff0c;应用部署完成了&#xff0c;我们的Demo网站已经成功启动了&#xff0c;那么如何访问网站呢&#xff1f;通过Pod IP访问应用我们可以通过Pod IP…

P4239 任意模数多项式乘法逆(多项式/ MTT)

P4239 任意模数多项式乘法逆 这个题目简直就是毒瘤&#xff0c;不过还好我们可以使用vector封装要不然真的没法看&#xff0c;现在我们就会用vector封装MTT了&#xff0c;然后有一个代码细节就是这里的求逆还是在模意义下的&#xff0c;所以我们还是需要求逆。 #include<b…

多项式求逆模板(NTT + mod)

【模板】多项式乘法逆 /*Author : lifehappy */ #include <bits/stdc.h>using namespace std;typedef long long ll;const int N 1e6 10, mod 998244353, G 3;int r[N], n;ll a[N], b[N], c[N];ll quick_pow(ll a, int n) {ll ans 1;while(n) {if(n & 1) ans …

2019-02-26-算法-进化(回文数)

题目描述&#xff1a; 判断一个整数是否是回文数。回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 示例 1: 输入: 121 输出: true示例 2: 输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为…

POJ1742 Coins(DP)

Coins 思路 没分析复杂度写了个二进制拆分&#xff0c;然后做010101背包O(nlog(c)m)>10e7了O(nlog(c)m) > 10e7了O(nlog(c)m)>10e7了&#xff0c;所以还是想办法优化吧。 我们引入一个needneedneed数组&#xff0c;need[j]need[j]need[j]表示&#xff0c;在枚举到第…

13张PPT带你了解主动式消息队列处理集群

前言偷偷和你们说&#xff0c;我搞了一份内部资料&#xff0c;该内部资料共有13张PPT&#xff0c;据作者透露&#xff0c;该PPT至少花了整整1周时间才编写完成&#xff0c;其内容简洁明了&#xff0c;内容深度足够&#xff0c;易于初学者理解&#xff0c;也给深度开发人员分享了…

CF773F Test Data Generation(倍增FFT/动态规划)

CF773F Test Data Generation https://www.luogu.com.cn/problem/CF773F 这个题还是挺巧妙的&#xff0c;最后需要我们求解的实际上值域为a选择奇数个数最大数是奇数的方案数&#xff0c;然后这个东西显然包含了3个信息&#xff0c;值域、个数、最后一个数的奇偶性&#xff0c…

2019-02-27-算法-进化(寻找两个有序数组的中位数)

题目描述 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数&#xff0c;并且要求算法的时间复杂度为 O(log(m n))。 你可以假设 nums1 和 nums2 不会同时为空。 示例 1: nums1 [1, 3] nums2 [2]则中位数是 2.0示例 2: nums1 [1, 2]…

.Net Core 三大Redis客户端对比和使用心得

前言稍微复杂一点的互联网项目&#xff0c;技术选型都可能会涉及Redis&#xff0c;.NetCore的生态越发完善&#xff0c;支持.NetCore的Redis客户端越来越多&#xff0c;下面三款常见的Redis客户端&#xff0c;相信大家平时或多或少用到一些&#xff0c;结合平时对三款客户端的使…

2020第十一届蓝桥杯软件类省赛第二场C/C++ 大学 B 组(题解)

试题 A: 门牌制作 问题描述 小蓝要为一条街的住户制作门牌号。 这条街一共有 2020 位住户&#xff0c;门牌号从 1 到 2020 编号。 小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符&#xff0c;最后根据需要将字 符粘贴到门牌上&#xff0c;例如门牌 1017 需要依次粘贴字符 …

队长开卖自家产“翠香”猕猴桃

猕猴桃品种有很多&#xff0c;但不是所有的果子都叫翠香。这两天我在公众号里卖了这个翠香猕猴桃&#xff0c;可能是有同学以为是做广告卖水果&#xff0c;其实是家里的亲戚猕猴桃成熟了&#xff0c;辛苦一年下来地里一共结了3000斤猕猴桃&#xff0c;遇到了一个难题就是如何把…

Java修炼之路——基础篇——Java集合类

集合类的全景图 常用集合类特性 1. Collection&#xff1a;每个位置对应一个元素1.1: List 存放有序元素&#xff0c;允许重复元素&#xff0c;允许元素为null1.1.1: ArrayList&#xff1a;内部结构为数组&#xff1b;初始容量为10&#xff1b;插入、删除的移动速度慢&#x…