复习day3
1. String(底层原理,创建方式,常量池)
底层原理
String类的一个最大特性是不可修改性,而导致其不可修改的原因是在String内部定义了一个常量数组final char数组,因此每次对字符串的操作实际上都会另外分配,分配一个新的常量数组空间
创建方式
String的创建方式一般有两种,一种是常见的new String(),如String s1 = new String(“ab”),另一种是字面量赋值,如String s2 = “ab”。第一种对象的创建方式会创建两个对象,一个是new创建的对象,一个是在字符串常量池中创建”ab”字符串。第二种方式是直接在字符串常量池中创建”ab”字符串(前提是字符串常量池没有该字符串,有的话,直接把该引用赋值给s2)
常量池(元空间的方法区里)
在JVM底层实际上会自动维护一个对象池(字符串常量池) 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存 到这个对象池之中. 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用 ,如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用。
2. String各种比较
“==”判断的是地址值,判断引用是否指向堆内存的同一块地址;equals()方法判断的两个变量是否是对同一个对象的引用,即堆中的内容是否相同。
/**
* 本类用来演示: 字符串的各种比较
*/
public class StringCompare {
public static void main(String[] args) {
//s1默认指向的是堆里面的字符串对象
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2);//false
//intern()强制让s1指向串池的对象
System.out.println(s1.intern() == s2);//true
String s3 = "b";
String s4 = "a" + s3;//产生一个StringBuilder对象
String s5 = "a" + "b";//因为此处的"a"和"b"就是字符串常量
//jvm对待字符串常量的拼接 - "a"和"b"的拼接
//当成"ab"的整体,直接扔到常量池中.
System.out.println(s4 == s5);//false
//字符串使用final修饰
final String s6 = "b";
//"a"+s6 => "ab"扔到常量池,没有产生新的对象.
String s7 = "a" + s6;
System.out.println(s5 == s7);//true
String x1 = new String("abc");
String x2 = new String("abc");
System.out.println(x1 == x2);//false
System.out.println(x1);
//希望字符串的值是一样的,就希望返回true
System.out.println(x1.equals(x2));//true
}
}
3. String ,StringBuilder, StringBuffer区别
三者之间都是使用final修饰的,都是不可被继承的
String: 字符串不可变,适用于字符串内容不经常发生改变的时候
StringBuilder: 字符串可变,适用于字符串内容经常发生改变的时候,适用于单线程(线程不安全),在单线程中,执行效率较高
StringBuffer:字符串可变,适用于字符串内容经常发生改变的时候,适用于多线程(线程安全)
4. 算法题
删除指定字符串
/**
* 根据字符串到原来的字符串中进行删除操作 - 操作的不是原来的字符串,不断返回一个新的字符串.
* @param oldStr
* @param target
* @return
*/
public static String delByStr(String oldStr,String target){
//1. 递归出口
if(!oldStr.contains(target))
return oldStr;
//2. oldStr中仍然包含target
//找到target字符串在oldStr字符串中的下标位置.
//bcbcabca -> ca
int startIndex = oldStr.indexOf(target);//返回target在oldStr中第一次出现的下标位置
int endIndex = startIndex+target.length();//5
//String类型转换成StringBuilder类型 - delete(int start,int end);//[start,end)
StringBuilder builder = new StringBuilder(oldStr);
StringBuilder result = builder.delete(startIndex,endIndex);//bcbbca
return delByStr(result.toString(),target);
}
找出俩个字符串中的最大长度的公串
public static String findCommonStr(String str1,String str2){
//abcbcbcaaaffffff
//fdfdffffffooobcbcbcqqq
//定义一个变量
int len = 0;
//定义StringBuilder对象,用来保存所有的最大长度的公串
StringBuilder builder = new StringBuilder();
//假设str1的长度比str2的长度小.
for (int i = 0; i < str1.length(); i++) {
for (int j = i+1; j <=str1.length(); j++) {
//获取每个子串的各种组合
String subStr = str1.substring(i,j);
//将每个子串的长度
int length = subStr.length();
if(str2.contains(subStr) && length>len){
//清空builder
builder.delete(0,builder.capacity());
builder.append(subStr+" ");
len = length;
}else if(str2.contains(subStr) && length==len){
builder.append(subStr+" ");
}
}
}
return builder.toString();
}
统计字母个数
/**
* @Description: 统计字符串, 每个字符出现的次数
* @Auther: zhugefeng
* @Date:2021/7/30 12:54
**/
public class CountStrDemo {
public static void main(String[] args) {
String str = "ahfdfjdkfjsdafsed";
count(str);
}
private static void count(String str) {
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
if (map.containsKey(str.charAt(i))) {
Integer count = map.get(str.charAt(i));
map.put(str.charAt(i),count++);
} else {
map.put(str.charAt(i), 1);
}
}
List<Map.Entry<Character,Integer>> sortList = new ArrayList<>();
//排序
Set<Map.Entry<Character,Integer>> set = map.entrySet();
Iterator<Map.Entry<Character,Integer>> iter =set.iterator();
while (iter.hasNext()){
sortList.add(iter.next());
}
sortList.sort((c1,c2)->c2.getValue()-c1.getValue());
for (Map.Entry<Character,Integer> e : sortList){
System.out.println(e.getKey()+":"+e.getValue());
}
}
}
5. Integer底层原理,IntegerCache 范围
Integer底层原理
在Integer类内部定义了一个私有的静态类IntegerCache,用来实现Integer的缓存常量池。
该缓存的作用是为了节省内存,提高性能。
在给一个Integer对象直接赋一个int类型的值得时候:Integer num = 100;Java会通过自动装箱机制将int类型值转为Integer类型。自动装箱是指在编译时期编译器自动调用包装类型中的valueOf()方法,进行自动的转换。
针对[-128,127]这个范围内的值,Integer会通过复用对象的方式来提升内存的使用率,减少新对象的生成。
如果在[-128,127]之间,那么直接返回内部的缓冲数组中的数据,如果不在这个范围,返回一个新的Integer对象.
6. Integer各种比较
1、包装类Integer跟基本类型int的比较
直接取出包装类事例所包装的数值进行比较。
Integer it1 = 2;
Integer it3 = new Integer(2);
int i1 = 2;
System.out.println(it1 == i1);//true
System.out.println(it3 == i1)//true
如果是两个包装类进行比较会有以下几种情况
(1)包装类的实例实际上是引用类型,所以比较的是对象地址,两个不同的对象比较,为false
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
-----------------------------------------------------------------------------------------------
[-128,127]之间,那么直接返回内部的缓冲数组中的数据,
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false
7. Integer和int区别
(1)Integer是int的包装类;int是基本数据类型;
(2)Integer变量必须实例化后才能使用;int变量不需要;
(3)Integer实际是对象的引用,指向此new的Integer对象;int是直接存储数据值 ;
(4)Integer的默认值是null;int的默认值是0
(5) Integer支持泛型,int不支持
8. 自动装箱与拆箱
装箱:将基本类型—转换成—对应的包装类;
拆箱:将包装类型—转换成—基本数据类型;
Java使用自动装箱和拆箱机制,节省了常用数值的内存开销和创建对象的开销,提高了效率,由编译器来完成,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。
9. 5个运行异常 5个非运行异常
运行时异常
ClassCastException 类转换异常
illegalArgumentException 非法参数异常
IndexOutOfBoundsException 下标越界异常
NullPointerException 空指针异常
java.util.NoSuchElementException - 不存在此元素
java.lang.ArithmeticException - 计算异常 - 分母为0
非运行时异常
java.io.IOExcetion - IO流异常
java.sql.SQLException - SQL异常
java.text.ParseException - 解析失败异常 - 字符串的模板和pattern不匹配
InterruptedException - 中断异常 - Thread.sleep(1000);
java.lang.CloneNotSupportedException - 不允许被clone.
10. 5个String常用api
indexOf()返回指定字符串在该字符串出现的序列
startsWith()判断该字符串是否以指定字符开始
endsWith()判断该字符串是否以指定字符串结尾
concat() 将指定字符串连接在该字符串的结尾
length()返回字符串的长度
substring(int start,int end) // 截取字符串 从start开始 ,到end-1为止 生成一个新串返回
trim 去掉字符串前后的空格
charAt(index)返回下标对应的字符