String 类声明为 final 的,不可被继承。
String 类实现了 Serializable 接口:表示字符串是支持序列化的。实现了 Comparable 接口:表示 String 可以比较大小的。
String 内部定义了 final char[] value 用于存储字符串数据。( JDK8 与 JDK8 之前版本 )
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
...
}
String:代表不可变的字符序列。简称:不可变性。
体现:
(1)当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的 value 进行赋值。
(2)当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的 value 进行赋值。
(3)String 的 replace() 方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的 value 进行赋值。
通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
字符串常量池中是不会存储相同内容的字符串的。
public class test1{
public static void main(String[] args){
// 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
String s1 = "abc"; //字面量的定义方式
String s2 = "abc";
System.out.println(s1 == s2); //比较s1和s2的地址值:true
s1 = "hello";
System.out.println(s1 == s2); //比较s1和s2的地址值:false
System.out.println(s1); //hello
System.out.println(s2); //abc
// 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
String s3 = "abc";
s3 += "def";
System.out.println(s3); //abcdef
System.out.println(s2); //abc
// String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
String s4 = "abc";
String s5 = s4.replace('a', 'm');
System.out.println(s4); //abc
System.out.println(s5); //mbc
}
}
方式一:通过字面量定义的方式
方式二:通过 new + 构造器的方式
public class test2{
public static void main(String[] args){
//通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
String s1 = "javaEE";
String s2 = "javaEE";
//通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); //false
System.out.println(s1 == s4); //false
System.out.println(s3 == s4); //false
Person p1 = new Person("Tom",12);
Person p2 = new Person("Tom",12);
System.out.println(p1.name.equals(p2.name)); //true
System.out.println(p1.name == p2.name); //true
p1.name = "Jerry";
System.out.println(p2.name);//Tom
}
}
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}


面试题:String s = new String("abc");方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间中 new 结构,另一个是 char[] 对应的常量池中的数据:"abc"。
public class test3{
public static void main(String[] args){
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4); //true
System.out.println(s3 == s5); //false
System.out.println(s3 == s6); //false
System.out.println(s3 == s7); //false
System.out.println(s5 == s6); //false
System.out.println(s5 == s7); //false
System.out.println(s6 == s7); //false
String s8 = s6.intern(); //返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
System.out.println(s3 == s8); //true
final String s9 = "xiaozhao";
String s10 = s9 + "java";
String s11 = "xiaozhaojava";
System.out.println(s10 == s11); //true(原因:s9用final修饰,类似于常量,存储在常量池中)
}
}
/*
s1 = s1 + "b";
说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1+"b"(也就是"ab")。如果多次执行这些改变串内容的 操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。
*/
特殊例子:
public class StringTest {
String str = new String("good");
char[] ch = { 't', 'e', 's', 't' };
public void change(String str, char ch[]) { // 将实参str和ch的地址值传递给形参str和ch
// this.str = "test ok"; 如果使用该语句,则ex.str输出为 test ok
str = "test ok";
System.out.println(str); // test ok
ch[0] = 'b';
}
public static void main(String[] args) {
StringTest ex = new StringTest();
ex.change(ex.str, ex.ch);
System.out.println(ex.str); // good
System.out.println(ex.ch); // best
}
}

int length():返回字符串的长度:return value.length
char charAt(int index):返回某索引处的字符:return value[index]
boolean isEmpty():判断是否是空字符串:return value.length == 0
String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
String trim():返回字符串的副本,忽略前导空白和尾部空白
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
int compareTo(String anotherString):比较两个字符串的大小
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
public class test1 {
public static void main(String[] args){}
String s1 = "HelloWorld";
System.out.println(s1.length()); // 10
System.out.println(s1.charAt(0)); // H
System.out.println(s1.isEmpty()); // false
String s2 = s1.toLowerCase();
System.out.println(s1); // HelloWorld(s1不可变的,仍然为原来的字符串)
System.out.println(s2); // helloworld(改成小写以后的字符串)
String s3 = " he llo world ";
String s4 = s3.trim();
System.out.println(s3); // he llo world
System.out.println(s4); // he llo world
String s5 = "helloworld";
System.out.println(s1.equals(s5)); // false
System.out.println(s1.equalsIgnoreCase(s5)); // true
String s6 = s1.concat("ByJava");
System.out.println(s6); // HelloWorldByJava
String s7 = "abc";
String s8 = new String("abe");
System.out.println(s7.compareTo(s8));// -2
String s9 = "小钊学Java";
String s10 = s9.substring(2);
System.out.println(s9); // 小钊学Java
System.out.println(s10); // 学Java
String s11 = s9.substring(1, 4);
System.out.println(s11); // 钊学J
}
}
boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
// 注:indexOf和lastIndexOf方法如果未找到都是返回-1
public class test2{
public static void main(String[] args){
String s1 = "zhaohelloworldzhao";
boolean b1 = s1.endsWith("zhao");
System.out.println(b1); // true
boolean b2 = s1.startsWith("Zhao");
System.out.println(b2); // false
boolean b3 = s1.startsWith("hello",4);
boolean b4 = s1.startsWith("hello",5);
System.out.println(b3); // true
System.out.println(b4); // false
String s2 = "zhao";
System.out.println(s1.contains(s2)); // true
System.out.println(s1.indexOf("zhao")); // 0
System.out.println(s1.indexOf("zhao",1)); // 14
System.out.println(s1.lastIndexOf("zhao")); // 14
System.out.println(s1.lastIndexOf("zhao",6)); // 0
// 什么情况下,indexOf(str)和lastIndexOf(str)返回值相同?
// 情况一:存在唯一的一个str。情况二:不存在str,均等于-1。
}
}
// 替换
String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String replaceAll(String regex, String replacement) :使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
String replaceFirst(String regex, String replacement) :使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
// 匹配
boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
// 切片
String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过 limit 个,如果超过了,剩下的全部都放到最后一个元素中。
public class test3{
public static void main(String[] args){
String s1 = "小钊学Java小钊";
String s2 = s1.replace('钊', '明');
System.out.println(s1); // 小钊学Java小钊
System.out.println(s2); // 小明学Java小明
String s = "12hello34world5java7891xiaozhao456";
//把字符串中的数字替换成!,如果结果中开头和结尾有!的话去掉
String s3 = s.replaceAll("\\d+", "!");
String s4 = s.replaceAll("\\d+", "!").replaceAll("^,|,$", "");
System.out.println(s3); // !hello!world!java!xiaozhao!
System.out.println(s4); // hello!world!java!xiaozhao
String s5 = "12345";
//判断s5字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches = s5.matches("\\d+");
System.out.println(matches); // true
String tel = "020-4534289";
//判断这是否是一个广州的固定电话,且-后的号码为7-8位
boolean result = tel.matches("020-\\d{7,8}");
System.out.println(result); // true
String s6 = "hello|world|java";
String[] strs = s6.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.print(strs[i] + " "); // hello world java
}
System.out.println();
String s7 = "hello.world.java";
String[] strs2 = s7.split("\\.");
for (int i = 0; i < strs2.length; i++) {
System.out.print(strs2[i] + " "); // hello world java
}
}
}
字符串 >> 基本数据类型、包装类
Integer 包装类的 public static int parseInt(String s):可以将由“数字”字符组成的字符串转换为整型。
类似地,使用 java.lang 包中的 Byte、Short、Long、Float、Double 类调相应的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
基本数据类型、包装类 >> 字符串
调用 String 类的 public String valueOf(int n) 可将 int 型转换为字符串
相应的 valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b) 可由参数的相应类型到字符串的转换
public class test1{
public static void main(String[] args){
String str1 = "123";
// int num = (int)str1;//错误的
int num = Integer.parseInt(str1);
String str2 = String.valueOf(num); // "123"
String str3 = num + "";
System.out.println(str1 == str3); // false(str3为堆地址值,str1为"123"在字符常量池的地址值)
}
}
public class test2{
public static void main(String[] args){
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.print(charArray[i] + " "); // a b c 1 2 3
}
char[] arr = new char[]{'h','e','l','l','o'};
String str2 = new String(arr);
System.out.println(str2); // hello
}
}
@Test
public void test3() throws UnsupportedEncodingException {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes(); // 使用默认的字符集,进行编码。
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk"); // 使用gbk字符集进行编码。
System.out.println(Arrays.toString(gbks));
String str2 = new String(bytes); // 使用默认的字符集,进行解码。
System.out.println(str2);
String str3 = new String(gbks);
System.out.println(str3); // 出现乱码。原因:编码集和解码集不一致!
String str4 = new String(gbks, "gbk");
System.out.println(str4); // 没有出现乱码。原因:编码集和解码集一致!
}
java.lang.StringBuffer 代表可变的字符序列,JDK1.0 中声明,可以对字符串内容进行增删,此时不会产生新的对象。
很多方法与String相同。
作为参数传递时,方法内部可以改变值。
StringBuffer 类不同于 String,其对象必须使用构造器生成。有三个构造器:
StringBuffer():初始容量为16的字符串缓冲区。char[] value = new char[16];
StringBuffer(int size):构造指定容量的字符串缓冲区。
StringBuffer(String str):将内容初始化为指定字符串内容。
StringBuffer 类的常用方法:
StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx
StringBuffer reverse():把当前字符序列逆转
public int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
public String substring(int start,int end):返回一个从start开始到end索引结束的左闭右开区间的子字符串
public int length():返回字符串的(有效)长度
public char charAt(int n ):返回某索引处的字符
public void setCharAt(int n ,char ch):修改n索引处的字符为ch
public class test1{
public static void main(String[] args){
StringBuffer s1 = new StringBuffer("abc");
s1.setCharAt(0,'m');
System.out.println(s1); // mbc
StringBuffer s2 = new StringBuffer();
System.out.println(s2.length()); // 0
s1.append(1);
s1.append('1');
System.out.println(s1); // mbc11
// s1.delete(2,4); // mb1
// s1.replace(2,4,"hello"); // mbhello1
// s1.insert(2,false); // mbfalsec11
// s1.reverse(); // 11cbm
String s2 = s1.substring(1, 3);
System.out.println(s1); // mbc11
System.out.println(s1.length()); // 5
System.out.println(s2); // bc
}
}
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样。
面试题:对比 String、StringBuffer、StringBuilder
String:不可变的字符序列;底层使用 char[] 存储
StringBuffer:可变的字符序列;线程安全的,效率低;底层使用 char[] 存储
StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用 char[] 存储
注意:作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder 会改变其值。
StringBuffer 类和 StringBuilder 类初始容量均为 16 的字符串缓冲区,如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。默认情况下,扩容为原来容量的 2 倍加 2,同时将原有数组中的元素复制到新的数组中。
因此开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity) 。
对比 String、StringBuffer、StringBuilder 三者的效率:
从高到低排列:StringBuilder > StringBuffer > String
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.
Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur