首先认识到——String是不可以变性(final)

String:字符串,使用一对“”引起来表示。
     * 1.String声明为final的,不可被继承
     * 2.String实现了Serializable接口:表示字符串是支持序列化的。
     *         实现了Comparable接口:表示String可以比较大小
     * 3.String内部定义了final char[] value用于存储字符串数据
     * 4.String:代表不可变的字符序列。简称:不可变性。

理解不可变性

import org.junit.Test;

/**
* String的使用
*/
public class StringTest { /**
* String:字符串,使用一对""引起来表示。
* 1.String声明为final的,不可被继承
* 2.String实现了Serializable接口:表示字符串是支持序列化的。
* 实现了Comparable接口:表示String可以比较大小
* 3.String内部定义了final char[] value用于存储字符串数据
* 4.String:代表不可变的字符序列。简称:不可变性。
* 体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
* 2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
* 3.当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
* 5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
* 6.字符串常量池中是不会存储相同内容的字符串的。
*
*/
@Test
public void Test1(){
String s1 = "abc"; //字面量的定义方式
String s2 = "abc";
s1 = "hello"; System.out.println(s1 == s2);//比较s1和s2的地址值 System.out.println(s1);//hello
System.out.println(s2);//abc System.out.println("*********************"); String s3 = "abc";
s3 += "def";
System.out.println(s3);//abcdef System.out.println("**********************"); String s4 = "abc";
String s5 = s4.replace('a', 'm');
System.out.println(s4);//abc
System.out.println(s5);//mbc
}
}

String不同实例化方式的对比

String str = "hello";

//本质上this.value = new char[0];
String s1 = new String(); //this.value = original.value;
String s2 = new String(String original); //this.value = Arrays.copyOf(value, value.length);
String s3 = new String(char[] a); String s4 = new String(char[] a,int startIndex,int count);

String str1 = “abc”;与String str2 = new String(“abc”);的区别?

  • 字符串常量存储在字符串常量池,目的是共享
  • 字符串非常量对象存储在堆中

import org.junit.Test;

/**
* String的使用
*/
public class StringTest { /**
* String的实例化方式
* 方式一:通过字面量定义的方式
* 方式二:通过new + 构造器的方式
*
* 面试题:String s = new String("abc");方式创建对象,在内存中创建了几个对象?
* 两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"
*
*/
@Test
public void test2(){
//通过字面量定义的方式:此时的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 System.out.println("***********************");
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
}
}

/**
* @author subei
* @create 2020-05-09 11:20
*/
public class Person { String name;
int age; public Person(String name, int age) {
this.name = name;
this.age = age;
} public Person() { }
}

import org.junit.Test;

/**
* String的使用
*/
public class StringTest { /**
* 结论
* 1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
* 2.只要其中有一个是变量,结果就在堆中
* 3.如果拼接的结果调用intern()方法,返回值就在常量池中
*
*/
@Test
public void test4(){
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3);//false final String s4 = "javaEE";//s4:常量
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true } @Test
public void test3(){
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(s5 == 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 = s5.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
}
}

重点:其中"JAVAEE"和"hadoop"是自变量,s1和s2都是变量名
          有变量名参与,就相当于在堆中创建了,相当于new,如s5,s6,s7

1、String s1 = “a”;

说明:在字符串常量池中创建了一个字面量为"a"的字符串。

2、s1 = s1 + “b”;

说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1+“b”(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。

3、String s2 = “ab”;

说明:直接在字符串常量池中创建一个字面量为"ab"的字符串。

4、String s3 = “a” + “b”;

说明:s3指向字符串常量池中已经创建的"ab"的字符串。

5、String s4 = s1.intern();

说明:堆空间的s1对象在调用intern()之后,会将常量池中已经存在的"ab"字符串赋值给s4。

/**
* 一道面试题
*/
public class StringTest {
String str = new String("good");
char[] ch = { 't', 'e', 's', 't' }; public void change(String str, char ch[]) {
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//A
System.out.println(ex.ch);//best//B
}
}

在这里解释:

1.为什么//A输出来的是good——因为基本数据类型传输得是存储值,而引用数据类型传输得是地址值,而String类型是个引用数据类型,所以在chenge方法中,参数String str的地址值实际上跟String str = new String("good")地址值一样,且是不能改变的,且good在常量池当中,而当A输出的则是地址值,所以出来的是good而不是test ok!

2.为什么B输出来的却是best——因为char是个基本数据类型,在堆中显示test,是可以改变地址值的,所以输出来的是best!

JVM中涉及字符串的内存结构

String的常用方法1

package doy1;

import org.junit.Test;

/**
* @author shkstart
* @create 2021-10-25 22:23
*/
public class zuoye1 {
/**
* 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 equals IgnoreCase(String anotherString):与equals方法类似,忽略大小写
* String concat(String str):将指定字符串连接到此字符串的结尾。等价于用“+”
* int compareTo(String anotherString):比较两个字符串的大小
* String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
* String substring(int beginIndex,int endIndex):返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
*/
//实则StringMethodTest
@Test
public void test2(){
String s1 = "HelloWorld";
//0123456789
String s2 = "helloworld";
System.out.println(s1.length());//10
System.out.println(s1.equals(s2));//false
System.out.println(s1.equalsIgnoreCase(s2));//true
/*
boolean equals(Object obj):比较字符串的内容是否相同
boolean equals IgnoreCase(String anotherString):与equals方法类似,忽略大小写
*/
System.out.println("***************");
String s3 = "abc";
String s4 = s3.concat("def");
System.out.println(s4);//abcdef
/*
String concat(String str):将指定字符串连接到此字符串的结尾。等价于用“+”
*/
System.out.println("***************");
String s5 = "abc";
String s6 = new String("abe");
System.out.println(s5.compareTo(s6));//-2 //涉及到字符串的排序,比如a==97,c==99,e==101
/*
int compareTo(String anotherString):比较两个字符串的大小
*/
System.out.println("***************");
String s7 = "周围好吵啊";
//0 1 2 3 4
String s8 = s7.substring(2);
System.out.println(s7);//因为String的不可变性,所以依然为周围好吵啊
System.out.println(s8);//好吵啊
/*
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
String substring(int beginIndex,int endIndex):返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串
*/
String s9 = s7.substring(0, 2);
System.out.println(s9);//周围,
/*String substring(int beginIndex,int endIndex):
返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
关于这里为什么输出的是周围——可以s7.substring(0, 2);是一个左闭右开区间,[2,0),
*/
}
/**
* 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():返回字符串的副本,忽略前导空白和尾部空白*/
@Test
public void Test1(){
String s1 = "Helloworld";
//0123456789
System.out.println(s1.length());
System.out.println(s1.length());
System.out.println(s1.charAt(0));
System.out.println(s1.charAt(9));
// System.out.println(s1.charAt(10));超过的话,那么就会出现报错
// s1 = "";
System.out.println(s1.isEmpty());//false---->不是空字符串 String s2 = s1.toLowerCase();
System.out.println(s1);//s1不可变的,仍然为原来的字符串
System.out.println(s2);//改成小写以后的字符串 String s3 = " he llo world ";
String s4 = s3.trim();
System.out.println("-----" + s3 + "-----");
System.out.println("-----" + s4 + "-----"); } }

String的常用方法2

package doy1;

/**
* @author shkstart
* @create 2021-10-24 13:07
*/
import org.junit.Test; public class StringMethodTest1 { /**
* 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
*/
@Test
public void test3(){
String str1 = "helloworld";
// 0123456789
boolean b1 = str1.endsWith("rld");
System.out.println(b1);//true boolean b2 = str1.startsWith("He");
System.out.println(b2);//false boolean b3 = str1.startsWith("ll",2);
System.out.println(b3);//true
/*
* 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
* */
//String str1 = "helloworld";
// 0123456789
String str2 = "wor";
// 0123456789
System.out.println(str1.contains(str2));//true System.out.println(str1.indexOf("lo"));//3 System.out.println(str1.indexOf("lo",5));//-1
//注:indexOf和lastIndexOf方法如果未找到都是返回-1
//为什么会出现-1?——因为指定的索引是5,所以从5开始往后面找,但是找不到lo,所以就得返回值是—— -1
String str3 = "hellorworld";
// 0123456789
System.out.println(str3.lastIndexOf("or"));//7--->返回指定子字符串在此字符串中最右边出现处的索引
System.out.println(str3.lastIndexOf("or",6));//4
//为什么出现的是4?——因为指定的索引为6,所以就得从6开始从后往前找,所以就是4
//什么情况下,indexOf(str)和lastIndexOf(str)返回值相同?
//情况一:存在唯一的一个str。情况二:不存在str
}
}

String的常用方法3

package doy1;

/**
* @author shkstart
* @create 2021-10-24 20:53
*/
import org.junit.Test; public class StringMethodTest2 { /**
* 替换:
* 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个,如果超过了,剩下的全部都放到最后一个元素中。
*
*/
@Test
public void test4(){
String str1 = "北京欢迎您";
String str2 = str1.replace('北','东'); System.out.println(str1);
System.out.println(str2); String str3 = str1.replace("北京", "南京");
System.out.println(str3); System.out.println("*************************");
String str = "12hello34world5java7891mysql456";
//把字符串中的数字替换成,,如果结果中开头和结尾有,的话去掉
String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(string); System.out.println("*************************");
str = "12345";
//判断str字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches = str.matches("\\d+");
System.out.println(matches);
String tel = "0571-4534289";
//判断这是否是一个杭州的固定电话
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result); System.out.println("*************************");
str = "hello|world|java";
String[] strs = str.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
System.out.println();
str2 = "hello.world.java.java";
String[] strs2 = str2.split("\\.");
for (int i = 0; i < strs2.length; i++) {
System.out.println(strs2[i]);
}
System.out.println();
str3 = "hello.world.java.java.aff.cfafa";
String[] strs3 = str3.split("\\.",3);
for (int i = 0; i < strs2.length; i++) {
System.out.println(strs3[i]);
}
}
}

JAVA基础——常用类(一)的更多相关文章

  1. Java基础常用类深度解析(包含常见排序算法)

    目录 一.工具类 1.1.工具类的设计 1.1.1.公共静态方法 1.2.单例模式 二.包装类 2.1.基本类型的包装类 2.1.1.Integer 2.1.1.1.Integer >> ...

  2. java基础---常用类

    一.字符串类String String:字符串,使用一对""引起来表示,字符串常量池在方法区中 public final class String implements java. ...

  3. JAVA基础--常用类 String,StringBuffer, 基础数据类型包装类, Math类, Enum类

    字符串相关类: String, StringBuffer String类为不可变的字符序列 String s1="hello"; String s2="hello&quo ...

  4. Java基础——常用类之日期时间类

    如果有机会,请尝试Java8中全新的时间日期API!(参见Java8新特性随笔) 如果还是使用Java7及之前的版本,那么你可以尝试一些工具类(参考使用工具类相关的Hutool-DateUtil) 如 ...

  5. Java基础——常用类(Date、File)以及包装类

    本文要点: 基本数据类型的包装类 字符串相关类: 不可变字符序列:String 可变字符序列:StringBuffer.StringBuilder 时间处理相关类: Date DateFormat.S ...

  6. Java基础—常用类之String类

    一.String类是什么 public final class String implements java.io.Serializable, Comparable<String>, Ch ...

  7. java基础-Integer类常用方法介绍

    java基础-Integer类常用方法介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在实际程序使用中,程序界面上用户输入的数据都是以字符串类型进行存储的.而程序开发中,我们需 ...

  8. Java基础-StringBuffer类与StringBuilder类简介

    Java基础-StringBuffer类与StringBuilder类简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.StringBuffer类 在学习过String类之后 ...

  9. Java API 常用类(一)

    Java API 常用类 super类详解 "super"关键字代表父类对象.通过使用super关键字,可以访问父类的属性或方法,也可以在子类构造方法中调用父类的构造方法,以便初始 ...

  10. 第二十九节:Java基础知识-类,多态,Object,数组和字符串

    前言 Java基础知识-类,多态,Object,数组和字符串,回顾,继承,类的多态性,多态,向上转型和向下转型,Object,数组,多维数组,字符串,字符串比较. 回顾 类的定义格式: [类的修饰符] ...

随机推荐

  1. 每日一题_1_x^n

    函数头为double power(double x,int n).在主函数中输入x.n并调用该函数求 (函数定义在主函数后面,在调用前做函数声明) 输出x^n 1 #define _CRT_SECUR ...

  2. Think in UML 其二

    UML基本元素 参与者 1.参与者位于系统边界之外. 思考参与者究竟是谁时,以下两个问题有助于了解 ·谁对系统有着明确的目标和要求并且主动发出动作? ·系统是为谁服务的? 2.参与者可以非人 功能性需 ...

  3. PLC入门笔记10

    梯形图电路之顺序控制 顺序控制功能图 顺序控制功能图的梯形图表达 编程原则 实例分析 SMo0.1西门子首次扫描时为ON,常用作初始化脉冲 这是台达的 这是优控的..

  4. SQL Server 还原数据库

    1.备份要还原的数据库 选择要备份的数据库,右键单击,任务--备份. 2.备份完成后,将数据库还原 3.新建一个空的数据库,比如Gsy_TestNew,将备份的数据库还原到这个新的库上 4.右键单击[ ...

  5. redis 常用指令

    redis指令有些相似,记忆起来不太容易,在此做一下整理 序号 类型 指令 参数 作用 例子 1 string set key value 存储一个 string 类型的值 set a aa 2 st ...

  6. Ubuntu实战

    Ubuntu是什么 Ubuntu早期是一个由Debian Linux发展起来的以桌面应用为主的操作系统.作为Linux发行版中的后起 之秀,Ubuntu Linux在短短几年时间里便迅速成长为从Lin ...

  7. jmeter&badboy安装

    一.jmeter下载地址: 1. http://jmeter.apache.org/download_jmeter.cgi   \  https://www.apache.org/dist/jmete ...

  8. Cookie 设置 添加 删除 修改

    置cookie 如果设置domin    后面的域名前面就会有.  <script>//设置cookiefunction setCookie(cname, cvalue, exdays)  ...

  9. vue引入多个指令文件

    单个指令引入,在main.js(入口JS文件)中引入你已经写好的指令文件,可以省略文件后缀: // main.js import focus from 'xxx/directive'多个指令引入 Vu ...

  10. Docker 容器与镜像

    列出所有容器ID :docker ps -aq 查看所有运行或者不运行容器:docker ps -a 停止所有的container(容器),这样才能够删除其中的images:docker stop $ ...