文章目录
前言
本文将重点介绍Java中常用类,并且重点介绍String类,在C语言中涉及过字符串,但其字符串的表示只能是使用字符数组或者字符指针,虽然可以使用标准库提供的字符操作函数完成一系列操作,但这种将数据和操作数据的方法分离开的方式不符合面对对象的思想,然而字符串的应用又十分广泛,因此Java提供了String类;在笔试,开发,面试中会遇到关于字符串的试题,所以我们要认真对待它。
String类
大家可以查看String类官方文档
String类的初始化
1.使用字符串常量直接初始化
格式:
String 变量名 = 字符串;
//初始化为空,不指向任何对象
String s1 = null;
//初始化为空字符串
String s2 = "";
//初始化为常量字符串abc
String s3 = "abc";
2.使用String的构造方法初始化
String类提供多种构造方法,常用的构造方法如下:
- String() 创建一个空字符串
public String() {
this.value = "".value;
}
- **String(String value)**根据字符串内容初始化
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
- **String(char[] value)**根据字符数组内容初始化
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
//创建一个空字符串
String s1 = new String();
//根据字符串内容初始化
String s2 = new String("abc");
//根据字符数组内容初始化
char[] charArray = new char[] {'A', 'B','C'};
String s3 = new String(charArray);
注:
- String是引用类型,其存储的是字符串的地址。
官方源码表面,String类有两个属性,我们以一段代码来理解它:
public static void main(String[] args) {
String s1 = new String("Hello");
String s2 = new String("World");
String s3 = s1;
}
2. 在Java中""引起来的是引用类型
public static void main(String[] args) {
System.out.println("Hello".length());//5
}
String类的常用方法
String类在实际的开发应用非常广泛,因此灵活的使用String类是十分重要的,下面我们介绍常用的方法。
String对象的比较
- == 比较是否引用同一个对象
注:对于基本数据类型 == 比较的是变量的值,而引用类型 ==比较的是引用中的地址。
public static void main(String[] args) {
String s1 = new String("qaq");
String s2 = new String("qaq");
String s3 = new String("aza");
String s4 = s1;
//这里的s1和s2的内容虽然是一样但其两个字符串在堆上的地址不同
System.out.println(s1 == s2);//false
System.out.println(s2 == s3);//false
System.out.println(s4 == s1);//true
//这里的就是指向同一个字符串,其地址必然相同
String ss1 = "qaq";
String ss2 = "qaq";
System.out.println(ss1 == ss2);//true
}
- boolean equals(Object anObject) 方法:按照字典序比较
String类重写父类Object的equal()方法:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
public static void main(String[] args) {
String s1 = new String("qaq");
String s2 = new String("qaq");
String s3 = new String("qaq");
//s1,s2,s3引用的是不同对象
System.out.println(s1 == s2);//false
System.out.println(s2 == s3);//false
//其内容相同
System.out.println(s1.equals(s2));//true
System.out.println(s2.equals(s3));//true
}
- int compareTo(String s) 方法: 按照字典序进行比较
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。比较方式:
- 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
- 如果前k个字符相等(k为两个字符长度中的最小值),返回值两个字符串长度差值
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("aac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); // 不同输出字符差值1
System.out.println(s1.compareTo(s3)); // 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}
- int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较
public static void main(String[] args) {
String s1 = new String("Abc");
String s2 = new String("aC");
String s3 = new String("ABc");
String s4 = new String("aBcDef");
System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}
字符串查找
String类提供的查找方法:
方法 | 功能 |
---|---|
char charAt(int index) | 返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
int indexOf(int ch, intfromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-1 |
int indexOf(String str) | 返回str第一次出现的位置,没有返回-1 |
int indexOf(String str, intfromIndex) | 从fromIndex位置开始找str第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch) | 从后往前找,返回ch第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch, intfromIndex) | 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1 |
int lastIndexOf(String str) | 从后往前找,返回str第一次出现的位置,没有返回-1 |
int lastIndexOf(String str, intfromIndex) | 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1 |
public static void main(String[] args) {
String s = "aaabbbcccaaabbbccc";
System.out.println(s.charAt(3)); // 'b'
System.out.println(s.indexOf('c')); // 6
System.out.println(s.indexOf('c', 10)); // 15
System.out.println(s.indexOf("bbb")); // 3
System.out.println(s.indexOf("bbb", 10)); // 12
System.out.println(s.lastIndexOf('c')); // 17
System.out.println(s.lastIndexOf('c', 10)); // 8
System.out.println(s.lastIndexOf("bbb")); // 12
System.out.println(s.lastIndexOf("bbb", 10)); // 3
}
字符串的转化
- 数值和字符串转化
public static void main(String[] args) {
String s1 = String.valueOf(1234);
String s2 = String.valueOf(12.34);
String s3 = String.valueOf(true);
String s4 = String.valueOf(new A("ad",12));
System.out.println(s1);//1234
System.out.println(s2);//12.34
System.out.println(s3);//true
System.out.println(s4);//Package.A@1b6d3586
}
- 大小写转化
public static void main(String[] args) {
String s1 = "QAQ";
String s2 = "qaq";
System.out.println(s1.toLowerCase());
System.out.println(s2.toUpperCase());
}
- 字符串转数组
public static void main(String[] args) {
//字符串转数组
String s = "knight";
char[] ch = s.toCharArray();
System.out.println(Arrays.toString(ch));//[k, n, i, g, h, t]
//数组转字符串
String s2 = new String(ch);
System.out.println(s2);//knight
}
- 格式化
public static void main(String[] args) {
String s = String.format("%d-%d-%d", 2022, 4, 9);
System.out.println(s);
}
字符串的替换和去除空格
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
方法 | 功能 |
---|---|
String replaceAll(String regex, String replacement) | 替换所有的指定内容 |
String replaceFirst(String regex, String replacement) | 替换首个内容 |
String replace(char oldChar, char newChar) | 替换所以的指定内容 |
去除字符串中首尾的空格
方法 | 功能 |
---|---|
String trim() | 去除字符串中首尾的空格 |
public static void main(String[] args) {
String s = " www.4399.com ";
System.out.println(s.trim());//www.4399.com
System.out.println(s.replaceFirst(".","-"));//- www.4399.com
System.out.println(s.replace(".","-"));// www-4399-com
System.out.println(s.replaceAll("-","."));// www.4399.com
}
字符串的拆分
将一个完整的字符串按照指定的分隔符划分为若干个子字符串
方法 | 功能 |
---|---|
String[] split(String regex) | 将字符串全部拆分 |
String[] split(String regex, int limit) | 将字符串以指定的格式,拆分为limit组 |
- 将字符串全部拆分
public static void main(String[] args) {
String s = "That is What I Like";
String[] ret = s.split(" ");
for (String str : ret) {
System.out.println(str);
}
}
- 字符串以指定的格式,拆分为limit组
public static void main(String[] args) {
String s = "That is What I Like";
String[] ret = s.split(" ",2);
for (String str : ret) {
System.out.println(str);
}
}
注:
- 字符"|","*","+"都得加上转义字符,前面加上 “\\” .
- 而如果是 “\” ,那么就得写成 “\\\\” .
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
示例:拆分IP地址
public static void main(String[] args) {
String str = "192.168.1.1" ;
String[] result = str.split("\\.") ;
for(String s: result) {
System.out.println(s);
}
}
示例:多次拆分
public static void main(String[] args) {
String str = "name=zhangsan&age=18" ;
String[] result = str.split("&") ;
for (int i = 0; i < result.length; i++) {
String[] temp = result[i].split("=") ;
System.out.println(temp[0]+" = "+temp[1]);
}
}
字符串判断
方法 | 功能 |
---|---|
boolean contains(CharSequence s) | 当且仅当此字符串包含指定的char值序列时才返回true |
boolean endsWith(String suffix) | 判断此字符串是否以指定的后缀结尾 |
boolean startsWith(String prefix) | 判断此字符串是否以指定的前缀开头 |
boolean isEmpty() | 返回 true当且仅当length()为 0 |
public static void main(String[] args) {
String s = "qaQs";
System.out.println(s.isEmpty());//false
System.out.println(s.startsWith("q"));//true
System.out.println(s.endsWith("a"));//false
System.out.println(s.contains("aQ"));//true
}
字符串截取
方法 | 功能 |
---|---|
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分内容 |
注:这里的范围是左闭右开
public static void main(String[] args) {
String s = "2022-4-9";
System.out.println(s.substring(4));//-4-9
System.out.println(s.substring(0,4));//2022
}
字符串常量池
常量池
在Java程序中,类似于1,2,120,”hello“等字面常量经常被使用,为了使程序运行速度更快,更节省内存,Java为基本数据类型和String类提供了常量池。
"池"是为了提高效率的方式,还有”内存池“,”线程池“,”数据库连接池“…
概念:
- Class文件常量池: .Java文件编译生成.Class文件中会保存当前类的字面常量以及符号信息
- 运行时常量池:当程序把编译好的字节码文件中的常量池加载到JVM中后,就形成了运行时常量池。
- 字符串常量池:主要存放的是字符串常量,本质上是一个固定大小的HashTable(一种高效查找的数据结构)
注:
- 在JVM中字符串常量池只有一份,是全局共享的
- 刚开始字符串常量池是空的,随着程序不断运行,字符串常量池中元素会越来越多
- 当类加载时,字节码文件中的常量池也被加载到JVM中,称为运行时常量池,同时会将其中的字符串常量保存在字符串常量池中
- 字符创常量池中的内容:一部分来自运行时常量池,一部分来自程序动态添加
String对象创建
- 直接使用字符串常量进行赋值
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
}
在字节码文件加载时,会将.Class文件中的常量池加载到内存中形成运行时常量池,所以此时"hello"字符常量保存到字符串常量池中.
解释:
创建s1时发现该字符串在常量池中,所以直接把该字符串引用赋值给s1;s2同样的道理
- 使用new创建对象
public static void main(String[] args) {
String str1 = "hello";
String str2= new String("hello");
System.out.println(str1 == str2);
}
- intern方法
intern 是一个native方法(Native方法指:底层使用C++实现的,看不到其实现的源代码),该方法的作用是手动将创建的String对象添加到常量池中.
- 常量和变量的编译方式不同
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hel" + "lo";//常量在编译时其内容已经确定,所以会直接放入常量池
System.out.println(s1 == s2);
String s3 = "Hel";
String s4 = "lo";
String s5 = s3 + s4;//变量在编译时不知道其内容
System.out.println(s1 == s5);
}
- 面试题:请解释String类中两种对象实例化的区别
JDK1.8中
- String str = “hello”
只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象- String str = new String(“hello”)
会开辟两块堆内存空间,字符串"hello"保存在字符串常量池中,然后用常量池中String对象给新开辟的String对象赋值。- String str = new String(new char[]{‘h’, ‘e’, ‘l’, ‘l’, ‘o’})
现在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内容拷贝到String对象中.
字符串的不可变性
我们知道字符串是被final修饰的意味着其指向不能改变,例:
final int[] arr = {1,2,3};
arr = new int[]{1,2,3,4};
被final修饰的数组其指向就不能改变了。
String类中的字符实际保存在内部维护的value字符数组中,所以:
- String类被final修饰,表明该类不能被继承。
- value被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改
- final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的
StringBuilder和StringBuffer
StringBuilder的介绍
由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的,这里介绍 StringBuilder常用的一些方法,其它需要用到了大家可参阅 StringBuilder在线文档
方法 | 说明 |
---|---|
StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index,char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(int start, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str) | 将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int start,int end) | 将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("Hello");
StringBuilder sb2 = sb1;
//追加->字符,字符串,整型数字,
sb1.append(" ");//Hello
sb1.append("world");//Hello world
sb1.append(531);//Hello world531
System.out.println(sb1);//Hello world531
System.out.println(sb1 == sb2);//true
System.out.println(sb1.charAt(1));//获取指定位置字符
System.out.println(sb1.length());//获取字符串长度
System.out.println(sb1.capacity());// 获取底层数组的总大小
sb1.setCharAt(6,'W');//修改任意位置字符
sb1.insert(0,"hihihi");//在指定位置插入
System.out.println(sb1);
System.out.println(sb1.indexOf("hi"));//获取hi第一次出现的下标
System.out.println(sb1.lastIndexOf("hi"));//获取hi最后一次出现的下标
sb1.deleteCharAt(0);//删除指定位置字符
sb1.delete(0,5);//删除指定范围字符
String s = sb1.substring(0,5);//截取[0, 5)区间中的字符以String的方式返回
System.out.println(s);
sb1.reverse();//字符串逆转
s = sb1.toString();//将StringBuffer以String的方式返回
System.out.println(s);
}
String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可
以修改
注:String类和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
- StringBuilder变为String: 调用toString()方法
String、StringBuffer、StringBuilder的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
- StringBuffer与StringBuilder大部分功能是相似的
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
Math类和Random类
Marh类
提供数学运算的一系列方法,其中有两个静态常量PI,E代表数学中的Π和e
|方法 |功能 |
|–|--|
double abs(double a)|返回一个double值的绝对值
double ceil(double a)|返回大于或等于参数的最小(最接近负无穷大) double值,并等于数学整数。
double floor(double a)|返回小于或等于参数的最大(最接近正无穷大) double值,等于数学整数。
int round(float a)|返回参数最接近的int ,其中int四舍五入为正无穷大。
double log10(double a)|返回一个double的基数10对数值
double sqrt(double a)|返回double值正确舍入的正平方根
double pow(double a,double b)|将第一个参数的值返回到第二个参数的幂
public static void main(String[] args) {
System.out.println(Math.abs(-1));//绝对值-> 1
System.out.println(Math.ceil(-5.8));//向上取整 -> -5.0
System.out.println(Math.floor(-5.2));//向下取整 -> -6.0
System.out.println(Math.round(4.5));//四舍五入 -> 5
System.out.println(Math.log10(120));//2.0791812460476247
System.out.println(Math.sqrt(250));//15.811388300841896
System.out.println(Math.pow(2,4));//16.0
}
Random类
构造方法:
方法 | 功能 |
---|---|
Random() | |
Random(long seed) | 使用单个long种子创建新的随机数生成器 |
普通方法:
方法 | 功能 |
---|---|
double nextDouble() | 随机生成double类型的数据 |
int nextInt() | 随机生成int类型的数据 |
int nextInt(int bound) | 随机生成(0,bound]的int类型的数据 |
boolean nextBoolean() | 随机生成boolean类型的数据 |
long nextLong() | 随机生成long类型的数据 |
public static void main(String[] args) {
Random r = new Random();
System.out.println(r.nextInt());
System.out.println(r.nextInt(10));
System.out.println(r.nextBoolean());
System.out.println(r.nextDouble());
System.out.println(r.nextLong());
}
包装类
在万物皆对象的Java中,基本数据类型不是对象,为了满足万物皆对象的理念就需要对基本数据类型的变量进行打包封装处理变成对象,而负责将这些变量声明为成员变量进行对象化处理的相关类,叫做包装类。
Java中的八种包装类
- 常用的方法
- 装箱和拆箱的概念
装箱: 在上述编写的方法中可以实现从int类型到Integer类型的转换,Integer类实际上是int类的包装类,我们把这种从int类型到Integer类型的转换过程,我们把他叫做装箱。什么叫做装箱?装箱的概念就是把箱子。我要想把int类型变成Integer类型实际上就需要把箱子打开,Integer打开把int类变成integer类的成员变量,这样相当于打包好了,实际上这个过程就叫做装箱。
拆箱: 所有把Integer打开,把里面的数据拿出来这个过程叫做拆箱。