课程大纲 | 课程内容 | 学习效果 | 掌握目标 |
面向对象 | Static关键字 | 掌握 | 熟练掌握static的含义和用法 |
String类 | 掌握 | 熟练掌握String类型的原理和使用方式 | |
字符串缓冲区StringBuilder | 掌握 | 熟练掌握StringBuilder的原理和使用方式 |
一、static关键字
1、问题引入
如果某个类型的所有对象,都具有一个相同的属性值,那么这个属性值就没有必要在所有对象中,都存储一份。坏处:浪费内存空间;维护难度大,一旦需要修改,就得修改所有的对象。如何解决这个问题呢?
当在定义类的时候,类中都会有相应的属性和方法。而属性和方法都是通过创建本类对象调用的。当在调用对象的某个方法时,这个方法没有访问对象的特有数据(属性——成员变量)时,创建这个对象有些多余。可是不创建对象,方法又调用不了,这时就会想,那么我们能不能不创建对象,就可以调用方法呢?
不使用static关键字
示例代码
public class Student {
private int id; private String name; private int age; private String country="中国";
public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
内存图景
|
2、static关键字概述(静态)
static关键字可以用于修饰类的成员变量、方法和代码块。
static修饰的变量称为静态变量。
static修饰的方法称为静态方法。
static修饰的初始化代码块,称为静态初始化块。
static修饰类,静态内部类(后面讲)
3、静态变量
用static修饰的变量叫做静态变量(类变量)。
静态变量的特征:类的所有对象共享同一个静态变量。
例如:static int x
案例:修改上面例子,把国家修改成静态变量
public class Student { private int id; private String name; private int age; static String country="中国"; // 静态变量 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void sayHello(){ System.out.println("hello..."); } public int add(in |
内存图景
|
(1)静态变量的特点
静态的解释:static关键字
静态、静止的。静态变量不会随着对象的变化而变化。
加载时机:
随着类的加载而加载。
静态变量随着类的加载进方法区,就直接在静态区给开辟了存储静态变量的内存空间。
静态变量优先于对象而存在。
静态变量被所有该类对象所共享。
代码层面:
可以使用类名直接调用,不需要使用对象名称。在不创建对象的前提下,仍然可以使用这个静态变量。建议使用类名来访问。
(2)静态变量和非静态变量的区别
- 概念上,所属不同:
非静态变量属于对象。
静态变量属于类,类变量。
- 内存空间不同,存储位置不同
非静态变量属于对象,所以存储在堆内存中。
静态变量属于类,存储在方法区的静态区中。
- 内存时间不同,生命周期不同
非静态变量属于对象,所以生命周期和对象相同,随着对象的创建而存在,随着对象的消失而消失。
静态变量属于类,所以生命周期和类相同,随着类的加载(创建对象、类名访问静态变量、类名访问静态方法、反射的方式、加载子类、运行某个测试类)而存在,随着类的消失(内存管理)而消失。
- 访问方式不同
非静态变量只能使用对象名访问。
静态变量既可以使用对象访问,也可以通过类名访问:
类名.静态变量名
类名.静态方法名()
4、静态方法
当static 修饰成员方法时,该方法称为类方法或静态方法。静态方法在声明中有static ,建议使用类名来直接调用,而不需要创建类的对象。调用方式非常简单。
(1)语法格式
格式:
修饰符 static 返回值类型 方法名 (参数列表){ // 执行语句 } |
举例:在Student类中定义静态方法
public static void showNum() { System.out.println("num:" + autoIncrementNum); } |
(2)静态方法调用的注意事项
静态方法可以直接访问静态变量和静态方法。(静态可以访问静态)
静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。(静态不能访问非静态)
静态方法中,不能使用this关键字。
静态方法只能访问静态成员。(静态可以访问静态)(静态不能访问非静态)
示例代码
public class Student { private int id; private String name; private int age; static String country="中国"; // 静态变量 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public static void sayHello(){ System.out.println("hello..."+country); //静态方法中可以直接访问静态成员 //System.out.println(name);静态方法中,不能方法非静态成员(成员变量和成员方法) //add(1,2); } public void introduce(){ System.out.println("我是"+name+" 来自"+country); // 非静态方法中可以直接方法静态成员 } public int add(int a,int b){ return a+b; } } |
(3)调用格式
被static修饰的成员可以并且建议通过类名直接访问。虽然也可以通过对象名访问静态成员,原因即多个对象均属于一个类,共享使用同一个静态成员,但是不建议,会出现警告信息。
格式
// 访问类变量 类名.类变量名; // 调用静态方法 类名.静态方法名(参数); |
示例代码
public static void main(String[] args) { Student stu1 = new Student(); Student stu2 = new Student(); /* System.out.println(stu1.country); System.out.println(stu2.country); */ //System.out.println(Student.country); // 静态变量 是不属于任何一个对象的,直接属于类 stu1.sayHello(); stu2.sayHello(); stu1.add(1,2); Student.sayHello(); //静态方法可以通过类名直接调用 //Student.add(1,2); 不能通过类名直接调用成员方法(非静态方法) } |
5、静态初始化块
static 修饰的初始化块
特征:在类加载时,只会执行一次
例如: static{}
示例代码
{ // 初始化代码块——每创建一个对象,就会执行一次 System.out.println("初始化代码块"); }
static{ // 静态代码块——在类加载时,只会执行一次 System.out.println("静态初始化代码块"); } |
6、案例
案例1:使用static 完成 投票功能。
最多有5个人投票,定义投票人的类(voter),
在这个类中定义一个投票的方法,当票数超过5时,提示不能再投票。
public class Voter { private static int num; //静态变量,所有对象共享 public void vote(){ if(num>=5){ System.out.println("票数已满"); }else{ num++; System.out.println("已投"+num+"票"); } } } |
案例2:使用计数器num统计创建User对象的个数(提示构造方法里对num进行自加操作)
public class User { private static int num; //计数——static的,所有对象共享 public User(){ num++; System.out.println("已创建"+num+"个对象"); } } |
案例3: 定义一个int类型数组操作的工具类,MyArrays。方法包括:
最大值,最小值,升序排列,求和方法
public class MyArrays{ // 作业
/* * 定义一个int类型数组操作的工具类,MyArrays。方法包括: 最大值,最小值,升序排列,求和方法 * */
//获取最大值 public static int getMax(int[] aa){ int max = aa[0]; //假设 for(int i=0;i<aa.length;i++){ if(aa[i]>max){ max = aa[i]; } } return max; } //获取最小值 public static int getMin(int[] aa){ int min = aa[0]; //假设 for(int i=0;i<aa.length;i++){ if(aa[i]<min){ min = aa[i]; } } return min; } //排序 public static void sort(int[] aa){ for(int i=0;i<aa.length;i++){ for(int j=0;j<aa.length-1-i;j++){ if(aa[j]>aa[j+1]){
int temp = 0; temp = aa[j]; aa[j] = aa[j+1]; aa[j+1]=temp;
} } } } //求和 public static int getSum(int[] aa){ int sum = 0; //增强型for循环(foreach循环) for(int x:aa){ sum = sum+x; } return sum; } } |
7、static特征总结
1 静态方法中不能访问非静态成员变量和成员方法(非静态方法可以方法静态变量) -非静态方法可以访问静态成员变量和静态方法
2 静态方法中不能使用this关键字
3 随着类的加载而加载,静态会随着类的加载而加载,随着类的消失而消失。说明它的生命周期很长。
4 优先于对象存在。-->静态是先存在,对象是后存在。
5 被所有实例(对象)所共享。
6 可以直接被类名调用
静态变量(类变量)和实例变量的区别:
存放位置
1:类变量随着类的加载而加载存在于方法区中.
2:实例变量随着对象的建立而存在于堆内存中.
生命周期
1:类变量生命周期最长,随着类的消失而消失.
2:实例变量生命周期随着对象的消失而消失.
静态优缺点
1:优点:对对象的共享数据进行单独空间的存储,节省空间
2:缺点:生命周期过长
访问出现局限性。(静态只能访问静态)
什么时候定义静态变量
1:静态变量(类变量)当对象中出现共享数据
例如:学生的学校名称。学校名称可以共享
对象的数据要定义为非静态的存放在对内存中(学生的姓名,学生的年龄)
什么时候定义静态方法
如果功能内部没有访问到非静态数据(对象的特有数据。那么该功能就可以定义为静态)
8、单例模式(Singleton)
GOF的23种设计模式中的一种。
一些人总结出来用来解决特定问题的固定的解决方案。
解决一个类在内存中只能存在一个对象,想要保证对象的唯一。
1 为了避免其他程序过多的建立该类对象。禁止其他程序建立该类对象。
2 为了其他程序可以访问该类对象,在本类中自定义一个对象。
3 方便其他程序对自定义类的对象的访问,对外提供一些访问方式。
方式:
1将构造方法私有化。
2在类中创建一个私有的本类对象。
3提供一个用类名调用的公有方法获取该对象。
示例代码
class Single { private static Single s = new Single(); // 饿汉式 private Single() { } public static Single getInstance() { return s; } } class Single2 { private static Single2 s = null; // 懒汉式 private Single2() { } public static Single2 getInstance() { if (s == null) { s = new Single2(); } return s; } } |
二、String类
1、概述
- String就是字符串类型,属于java.lang包,不需要导包。
- 所有的字符串常量(“Hello World”、”abc”)都属于String类型的对象。
- 字符串字面值属于常量,存储在方法区的常量池中。
- String类型在创建之后就无法更改(是一个不可变的字符序列)。
- 不可变的原因是String类型只提供了构造方法,没有提供set方法,因此只能在创建对象的时候,初始化成员变量,将来对象创建完成之后,无法通过方法来修改。
public static void main(String[] args) { String str1 = "abc"; System.out.println(str1); str1 = "xyz"; System.out.println(str1); // 不可变? 可变?——str1是引用,是内存地址。这里指的不可变是字符串(在内存中的字符串内容不会改变) } |
2、常量池
任何好的编程语言的关键目标之一是高效的使用内存。随着应用程序的增长,String字面值占用大量的内存非常常见。对程序而言,全部String字面值中往往有大量的冗余,为了使Java更高效地使用内存,JVM留出一块特殊的内存区域,称为“String常量池”。当编译器遇到String字面值时,它检查该池内是否已经存在相同的String字面值。如果找到,则将新的字面值的引用指向现有的String,而不创建任何新的String字面值对象。
3、String类常见的构造方法
- String():创建一个空字符串
2、String(String original):创建参数字符串的一个副本(参数字符串是在常量池中,构造方法创建的字符串是在堆内存中)。
3、String(byte[] arr):将一个字节数组转成一个字符串。
将我们不认识的字节数组,转成了我们认识的字符串,过程叫做【解码】。
查询的是当前平台默认的编码表。
4、String(byte[] arr, int offset, int length):将字节数组的一部分转成字符串
5、String(char[] arr):将字符数组转成字符串。
既不是编码,也不是解码,只不过是把字符数组转成了字符串
- String(char[] arr, int offset, int length):将字符数组的一部分转成字符串。
示例代码
public static void main(String[] args) { /* String str = new String(); // 创建了一个空串 "" //String str = ""; System.out.println(str);
String str2 = new String("abc"); //String str2 = "abc"; System.out.println(str2); */ String str1 = "abc"; // 内存中有几个对象??? 一个——常量池中 String str2 = "abc"; // 内存中有几个对象??? 一个 String str3 = new String("abc"); //两个,一个在堆区,一个在常量池 System.out.println(str1==str2); //true System.out.println(str1==str3); //false } |
public static void main(String[] args) { //byte[] b = new byte[]{}; String str = new String(new byte[]{65,66,67,68,69}); System.out.println(str); String str2 = new String(new byte[]{65,66,67,68,69},2,3);//从第几个元素开始,取几个 System.out.println(str2); String str3 = new String(new char[]{'a','b','c','d','e'}); System.out.println(str3); String str4 = new String(new char[]{'a','b','c','d','e'},2,3); System.out.println(str4); } |
4、内存图
|
|
5、String类的方法介绍
(1)API
概述
API(Application Programming Interface),应用程序编程接口。
Java API是一本程序员的字典 ,是JDK中提供给我们使用的类的说明文档。这些类将底层的代码实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可。所以我们可以通过查询API的方式,来学习Java提供的类,并得知如何使用它们。
使用步骤
1.打开帮助文档。
2.点击显示,找到索引,看到输入框。
3.你要找谁?在输入框里输入,然后回车。
4.看包。java.lang下的类不需要导包,其他需要。
5.看类的解释和说明。
6.学习构造方法。
7.使用成员方法。
演示
使用API文档查看之前使用过的Scanner类和Random类
(2)判断功能的方法
|
示例代码
String s1 = "aaa"; String s2 = new String("aaa"); System.out.println(s1.equals(s2));
//判断键盘输入的值是否为admin Scanner sc = new Scanner(System.in); String str = sc.nextLine();
System.out.println(str=="admin"); System.out.println("admin".equals(str)); //常量和变量使用equals比较内容时,尽量把常量写在前面
//equalsIgnoreCase 忽略大小写的比较 String str1 = "aaa"; String str2 = "AAA"; System.out.println(str1.equals(str2)); System.out.println(str1.equalsIgnoreCase(str2));
//contains 判断字符串是否包含某内容(子串) String str = "abcde"; System.out.println(str.contains("ab")); System.out.println(str.contains("cde")); System.out.println(str.contains("ac"));
// startsWith endsWith 判断字符串是否以某个值开头,是否以某个值结尾 String str="http://www.sina.com.cn";
System.out.println(str.startsWith("h")); System.out.println(str.startsWith("http")); System.out.println(str.startsWith("http://www.sina.com.cn")); System.out.println(str.startsWith("a"));
System.out.println(str.endsWith("cn")); System.out.println(str.endsWith(".cn"));
// isEmpty 判断字符串是否 为空串 String str1 = ""; String str2 = new String(); String str3 = new String(""); String str4 = " ";
System.out.println(str1.isEmpty()); System.out.println(str2.isEmpty()); System.out.println(str3.isEmpty()); System.out.println(str4.isEmpty());
|
(3)获取功能的方法
注意事项:1、包含头不包含尾,返回的结果中,不包含endIndex索引指向的字符;2、所有的方法都无法修改字符串对象本身,一般都是返回一个新的字符串对象
indexOf(int ch):返回ch字符在当前调用者字符串中,第一次出现的索引 indexOf(int ch, int fromIndex):从fromIndex索引开始寻找,找到ch字符在当前字符串中第一次出现的索引 indexOf(String str):返回的是str这个字符串在调用者字符串中第一次出现的索引 indexOf(String str, int fromIndex):从fromIndex索引开始寻找,找到str字符串在当前字符串中第一次出现的索引(注意:无论从哪个位置开始找,所有字符的索引都不会变化) 6、lastIndexOf家族: 和IndexOf基本一样,只不过是从后往前找,所有字符和字符串的索引也都不会发生变化 |
示例代码
public class Demo05_String类的常用方法_获取功能的方法 { public static void main(String[] args) { /* // 1 length() 获取字符串长度(由多少个字符组成) String str = "abc"; int x = str.length(); System.out.println(x); */
/* //2 charAt 获取某个位置上的字符 String str = "abcde"; char c = str.charAt(1); System.out.println(c); */ /* //3 substring 截取子串 String str = "abcdefg"; String result = str.substring(2); //取到最后 System.out.println(result); String result2 = str.substring(2,4); // 左闭右开 System.out.println(result2);
*/ /* //4 indexOf 查找位置 String str = "abcdeabcd"; int idx = str.indexOf("cd"); System.out.println(idx);
int idx2 = str.indexOf("ab",3); //int idx2 = str.indexOf("ab",-3);// 第2个参数为负数,相当于0 System.out.println(idx2);
int idx3 = str.indexOf("xy"); System.out.println(idx3); // 找不到时,返回-1
*/ /* //5 lastIndexOf 查找位置 从后向前找 String str = "abcdeabcd";
int idx = str.lastIndexOf("cd"); System.out.println(idx);
int idx2 = str.lastIndexOf("ab",3); System.out.println(idx2);
int idx3 = str.lastIndexOf("xy"); System.out.println(idx3); // 找不到时,返回-1 */ } } |
(4)转换功能方法
|
示例代码
public class Demo06_String类常用方法_转换功能的方法 { public static void main(String[] args) { /* // 1 getBytes() 将字符串转换成字节数组 String str = "abcd"; byte[] b = str.getBytes(); for(byte bb:b){ System.out.println(bb); } */ /* // 2 toCharArray() 将字符串转成字符数组 String str = "abcd"; char[] cc = str.toCharArray();
for(char c:cc){ System.out.println(c); } */
/* // 3 toUpperCase 小写转大写 String str = "abcd";
String str2 = str.toUpperCase(); System.out.println(str2);
*/ /* //4 toLowerCase 大写转小写 String str = "AbCd"; String str2 = str.toLowerCase(); System.out.println(str2);
*/
/* //5 concat 用来拼接字符串 和 +的作用相同 . 不同点: + 可以加任何类型 而concat只能拼接字符串 String s1 = "aaa"; String s2 = "bbb"; String s3= s1.concat(s2); System.out.println(s3);
*/ /* //6 valueOf 将其他类型转换成字符串 静态方法
int x = 100; String str = String.valueOf(x); System.out.println(str+1); // "1001"
int y = 200; String str2 = y+""; //任何类型和字符串相加结果都是字符串 System.out.println(str2+1); //"2001" */ } } |
练习
键盘录入一个大小写混杂的纯英文字符串。
将字符串转换成首字母大写,其他字母全部小写。
例如,键盘录入”i lOvE jAvA”,转换成 “I love java”
public class Demo07_l练习_首字母大写其他小写 { /* 键盘录入一个大小写混杂的纯英文字符串 将字符串转换成首字母大写,其他字母全部小写 例如,键盘录入”i lOvE jAvA”,转换成 “I love java” * */ public static void main(String[] args) { Scanner sc = new Scanner(System.in); String str = sc.nextLine(); // 首字母转大写,其他小写
String s1 = str.substring(0,1); //截取首字母 String s2 = str.substring(1); //截取其他
String result = s1.toUpperCase()+s2.toLowerCase(); System.out.println(result);
} } |
(5)其他方法
|
示例代码
public class Demo08_其他方法 {
public static void main(String[] args) { /* // replace 替换 replaceAll---后面讲
String str = "www.baidu.com";
String str2 = str.replace("w", "x"); System.out.println(str2);
String str3 = str.replace("www", "x"); System.out.println(str3);
*/
/* // trim 去首尾空格
String str = " aaa bbb "; String str2 = str.trim(); System.out.println(str); System.out.println(str2);
*/ /* // split 字符串拆分 拆成数组 String str = "aaa#bbb#ccc#ddd"; String[] ss = str.split("#"); for(String s:ss){
System.out.println(s); } */
/* String str = "aaa##bbb#ccc#ddd"; String[] ss = str.split("#"); for(String s:ss){
System.out.println(s); }
*/ String str = "aaa+bbb+ccc+ddd"; //String[] ss = str.split("+"); // 因为+是正则表达式(后面讲)的特殊字符 (+ . * ?)需要转义 String[] ss = str.split("\\+"); for(String s:ss){
System.out.println(s); } } } |
三、字符串缓冲区StringBuilder
1、概述
- StringBuilder是一个可变的字符序列,因为在类中提供了修改私有成员变量的方法。常用的方法是append和insert,就是在StringBuilder对象本身上,进行修改操作。
- StringBuilder底层和String类型一样,也是维护了一个字符数组,数组是私有的,外界无法直接访问,因此在StringBuilder或者String中对数组进行操作的公有方法的封装。
- String类型和StringBuilder的关系:都是用于描述字符串。
1、String是不可变的字符序列,没有提供修改私有成员的方法;StringBuilder是可变的字符序列,因为提供了修改成员变量的方法;
2、String长度本身也不可以变化,StringBuilder长度可以变化,可以认为StringBuilder就像一个可以伸缩的容器,用于存储字符。
2、构造方法
- 构造方法作用:创建当前对象、将其他类型的数据,转换成当前类型。
- StringBuilder的构造方法:
StringBuilder():创建一个生成器,初始容量为16个字符。
StringBuilder(int capacity):创建一个生成器,初始容量为capacity大小。
StringBuilder(String str):创建一个生成器,初始值就是str这些字符,初始大小是str+16。
- 获取容积的方法:
capacity():获取当前生成器的容器大小。
length():获取当前生成器中的字符个数。
代码示例
public class Demo01_StringBuilder构造方法 { public static void main(String[] args) { /* StringBuilder sb = new StringBuilder(); int length = sb.length(); // 获取sb中包含多少个字符 System.out.println(length); int capacity = sb.capacity(); //获取容量 默认 16 System.out.println(capacity); */ StringBuilder sb = new StringBuilder("abc"); int length = sb.length(); // 获取sb中包含多少个字符 System.out.println(length); int capacity = sb.capacity(); //获取容量 这种初始化方式 用字符串的长度+16 System.out.println(capacity); } } |
3、添加功能
- append(任意类型):可以将任意数据类型,转成字符,添加到生成器中
- insert(int index, 任意数据类型):可以将任意数据类型,添加到指定的位置
说明:1、index的范围是0~当前缓冲区的大小;2、插入数据之后,数据本身的索引就是参数中指定的index
代码示例
public class Demo02_StringBuilder添加功能 { public static void main(String[] args) { StringBuilder sb = new StringBuilder("abc"); sb.append("xyz"); // 追加在末尾 System.out.println(sb); sb.insert(1, "hello"); // 在相应的位置插入 System.out.println(sb); } } |
4、删除功能
- deleteCharAt(int index) :删除指定索引的字符
- delete(int start, int end):删除指定范围的字符,被删除的部分包含头不包含尾
代码示例
public class Demo03_StringBuilder_删除功能 { public static void main(String[] args) { StringBuilder sb = new StringBuilder("abcdefg"); System.out.println(sb); sb.deleteCharAt(1); System.out.println(sb); sb.delete(1,3); // 左闭右开 System.out.println(sb); } } |
5、替换和反转功能
- replace(int start, int end ,String str):
将字符串缓冲区中的从start开始到end-1这部分内容,替换成str
- reverse():将原有字符序列进行反转
代码示例
public class Demo04_StringBuilder_替换和反转功能 { public static void main(String[] args) { StringBuilder sb = new StringBuilder("abcdefg"); //sb.reverse(); //反转 //System.out.println(sb); sb.replace(1, 3, "hello"); //替换 System.out.println(sb); } } |
6、练习
1、定义一个方法,接收一个String类型的字符串,返回该字符串的反转形式
举例:接收字符串为abc,返回字符串为cba
要求:使用StringBuilder进行反转,提高开发效率
代码示例
public class Demo05_练习_使用StringBuilder进行字符串反转 { public static void main(String[] args) { String str = "abc"; String result = fanzhuan(str); System.out.println(result); } public static String fanzhuan(String str){ StringBuilder sb = new StringBuilder(str); sb.reverse();// 反转——使用StringBuilder的reverse方法反转效率高 return sb.toString(); // 把StringBuilder转成String } } |
7、String和StringBuilder拼接字符串的区别
使用String类型拼接字符串:时间和空间上都非常浪费。
1、创建一个StringBuilder的存储空间,大小为第一个字符串的长度+16(第一个对象)
2、将第一个字符串添加到缓冲区中
3、将第二个字符串添加到缓冲区中
4、将缓冲区对象转成字符串对象(创建了一个新的字符串对象)(第二个对象)
5、返回该字符串对象
使用StringBuilder拼接字符串:时间和空间上都非常节省,无论循环多少次,都只创建两个对象。
1、创建一个新的StringBuilder的存储空间
2、在StringBuilder的基础上进行添加,不创建新的字符串
3、循环完成后,将StringBuilder转成String
示例代码
/* * String 使用+拼接字符串时,底层会转换成StringBuilder。拼完后再转成String * 这样做内存中会创建更多的对象,而且转换过程也比较耗时。 * * StringBuilder 使用append拼接字符串就不存在以上问题 * * 当有大量的字符串需要拼接时,一定要使用StringBuilder * * 定义一个方法,接收一个int[]类型的数组,返回该数组的字符串表示形式 举例:接收数组为int[] arr = {1, 2, 3},返回的字符串为[1, 2, 3] 要求:使用StringBuilder进行拼接,提高运行效率 * * * */ public static void main(String[] args) { int[] aa = {1,2,3,4,5}; String str = arrStr(aa); System.out.println(str); } public static String arrStr(int[] aa){ StringBuilder sb = new StringBuilder("["); for(int i=0;i<aa.length;i++){ sb.append(aa[i]).append(i==aa.length-1?"]":","); } return sb.toString(); }
public static String arrStr2(int[] aa) { String result = "["; for (int i = 0; i < aa.length; i++) { result += aa[i] + (i == aa.length - 1 ? "]" : ", "); } return result; } } |
8、String和StringBuilder的相互转换
String转成StringBuilder
1、StringBuilder的构造方法
2、append方法
StringBuilder转成String类型
1、toString的方法
2、使用String的构造方法
代码示例
public static void main(String[] args) { String str = "abc"; StringBuilder sb = new StringBuilder(str); String result = sb.toString(); } |
9、StringBuffer和StringBuilder的区别
相同点:
都是字符串的缓冲区,都是字符串的生成器,都是可变的字符序列
不同点:
1、出现版本不同:
StringBuffer在jdk1.0出现的
StringBuilder在jdk1.5出现的
2、线程安全性不同:
StringBuffer是线程安全的,在多线程环境下仍然保证数据安全
StringBuilder是线程不安全,在多线程环境下无法保证数据安全
3、效率不同:
StringBuffer效率低
StringBuilder效率高
10、String和StringBuilder作为方法的参数
- String作为方法的参数进行传递,无法修改原值。在被调用的方法中,修改引用指向的对象,和主方法中的引用无关。
|
- StringBuilder作为方法的参数进行传递,如果在被调用的方法中,修改的是StringBuilder的引用,那么不会改变原有对象中的数据。
|
- StringBuilder作为方法的参数进行传递,如果在被调用的方法中,通过该引用修改了对象的数据,那么原值就会发生改变。
|
代码示例
public class Demo09_String和StringBuilder作为方法参数问题 { public static void main(String[] args) { /* String str = "abc"; update(str); System.out.println(str); */ /* StringBuilder sb = new StringBuilder("abc"); update2(sb); System.out.println(sb); */ StringBuilder sb = new StringBuilder("abc"); update3(sb); System.out.println(sb); } public static void update(String ss){ ss = "xyz"; } public static void update2(StringBuilder ss){ ss = new StringBuilder("xyz"); } public static void update3(StringBuilder ss){ ss.append("xyz"); } } |
11、字符串的比较 ==和equals总结
示例代码
public static void main(String[] args) { /* String str = "abc"; //常量池 String str2 = new String("abc"); //堆 System.out.println(str==str2); */ /* String str = "aaa"+"bbb"; //常量优化机制——在编译时 就已经完成了 "aaa"+"bbb"的计算 String str2 = "aaabbb"; System.out.println(str==str2); */ /* String str = "aaa"; str = str+"bbb"; String str2 = "aaabbb"; System.out.println(str==str2); */ /* String s1 = "aaa"; String s2 = "bbb"; String str = s1+s2; String str2 = "aaabbb"; System.out.println(str==str2); */
//String str = "aaa"+"bbb"; //常量优化机制,在编译器就完成了运算 str指向常量池中的 "aaabbb" String str = "aaa"; str = str+"bbb"; // 字符串使用+拼接时,一旦有变量参与,底层会转成StringBuilder 并使用append完成拼接。运算完成后,在转换成String返回。 // 而且,这个转换后的String存在堆区 } |
作业
1、分析以下需求,并用代码实现:
(1)定义数字字符串数组{"010","3223","666","7890987","123123"}
(2)判断该数字字符串数组中的数字字符串是否是对称(第一个数字和最后一个数字相等,第二个数字和倒数第二个数字是相等的,依次类推)的,并逐个输出
(3)如:010 是对称的,3223 是对称的,123123 不是对称的
(4)最终打印该数组中对称字符串的个数
提示:循环获取字符串的每一个字符,依次比较第一个和最后一个,第二个和倒数第二个。。。
2.分析以下需求,并用代码实现:
(1)从键盘循环录入录入一个字符串,输入"end"表示结束
(2)将字符串中大写字母变成小写字母,小写字母变成大写字母,其它字符用"*"代替,并统计字母的个数
举例:
键盘录入:Hello12345World
输出结果:hELLO*****wORLD
总共10个字母
3、键盘录入一个字符串,统计该字符串中的大写字母、小写字母、数字字符和其他字符分别有多少个
例如,键盘录入abcABCD12345!@#$%&,输出结果为:小写字母有3个,大写字母有4个,数字字符有5个,其他字符有6个。
4、定义一个方法,功能如下:给定一个数组,转换成一个字符串
例如:数组为int[] arr = {1, 2, 3},字符串为[1, 2, 3]
5、定义一个方法,功能如下:给定一个字符串,返回该字符串的反转形式
例如:字符串为abcdef,返回结果为fedcba