目录
方式二:调用构造器创建 String s = new String("ww")
2、String、StringBuilder、StringBuffer的比较
针对八种基本数据类型相应的引用类型 ---包装类
有了类的特点,就可以调用类中的方法了
| 基本数据类型 | 包装类 |
|---|---|
| boolean | Boolean |
| char | Charater |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
加粗的包装类的父类都是 Number
jdk5前是手动装箱和拆箱的 装箱(基本类型 -> 包装类型) 反之是拆箱
(只要是基本数据类型都可以char 和boolean也一样)
jdk5之后(含jdk5)就有了自动装箱和拆箱
自动装箱底层调用的是 valueOf()方法 比如int --> Integer 就是调用Integer.valueOf(int a);

4.自动拆箱底层调用的是 XXXValue()方法 比如 Integer --> int 就是调用new Integer().intValue(Integer i);

面试题
- Object obj1 = true ? new Integer(1) : new Double(2.0);
- System.out.println(obj1);
输出结果?
答案是 1.0 三元运算法是一个整体,会将new Integer() 的结果变成Double精度 所以出来的是1.0而不是1
- public class WrapperTest {
- public static void main(String[]args){
- //获取最小值
- int minValue = Integer.MIN_VALUE;
- //获取最大值
- int maxValue = Integer.MAX_VALUE;
-
- //判断是不是数字
- boolean a = Character.isDigit('a');
- //判断是不是字母
- boolean b = Character.isLetter('b');
- //判断是不是大写
- boolean a1 = Character.isUpperCase('a');
- //判断是不是小写
- boolean c = Character.isLowerCase('c');
- //判断是不是空格
- boolean whitespace = Character.isWhitespace(' ');
- //转换成大写
- char a2 = Character.toUpperCase('a');
- //转换成小写
- char a3 = Character.toLowerCase('A');
- }
- }
经典面试题
- public void method1() {
-
- Integer i =new Integer(1);
- Integer j =new Integer(1);
- System.out.println(i == j); //false
-
- Integer m = 1;
- Integer n = 1;
- System.out.println(m == n); //true
-
- Integer x = 128;
- Integer y = 128;
- System.out.println(x == y); //false
-
- }
== 引用数据类型比较的是地址是否相同
第一个 只要new就是创建一个新的对象 因此返回false
第二个 这个就涉及Integer 自动装箱的底层原理, 我们知道Integer自动装箱实际上是调用了ValueOf()方法
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
//如果不符合才创建新的对象
return new Integer(i);
}
因此这个是关键
if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)];
通过源码可以看到
static final int low = -128;
static final int high;
static {
h = 127
}
/*
所以知道数字在-128 到127之间的数都是从 数组中取
因此如何符合这个范围 取到的都是同一个对象
因此 第二个 得到true
第三个128 不在这个范围 得到的是false
*/
习题二
- Integer i = 127;
- int j =127;
- System.out.println(i == j)
//这里如果有基本数据类型,判断的是值是否相同 所以是true
字符串字符使用Unicode字符编码,一个字符不管是字母还是汉字都是占两个字节

String 是一个final修饰的类 代表String不能被继承
String的存储是通过 字符数组存储的,真正存储字符串内容的是通过这个数组
/** The value is used for character storage. 该值用于字符存储。 */ private final char value[];
注意这个 value是一个final类型 不可修改 --》是地址不可以修改 但是可以修改字符数组中内容的(但是这个字符数组还是private的,并且没有提供外部访问方法,因此只要字符串值改变了就是地址就发生了改变)
先从常量池查看是否有"ww"数据空间,如果有,直接指向;如果没有则重写创建,然后指向。S最终指向的是常量池中的空间地址
先在堆中创建空间,里面维护了value属性,指向常量池"ww"的空间。如果常量池没有,重新后仓健,如果有直接通过value指向。最终指向的是堆中空间地址
内存分析图

面试题
String a = "hello" + "world" ;
创建了几个对象?
只是创建了一个对象 helloworld
编译器不是傻子,这里做了优化,判断创建的常量池对象,是否有引用
(正常我们思路是创建三个 hello 、world、helloworld,但是hello和world没有引用,因此不创建 只创建一个helloworld)
面试题2
String a ="hello"
String b = "abc"
String c =a + b
创建了几个对象?并画出内存图
我认为创建了6个对象(不要纠结创建了几个对象,重点看内存分析)
常量池中 hello abc helloabc 三个对象
堆中创建了StringBuilder 、 创建了一个新的String赋值给了c 、然后StringBuilder还创建了char[]数组对象

证明代码:
- public class WrapperTest {
- public static void main(String[]args){
- String a ="hello";
- String b = "abc";
- String c =a + b;
- String d = "helloabc";
- String e = "hello" + "abc";
- System.out.println(c == d); //false
- System.out.println(d == e);//true
-
- }
- }
小结
String c1 =“ab” + "cd" 就是常量池相加
String a + b 就是引用相加,是在堆中的
equals 区分大小写,判断内容是否相等
equalsIgnoreCase 忽略大小写的判断内容是否相等
length 获取字符的个数, 即字符串长度
indexOf 获取字符在字符或者字符串在 字符串中第一次出现的索引,如果没有返回-1
lastIndexOf 获取字符或者字符串 在字符串中最后出现的索引 如果没有返回-1
substring 截取指定范围的子串
trim 去除前后空格
charAt 获取某索引出的字符,注意不能使用Str[index] 这个方式。
toUpperCase 转换为大写字母
toLowerCase 转换为小写字母
concat 连接字符串
replace 替换字符串中的字符
split 分割字符串,对应某些分割字符, 转换为字符串数组
compareTo 比较两个字符串大小
一个字符一个字符的进行比较,(c大于a 按照Asall码比较)
如果比较出来就返回 相减的值
如果长度和字符都一样则返回0
如果长度不相同,但是有的字符串都相同,返回长度差
toCharArray 转换为字符数组
format 格式化字符串 %s 字符串 %d整型 %.2f浮点型 %c字符
java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删
很多方法与String相同,但是StringBuffer是可变长度的,StringBuffer也是一个容器
StringBuffer的直接父类是AbstractStringBuffer
StringBuffer实现了 Serializable,即StringBuffer对象可以串行化(序列化)进行网络传输
在父类 AbstractStringBuffer 有属性char[] value,不是final类型
该value数组存放我们字符串内容,因此存放在堆中 ,不在是常量池了
StringBuffer也是一个final类,不能被继承
因为StringBuffer里面的值可以改变,每次StringBuffer更新内容,不用每次更新地址,效率相较于String是比较高的
- String str = null;
-
- StringBuffer sb = new StringBuffer();
-
- sb.append(str); //如果为null其实底层调用的是AbstractStringBuilder的appendNull()方法 将null加入进去
-
- System.out.println(sb.length()) ; //因此输出的4
-
- System.out.println(sb) ; //其实调用的toString方法 输出的是null字符串
-
- StringBuffer sb1 = new StringBuffer(str); //这里底层调用的是 Super(str.length()+16);
- //因此会出现异常 NullpointerException 空指针异常
StringBuilder与StringBuffer是类似的 ,只不过是StringBuilder是线程不安全的,效率更加高效
增 append()
删 delete(start,end)
替换 replace(start,end,str)
查 indexOf(str) 查找字符串第一次出现的索引,如果没有返回-1
插入 insert()
获取长度 length()
StringBuffer和StringBuilder非常相似,均代表可变的字符序列,而且方法是也一样
String:不可变字符序列,效率低,但是复用性高(常量池可以被多次使用)
StringBuffer可变字符序列,效率很高 是线程安全的
StringBuilder 可变字符序列 ,效率更高 ,是线程不安全的
如果频繁的修改String ,不建议使用String
使用结论
如果字符串存在大量的修改操作,一般使用StringBuffer或者StringBuilder
如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
如果字符串很少修改,被多个对象引用,使用String ,比如配置信息等
常用方法 都是静态方法 使用类名. 调用即可
abs绝对值
pow求幂(几次方)
ceil先上取整
floor向下取整
round四舍五入
sqrt求开方
random求随机数([0,1]的随机数)
max 求两个数的最大值
min求两个数的最小值
Arrays类里面包含了一系列的静态方法,用于管理或操作数组(比如排序和搜索)
toString返回数组的字符串形式 Arrays.toString(arr)
- public static void main(String[]args){
- int[] arr = {1, 20, 90};
- System.out.println(Arrays.toString(arr)); //[1, 20, 90]
- }
sort 排序 (自然排序和定制排序)
自然排序
- public static void main(String[]args){
- int[] arr = {1, -3, 4, 145, 90};
- System.out.println(Arrays.toString(arr));//[1, -3, 4, 145, 90]
- //排序
- Arrays.sort(arr);
- System.out.println(Arrays.toString(arr));//[-3, 1, 4, 90, 145]
- }
定制排序
- public static void main(String[]args){
- Integer[] arr = {1, -3, 4, 145, 90};
- System.out.println(Arrays.toString(arr));//[1, -3, 4, 145, 90]
-
- //排序定制排序 传入两个参数 第一个参数是要排序的数组 第二个参数是比较器
- //实现了Comparator接口的匿名内部类,要求实现compare接口
- //o1 - o2 是升序排序 o2 - o1 是降序排序
- Arrays.sort(arr, new Comparator
() { - @Override
- public int compare(Integer o1, Integer o2) {
- return o1 - o2;
- }
- });
- //lambda表达式可以写成
- /*
- Arrays.sort(arr, (o1,o2) -> o1 - o2);
- */
- System.out.println(Arrays.toString(arr));//[-3, 1, 4, 90, 145]
- }
binarySearch通过二分搜索法进行查找,要求必须排好序 Arrays.binarySearch(arr, target)
- public static void main(String[]args){
-
- Integer[] arr = {1, -3, 4, 145, 90};
- Arrays.sort(arr);
- //使用二分搜索查找 必须是排好序的
- //如果找到就返回索引
- System.out.println(Arrays.binarySearch(arr, 4)); //2
- //如果没有找到就返回 -(low + 1) low是应该存在的位置
- //{-3,1,4,90,145}
- //22 在4 和 90 之间 如果存在就是在 4的索引的后一位 即3
- System.out.println(Arrays.binarySearch(arr, 22)); //-4
- //-4 在-3 之后 如果存在 low等于0
- System.out.println(Arrays.binarySearch(arr, -4));//-1
- }
copyOf 数组元素复制
- public static void main(String[]args){
- Integer[] arr = {1, -3, 4, 145, 90};
- //从arr数组 拷贝arr.length到新数组中
- Integer[] integers = Arrays.copyOf(arr, arr.length);//[1, -3, 4, 145, 90]
- Integer[] integers2 = Arrays.copyOf(arr, 2); //[1, -3]
- Integer[] integers3 = Arrays.copyOf(arr, arr.length+1); //[1, -3, 4, 145, 90, null]
- System.out.println(Arrays.toString(integers));
- System.out.println(Arrays.toString(integers2));
- System.out.println(Arrays.toString(integers3));
- }
-
- 注入如果是第二个参数是负数 就会抛出异常
- 这个方法底层实际上使用的是System.arraycopy()
file 数组元素的填充
- public static void main(String[]args){
- Integer[] arr = {1, -3, 4, 145, 90};
- //从arr数组 拷贝arr.length到新数组中
- Arrays.fill(arr,99);
- System.out.println(Arrays.toString(arr)); //[99, 99, 99, 99, 99]
- }
equals 比较两个数组元素内容是否相同
- public static void main(String[]args){
- Integer[] arr = {1, -3, 4, 145, 90};
- Integer[] arr2 = {1, -3, 4, 145, 90};
- //从arr数组 拷贝arr.length到新数组中
- Integer[] arr3= {22,2};
- System.out.println(Arrays.equals(arr, arr2)); //true
- System.out.println(Arrays.equals(arr, arr3)); //false
- }
asList 将数组转换成List
- public static void main(String[]args){
- Integer[] arr = {1, -3, 4, 145, 90};
- List
integers = Arrays.asList(arr); - }
- 编译类型是 List 其实编译类型是ArrayList