String类
String类概述
java.lang.String
类代表字符串。Java程序中所有的字符串文字(例如 "abc" )都可以被看作是实现此类的实例。 类 String
中包括用于检查各个字符串的方法,比如用于比较字符串,搜索字符串,提取子字符串以及创建具有翻译为大写或小写的所有字符的字符串的副本。
特点 :
1.字符串不变:字符串的值在创建后不能被更改。
String s1 = "abc";
s1 += "d";
System.out.println(s1); // "abcd"
// 内存中有"abc","abcd"两个对象,s1从指向"abc",改变指向,指向了"abcd"。
2.因为String
对象是不可变的,所以它们可以被共享。
String s1 = "abc";
String s2 = "abc";
// 内存中只有一个"abc"对象被创建,同时被s1和s2共享。
3."abc" 等效于 char[] data={ 'a' , 'b' , 'c' }
。
例如:
String str = "abc";
相当于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
// String底层是靠字符数组实现的。
使用
java.lang.String
:此类不需要导入。
-
public String()
:初始化新创建的String
对象,以使其表示空字符序列。 -
public String(char[] value)
:通过当前参数中的字符数组来构造新的String
。 -
public String(byte[] bytes)
:通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String
。 - 直接创建
String str = "hello"
举例:
public class Demo01String {
public static void main(String[] args) {
// 使用空参构造
String str1 = new String(); // 小括号留空,说明字符串什么内容都没有。
System.out.println("第1个字符串:" + str1);
// 根据字符数组创建字符串
char[] charArray = { 'A', 'B', 'C' };
String str2 = new String(charArray);
System.out.println("第2个字符串:" + str2);
// 根据字节数组创建字符串
byte[] byteArray = { 97, 98, 99 };
String str3 = new String(byteArray);
System.out.println("第3个字符串:" + str3);
// 直接创建
String str4 = "Hello";
System.out.println("第4个字符串:" + str4);
}
}
不管new没new,都String
对象。
字符串常量池
package cn.itcast.day08.demo01;
/*
字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池中。
对于基本类型来说,==是进行数值的比较。
对于引用类型来说,==是进行【地址值】的比较。
*/
public class Demo02StringPool {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
char[] charArray = {'a', 'b', 'c'};
String str3 = new String(charArray);
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // false
System.out.println(str2 == str3); // false
}
}
常量池图解:
String相关方法
1.比较:
==
是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法:
-
public boolean equals(Object obj)
:参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false。 -
public boolean equalsIgnoreCase(String str)
:忽略大小写,进行内容比较。
注意事项:
- 任何对象都能用Object进行接收。
- equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。
- 如果比较双方一个常量一个变量,推荐把常量字符串写在前面。
推荐:"abc".equals(str)
不推荐:str.equals("abc")
代码:
package cn.itcast.day08.demo02;
public class Demo01StringEquals {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str3 = new String(charArray);
System.out.println(str1.equals(str2)); // true
System.out.println(str2.equals(str3)); // true
System.out.println(str3.equals("Hello")); // true
System.out.println("Hello".equals(str1)); // true
String str4 = "hello";
System.out.println(str1.equals(str4)); // false
System.out.println("=================");
String str5 = null;
System.out.println("abc".equals(str5)); // 推荐:false
// System.out.println(str5.equals("abc")); // 不推荐:报错,空指针异常NullPointerException
System.out.println("=================");
String strA = "Java";
String strB = "java";
System.out.println(strA.equals(strB)); // false,严格区分大小写
System.out.println(strA.equalsIgnoreCase(strB)); // true,忽略大小写
// 注意,只有英文字母区分大小写,其他都不区分大小写
System.out.println("abc一123".equalsIgnoreCase("abc壹123")); // false
}
}
2. 字符串的获取
String当中与获取相关的常用方法有:
-
public int length()
:获取字符串当中含有的字符个数,拿到字符串长度。
例:int len = "abc".lendth()
-
public String concat(String str)
:将当前字符串和参数字符串拼接成为返回值新的字符串。
例:String str3 = str1.concat(str2);
-
public char charAt(int index)
:获取指定索引位置的单个字符。(索引从0开始。)
例:char ch = "Hello".charAt(1);
-
public int indexOf(String str)
:查找参数字符串在本字符串当中首次出现的索引位置,如果没有,则返回-1
值。
例:int index = original.indexOf("llo");
public class Demo02StringGet {
public static void main(String[] args) {
// 获取字符串的长度
int length = "asdasfeutrvauevbueyvb".length();
System.out.println("字符串的长度是:" + length);
// 拼接字符串
String str1 = "Hello";
String str2 = "World";
String str3 = str1.concat(str2);
System.out.println(str1); // Hello,原封不动
System.out.println(str2); // World,原封不动
System.out.println(str3); // HelloWorld,新的字符串
System.out.println("==============");
// 获取指定索引位置的单个字符
char ch = "Hello".charAt(1);
System.out.println("在1号索引位置的字符是:" + ch);
System.out.println("==============");
// 查找参数字符串在本来字符串当中出现的第一次索引位置
// 如果根本没有,返回-1值
String original = "HelloWorldHelloWorld";
int index = original.indexOf("llo");
System.out.println("第一次索引值是:" + index); // 2
System.out.println("HelloWorld".indexOf("abc")); // -1
}
}
3.字符串的截取方法
-
public String substring(int index)
:截取从参数位置一直到字符串末尾,返回新字符串。 -
public String substring(int begin, int end)
:截取从begin开始,一直到end结束,中间的字符串。 - 备注:
[begin,end)
,包含左边,不包含右边。
public class Demo03Substring {
public static void main(String[] args) {
String str1 = "HelloWorld";
String str2 = str1.substring(5);
System.out.println(str1); // HelloWorld,原封不动
System.out.println(str2); // World,新字符串
System.out.println("================");
String str3 = str1.substring(4, 7);
System.out.println(str3); // oWo
System.out.println("================");
// 下面这种写法,字符串的内容仍然是没有改变的
// 下面有两个字符串:"Hello","Java"
// strA当中保存的是地址值。
// 本来地址值是Hello的0x666,
// 后来地址值变成了Java的0x999
String strA = "Hello";
System.out.println(strA); // Hello
strA = "Java";
System.out.println(strA); // Java
}
}
4.转换方法
String当中与转换相关的常用方法有:
-
public char[] toCharArray()
:将当前字符串拆分成为字符数组作为返回值。 -
public byte[] getBytes()
:获得当前字符串底层的字节数组。 -
public String replace(CharSequence oldString, CharSequence newString)
:将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。 - 备注:
CharSequence
意思就是说可以接受字符串类型。
代码示例:
public class Demo04StringConvert {
public static void main(String[] args) {
// 转换成为字符数组
char[] chars = "Hello".toCharArray();
System.out.println(chars[0]); // H
System.out.println(chars.length); // 5
System.out.println("==============");
// 转换成为字节数组
byte[] bytes = "abc".getBytes();
for (int i = 0; i < bytes.length; i++) {
System.out.println(bytes[i]);
}
System.out.println("==============");
// 字符串的内容替换
String str1 = "How do you do?";
String str2 = str1.replace("o", "*");
System.out.println(str1); // How do you do?
System.out.println(str2); // H*w d* y*u d*?
System.out.println("==============");
String lang1 = "会不会玩儿呀!你大爷的!你大爷的!你大爷的!!!";
String lang2 = lang1.replace("你大爷的", "****");
System.out.println(lang2); // 会不会玩儿呀!****!****!****!!!
}
}
5.分割功能的方法
分割字符串的方法:
-
public String[] split(String regex)
:按照参数的规则,将字符串切分成为若干部分。
注意事项:
split
方法的参数其实是一个“正则表达式”,今后学习。
今天要注意:如果按照英文句点“.”
进行切分,必须写"\\."
(两个反斜杠)
public class Demo05StringSplit {
public static void main(String[] args) {
String str1 = "aaa,bbb,ccc";
String[] array1 = str1.split(",");
for (int i = 0; i < array1.length; i++) {
System.out.println(array1[i]);
}
System.out.println("===============");
String str2 = "aaa bbb ccc";
String[] array2 = str2.split(" ");
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i]);
}
System.out.println("===============");
String str3 = "XXX.YYY.ZZZ";
String[] array3 = str3.split("\\.");
System.out.println(array3.length); // 3
for (int i = 0; i < array3.length; i++) {
System.out.println(array3[i]);
}
}
}
结果:
6.练习:
定义一个方法,把数组{1,2,3}按照指定格式拼接成一个字符串。格式参照如下:[word1#word2#word3]
。
分析:
- 首先准备一个
int[]
数组,内容是:1、2、3 - 定义一个方法,用来将数组变成字符串:
- 返回值类型:
String
- 方法名称:
fromArrayToString
- 参数列表:
int[]
- 格式:
[word1#word2#word3]
用到:for循环、字符串拼接、每个数组元素之前都有一个word字样、分隔使用的是#、区分一下是不是最后一个 - 调用方法,得到返回值,并打印结果字符串。
代码示例:
public class Demo06StringPractise {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4};
String result = fromArrayToString(array);
System.out.println(result);
}
public static String fromArrayToString(int[] array) {
String str = "[";
for (int i = 0; i < array.length; i++) {
if (i == array.length - 1) {
str += "word" + array[i] + "]";
} else {
str += "word" + array[i] + "#";
}
}
return str;
}
}
7.统计字符个数
题目:
键盘输入一个字符串,并且统计其中各种字符出现的次数。
种类有:大写字母、小写字母、数字、其他
思路:
- 既然用到键盘输入,肯定是Scanner
- 键盘输入的是字符串,那么:String str = sc.next();
- 定义四个变量,分别代表四种字符各自的出现次数。
- 需要对字符串一个字、一个字检查,String-->char[],方法就是toCharArray()
- 遍历char[]字符数组,对当前字符的种类进行判断,并且用四个变量进行++动作。
- 打印输出四个变量,分别代表四种字符出现次数。
public class Demo07StringCount {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String input = sc.next(); // 获取键盘输入的一个字符串
int countUpper = 0; // 大写字母
int countLower = 0; // 小写字母
int countNumber = 0; // 数字
int countOther = 0; // 其他字符
char[] charArray = input.toCharArray();
for (int i = 0; i < charArray.length; i++) {
char ch = charArray[i]; // 当前单个字符
if ('A' <= ch && ch <= 'Z') {
countUpper++;
} else if ('a' <= ch && ch <= 'z') {
countLower++;
} else if ('0' <= ch && ch <= '9') {
countNumber++;
} else {
countOther++;
}
}
System.out.println("大写字母有:" + countUpper);
System.out.println("小写字母有:" + countLower);
System.out.println("数字有:" + countNumber);
System.out.println("其他字符有:" + countOther);
}
}
static关键字
- 关于
static
关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属于某个对象的。也就是说,既然属于类,就可以不靠创建对象来调用了。多个对象共享同一份数据。
类变量:
- 当
static
修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。
static的图解:
1.static修饰成员变量
格式:
static 数据类型 变量名;
创建学生类:
public class Student {
private int id; // 学号
private String name; // 姓名
private int age; // 年龄
static String room; // 所在教室
private static int idCounter = 0; // 学号计数器,每当new了一个新对象的时候,计数器++
public Student() {
this.id = ++idCounter;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
this.id = ++idCounter;
}
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;
}
}
在main方法中调用:
public class Demo01StaticField {
public static void main(String[] args) {
Student two = new Student("黄蓉", 16);
two.room = "101教室";
System.out.println("姓名:" + two.getName()
+ ",年龄:" + two.getAge() + ",教室:" + two.room
+ ",学号:" + two.getId());
Student one = new Student("郭靖", 19);
System.out.println("姓名:" + one.getName()
+ ",年龄:" + one.getAge() + ",教室:" + one.room
+ ",学号:" + one.getId());
}
}
运行:
解析:
static
修饰的room
在two
对象时赋值,那么就相当于整个类中的对象有是这个值room
值。
通常定义静态成员变量--计数器,每当调用构造方法时加一,在全参构造时,把该计数器的值加一赋给对象的成员变量
id
。
2.static修饰成员方法
当 static
修饰成员方法时,该方法称为类方法 。静态方法在声明中有 static
,建议使用类名来调用,而不需要创建类的对象。
- 类方法:使用
static
关键字修饰的成员方法,习惯称为静态方法。
定义格式:
修饰符 static 返回值类型 方法名 (参数列表){
// 执行语句
}
举例:
定义MyClass类:
public class MyClass {
int num; // 成员变量
static int numStatic; // 静态变量
// 成员方法
public void method() {
System.out.println("这是一个成员方法。");
// 成员方法可以访问成员变量
System.out.println(num);
// 成员方法可以访问静态变量
System.out.println(numStatic);
}
// 静态方法
public static void methodStatic() {
System.out.println("这是一个静态方法。");
// 静态方法可以访问静态变量
System.out.println(numStatic);
// 静态不能直接访问非静态【重点】
// System.out.println(num); // 错误写法!
// 静态方法中不能使用this关键字。
// System.out.println(this); // 错误写法!
}
}
在main方法中调用:
package cn.itcast.day08.demo03;
/*
静态变量:类名称.静态变量
静态方法:类名称.静态方法()
*/
public class Demo02StaticMethod {
public static void main(String[] args) {
MyClass obj = new MyClass(); // 首先创建对象
// 然后才能使用没有static关键字的内容
obj.method();
// 对于静态方法来说,可以通过对象名进行调用,也可以直接通过类名称来调用。
obj.methodStatic(); // 正确,不推荐,这种写法在编译之后也会被javac翻译成为“类名称.静态方法名”
MyClass.methodStatic(); // 正确,推荐
// 对于本来当中的静态方法,可以省略类名称
myMethod();
Demo02StaticMethod.myMethod(); // 与上边形式完全等效
}
public static void myMethod() {
System.out.println("自己的方法!");
}
}
解析:
- 对于静态方法,推荐使用
类名称
进行调用。自己的静态方法可以省略类名称,直接写方法名()
。 - 不能使用
this
关键字(this关键字指向的是当前对象),静态内容与非静态内容在内存中不在一个位置。 - 对于成员方法,必须使用对象进行调用,对象也可以调用静态方法,但是不推荐。推荐使用:
类名.静态方法()
- 静态方法可以访问静态变量,不能访问成员变量。原因:先有静态内容。后有非静态内容,先人不知道后人。
非静态方法都可以访问。 - 无论是成员变量,还是成员方法。如果有了static,都推荐使用类名称进行调用。
3.static的内存图
在StaticStudent类中:
public class Demo03StaticStudent {
public static void main(String[] args) {
// 首先设置一下教室,这是静态的东西,应该通过类名称进行调用
Student.room = "101教室";
Student one = new Student("郭靖", 20);
System.out.println("one的姓名:" + one.getName());
System.out.println("one的年龄:" + one.getAge());
System.out.println("one的教室:" + Student.room);
System.out.println("============");
Student two = new Student("黄蓉", 18);
System.out.println("two的姓名:" + two.getName());
System.out.println("two的年龄:" + two.getAge());
System.out.println("two的教室:" + Student.room);
}
}
运行:
那么他们是怎么实现room属性的共享的呢?
static内存图解:
通过类名称访问静态变量的时候,全程和类名称没有关系。只和类名称有关系,就算是拿对象.静态变量调用,在编译时也会编译为类.静态变量,到静态区中找。
4.静态代码块
静态代码块的格式:
public class 类名称 {
static {
// 静态代码块的内容
}
}
创建Person类:
public class Person {
static {
System.out.println("静态代码块执行!");
}
public Person() {
System.out.println("构造方法执行!");
}
}
在main方法中调用:
public class Demo04Static {
public static void main(String[] args) {
Person one = new Person(); //执行第一次也是最后一次静态代码块
Person two = new Person(); //不再执行静态代码块
}
}
运行结果:
解析:
静态代码块只执行唯一的一次,就是在第一次调用该类的构造方法时,执行。
特点:当第一次用到本类时,静态代码块执行唯一的一次。
静态内容总是优先于非静态,所以静态代码块比构造方法先执行。
静态代码块的典型用途:
用来一次性地对静态成员变量进行赋值。
数组工具类Arrays
java.util.Arrays
此类包含用来操作数组的各种方法,比如排序和搜索等。里面提供了大量静态方法,用来实现数组常见的操作。
-
public static String toString(数组)
:将参数数组变成字符串(按照默认格式:[元素1, 元素2, 元素3...]) -
public static void sort(数组)
:按照默认升序(从小到大)对数组的元素进行排序。
备注:
- 如果是数值,
sort
默认按照升序从小到大 - 如果是字符串,
sort
默认按照字母升序 - 如果是自定义的类型,那么这个自定义的类需要有
Comparable
或者Comparator
接口的支持。(今后学习)
代码:
import java.util.Arrays;
public class Demo01Arrays {
public static void main(String[] args) {
int[] intArray = {10, 20, 30};
// 将int[]数组按照默认格式变成字符串
String intStr = Arrays.toString(intArray);
System.out.println(intStr); // [10, 20, 30]
int[] array1 = {2, 1, 3, 10, 6};
Arrays.sort(array1);
System.out.println(Arrays.toString(array1)); // [1, 2, 3, 6, 10]
String[] array2 = {"bbb", "aaa", "ccc"};
Arrays.sort(array2);
System.out.println(Arrays.toString(array2)); // [aaa, bbb, ccc]
}
}
把一个数组转换为String类型: Arrays.toString(数组)
给数组排序: Arrays.sort(数组)
Arrays练习
练习:
将一个随机字符串中的所有字符升序排列,并倒序打印。
public class Demo02ArraysPractise {
public static void main(String[] args) {
String str = "asv76agfqwdfvasdfvjh";
// 如何进行升序排列:sort
// 必须是一个数组,才能用Arrays.sort方法
// String --> 数组,用toCharArray
char[] chars = str.toCharArray();
Arrays.sort(chars); // 对字符数组进行升序排列
// 需要倒序遍历
for (int i = chars.length - 1; i >= 0; i--) {
System.out.println(chars[i]);
}
}
}
倒序遍历的快捷键:遍历对象.forr
Math类
java.lang.Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。类似这样的工具类,其所有方法均为静态方法,并且不会创建对象.
- public static double abs(double num):获取绝对值。有多种重载。
- public static double ceil(double num):向上取整。
- public static double floor(double num):向下取整。
- public static long round(double num):四舍五入。
- Math.PI代表近似的圆周率常量(double)。
public class Demo03Math {
public static void main(String[] args) {
// 获取绝对值
System.out.println(Math.abs(3.14)); // 3.14
System.out.println(Math.abs(0)); // 0
System.out.println(Math.abs(-2.5)); // 2.5
System.out.println("================");
// 向上取整
System.out.println(Math.ceil(3.9)); // 4.0
System.out.println(Math.ceil(3.1)); // 4.0
System.out.println(Math.ceil(3.0)); // 3.0
System.out.println("================");
// 向下取整,抹零
System.out.println(Math.floor(30.1)); // 30.0
System.out.println(Math.floor(30.9)); // 30.0
System.out.println(Math.floor(31.0)); // 31.0
System.out.println("================");
System.out.println(Math.round(20.4)); // 20
System.out.println(Math.round(10.5)); // 11
}
}
Math练习
题目:
计算在-10.8
到5.9
之间,绝对值大于6
或者小于2.1
的整数有多少个?
分析:
- 既然已经确定了范围,
for
循环 - 起点位置
-10.8
应该转换成为-10
,两种办法:
2.1 可以使用Math.ceil
方法,向上(向正方向)取整
2.2 强转成为int
,自动舍弃所有小数位 - 每一个数字都是整数,所以步进表达式应该是
num++
,这样每次都是+1
的。 - 如何拿到绝对值:
Math.abs
方法。 - 一旦发现了一个数字,需要让计数器++进行统计。
备注:如果使用Math.ceil
方法,-10.8
可以变成-10.0
。注意double
也是可以进行++
的。
public class Demo04MathPractise {
public static void main(String[] args) {
int count = 0; // 符合要求的数量
double min = -10.8;
double max = 5.9;
// 这样处理,变量i就是区间之内所有的整数
for (int i = (int) min; i < max; i++) {
int abs = Math.abs(i); // 绝对值
if (abs > 6 || abs < 2.1) {
System.out.println(i);
count++;
}
}
System.out.println("总共有:" + count); // 9
}
}