包装类

包装类的分类

黄色父类都是Object

第13章 常用类 - 图1

包装类和基本数据的转换

jdk5 前,是手动装箱和拆箱

jdk5 后,就可以自动装箱和自动拆箱

  1. public class Integer01 {
  2. public static void main(String[] args) {
  3. //演示 int <--> Integer 的装箱和拆箱
  4. //jdk5 前是手动装箱和拆箱
  5. //手动装箱 int->Integer
  6. int n1 = 100;
  7. Integer integer = new Integer(n1);
  8. Integer integer1 = Integer.valueOf(n1);
  9. //手动拆箱
  10. //Integer -> int
  11. int i = integer.intValue();
  12. //jdk5 后,就可以自动装箱和自动拆箱
  13. int n2 = 200;
  14. //自动装箱 int->Integer
  15. Integer integer2 = n2; //底层使用的是 Integer.valueOf(n2)
  16. //自动拆箱 Integer->int
  17. int n3 = integer2; //底层仍然使用的是 intValue()方法
  18. }
  19. }

包装类型和 String 类型的相互转换 Wrapper VS String

  1. public class WrapperVSString {
  2. public static void main(String[] args) {
  3. //包装类(Integer)->String
  4. Integer i = 100;//自动装箱
  5. //方式 1
  6. String str1 = i + "";
  7. //方式 2
  8. String str2 = i.toString();
  9. //方式 3
  10. String str3 = String.valueOf(i);
  11. //String -> 包装类(Integer)
  12. String str4 = "12345";
  13. Integer i2 = Integer.parseInt(str4);//使用到自动装箱
  14. Integer i3 = new Integer(str4);//构造器
  15. System.out.println("ok~~");
  16. }
  17. }

Integer 类和 Character 类的常用方法

  1. public class WrapperMethod {
  2. public static void main(String[] args) {
  3. System.out.println(Integer.MIN_VALUE); //返回最小值
  4. System.out.println(Integer.MAX_VALUE);//返回最大值
  5. System.out.println(Character.isDigit('a'));//判断是不是数字
  6. System.out.println(Character.isLetter('a'));//判断是不是字母
  7. System.out.println(Character.isUpperCase('a'));//判断是不是大写
  8. System.out.println(Character.isLowerCase('a'));//判断是不是小写
  9. System.out.println(Character.isWhitespace('a'));//判断是不是空格
  10. System.out.println(Character.toUpperCase('a'));//转成大写
  11. System.out.println(Character.toLowerCase('A'));//转成小写
  12. }
  13. }

课堂测试题(很重要)

第13章 常用类 - 图2

三目运算符是一个整体如果有double,会把精度调为0.0

if else 则不是

Integer 类面试题 1 WrapperExercise02.java

  1. public class WrapperExercise02 {
  2. public static void main(String[] args) {
  3. Integer i = new Integer(1);
  4. Integer j = new Integer(1);
  5. System.out.println(i == j); //False
  6. //所以,这里主要是看范围 -128 ~ 127 就是直接返回
  7. /*
  8. public static Integer valueOf(int i) {
  9. if (i >= IntegerCache.low && i <= IntegerCache.high)
  10. return IntegerCache.cache[i + (-IntegerCache.low)];
  11. return new Integer(i);
  12. }
  13. */
  14. Integer m = 1; //底层 Integer.valueOf(1); -> 阅读源码
  15. Integer n = 1;//底层 Integer.valueOf(1);
  16. System.out.println(m == n); //T
  17. //所以,这里主要是看范围 -128 ~ 127 就是直接返回
  18. //,否则,就 new Integer(xx);
  19. Integer x = 128;//底层 Integer.valueOf(1);
  20. Integer y = 128;//底层 Integer.valueOf(1);
  21. System.out.println(x == y);//False
  22. }
  23. }

解读:

  1. 如果 i 在 IntegerCache.low(-128)~IntegerCache.high(127),就直接从数组返回

  2. 如果不在 -128~127,就直接 new Integer(i)

  1. public class WrapperExercise03 {
  2. public static void main(String[] args) {
  3. //示例一
  4. Integer i1 = new Integer(127);
  5. Integer i2 = new Integer(127);
  6. System.out.println(i1 == i2);//F
  7. //示例二
  8. Integer i3 = new Integer(128);
  9. Integer i4 = new Integer(128);
  10. System.out.println(i3 == i4);//F
  11. //示例三
  12. Integer i5 = 127;//底层 Integer.valueOf(127)
  13. Integer i6 = 127;//-128~127
  14. System.out.println(i5 == i6); //T
  15. //示例四
  16. Integer i7 = 128;
  17. Integer i8 = 128;
  18. System.out.println(i7 == i8);//F
  19. //示例五
  20. Integer i9 = 127; //Integer.valueOf(127)
  21. Integer i10 = new Integer(127);
  22. System.out.println(i9 == i10);//F
  23. //示例六
  24. Integer i11=127;
  25. int i12=127;
  26. //只有有基本数据类型,判断的是
  27. //值是否相同
  28. System.out.println(i11==i12); //T
  29. //示例七
  30. Integer i13=128;
  31. int i14=128;
  32. System.out.println(i13==i14);//T
  33. }
  34. }

第一代日期类

  1. Date : 精确到毫秒,代表特定的瞬间

  2. SimpleDateFormat : 格式的解析日期的类
    SimpleDateFormat : 格式化的解析日期的具体类
    他允许进行格式化(日期 -> 文本),解析(文本 -> 日期)和规范化

Date

  1. 获取当前系统时间

  2. 这里的 Date 类是在 java.util 包

  3. 默认输出的日期格式是国外的方式, 因此通常需要对格式进行转换

    1. Date d1 = new Date(); //获取当前系统时间
    2. System.out.println("当前日期=" + d1);
    3. Date d2 = new Date(9234567); //通过指定毫秒数得到时间
    4. System.out.println("d2=" + d2); //获取某个时间对应的毫秒数

第13章 常用类 - 图3

  1. 创建 SimpleDateFormat 对象,可以指定相应的格式

  2. 这里的格式使用的字母是规定好,不能乱写
    format:将日期转换成指定格式的字符串

  1. SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 hh:mm:ss E");
  2. String format = sdf.format(d1); // format:将日期转换成指定格式的字符串
  3. System.out.println("当前日期=" + format);
  1. 可以把一个格式化的 String 转成对应的 Date

  2. 得到 Date 仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换

  3. 在把 String -> Date , 使用的 sdf 格式需要和你给的 String 的格式一样,否则会抛出转换异常
    parse():将指定格式字符串转换成日期

  1. String s = "1996 年 01 月 01 日 10:20:30 星期一";
  2. Date parse = sdf.parse(s);
  3. System.out.println("parse=" + sdf.format(parse));

第二代日期类

calendar(日历)类

  1. Calendar 是一个抽象类, 并且构造器是 private

  2. 可以通过 getInstance() 来获取实例

  3. 提供大量的方法和字段提供给程序员

  4. Calendar没有提供对应的格式化的类,因此需要程序员自己组合来输出(灵活)

  5. 如果我们需要按照 24小时进制来获取时间
    Calendar.HOUR ==改成=> Calendar.HOUR_OF_DAY

  1. Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
  2. System.out.println("c=" + c);
  3. //2.获取日历对象的某个日历字段
  4. System.out.println("年:" + c.get(Calendar.YEAR));
  5. // 这里为什么要 + 1, 因为Calendar 返回月时候,是按照 0 开始编号
  6. System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
  7. System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
  8. System.out.println("小时:" + c.get(Calendar.HOUR));
  9. System.out.println("分钟:" + c.get(Calendar.MINUTE));
  10. System.out.println("秒:" + c.get(Calendar.SECOND));
  11. //Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
  12. System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH) +
  13. " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND) );

使用get()方法调用属性

Calendar 返回月时候,是按照 0 开始编号

第三代日期类

  1. LocalDate(日期/年月日),LocalTime(时间/时分秒),LocalDateTime(日期时间/年月日时分秒) JDK8加入

  2. LocalDate只包含日期,可以获取日期字段
    LocalTime只包含时间,可以获取时间字段
    LocalDateTime包含日期+时间,可以获取日期和时间字段

  1. //1. 使用 now() 返回表示当前日期时间的 对象
  2. LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now();//LocalTime.now()
  3. System.out.println(ldt);
  4. //2. 使用 DateTimeFormatter 对象来进行格式化
  5. // 创建 DateTimeFormatter 对象
  6. DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  7. String format = dateTimeFormatter.format(ldt);
  8. System.out.println("格式化的日期=" + format);
  9. System.out.println("年=" + ldt.getYear());
  10. System.out.println("月=" + ldt.getMonth());
  11. System.out.println("月=" + ldt.getMonthValue());
  12. System.out.println("日=" + ldt.getDayOfMonth());
  13. System.out.println("时=" + ldt.getHour());
  14. System.out.println("分=" + ldt.getMinute());
  15. System.out.println("秒=" + ldt.getSecond());
  16. LocalDate now = LocalDate.now(); //可以获取年月日
  17. LocalTime now2 = LocalTime.now();//获取到时分秒
  18. //提供 plus 和 minus 方法可以对当前时间进行加或者减
  19. //看看 890 天后,是什么时候 把 年月日-时分秒
  20. LocalDateTime localDateTime = ldt.plusDays(890);
  21. System.out.println("890 天后=" + dateTimeFormatter.format(localDateTime));
  22. //看看在 3456 分钟前是什么时候,把 年月日-时分秒输出
  23. LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
  24. System.out.println("3456 分钟前 日期=" + dateTimeFormatter.format(localDateTime2));
  1. 使用 now() 返回表示当前日期时间的 对象
    1. LocalDateTime ldt = LocalDateTime.now();
  1. 使用 DateTimeFormatter 对象来进行格式化
    1. DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    2. String format = dateTimeFormatter.format(ldt);

Instant 时间戳

  1. 通过 静态方法 now() 获取表示当前时间戳的对象
    1. //1.通过 静态方法 now() 获取表示当前时间戳的对象
    2. Instant now = Instant.now();
    3. System.out.println(now);
  1. 通过 from 可以把 Instant 转成 Date
    1. //2. 通过 from 可以把 Instant 转成 Date
    2. Date date = Date.from(now);
  1. 通过 date 的 toInstant() 可以把 date 转成 Instant 对象
    1. //3. 通过 date 的 toInstant() 可以把 date 转成 Instant 对象
    2. Instant instant = date.toInstant();

字符串的特性

  1. String是一个final类,代表不可变的字符序列
  2. 字符串是不可变.一个字符串对象一旦被分配,内容是不可变的.
  1. 以下语句创建了几个对象:
  2. String s1 = "hello";
  3. s1 = "haha";
  4. 两个
  1. 以下语句创建了几个对象:
  2. String s1 = "hello"+"abc";
  3. 只有一个
  1. 编译器会做一个优化,判断创建的常量池对象,是否有引用指向

  2. String a = “hello” + “abc”; —-> String a = “helloabc”;

  1. 以下语句创建了几个对象:
  2. String a = "hello";
  3. String b = "abc";
  4. String c = a + b;

底层:

  1. 先创建一个StringBuilder sb = StringBuilder()

  2. 执行sn.append("hello")
    现版本: indexCoder = prepend(indexCoder, buf, s2);

  3. 执行sb.append("abc")
    现版本:indexCoder = prepend(indexCoder, buf, s1);

  4. 执行String c = sb.toString()

  5. 最后是 c 指向堆中的sb对象(String) value[] —> 池中的 “helloabc”
    因为toString方法的底层是

    1. static String simpleConcat(Object first, Object second) {
    2. String s1 = stringOf(first);
    3. String s2 = stringOf(second);
    4. // start "mixing" in length and coder or arguments, order is not
    5. // important
    6. long indexCoder = mix(initialCoder(), s2);
    7. indexCoder = mix(indexCoder, s1);
    8. byte[] buf = newArray(indexCoder);
    9. // prepend each argument in reverse order, since we prepending
    10. // from the end of the byte array
    11. indexCoder = prepend(indexCoder, buf, s2);
    12. indexCoder = prepend(indexCoder, buf, s1);
    13. return newString(buf, indexCoder);
    14. }

重要规则:如果是两个常量相加,看的是池。String c1 = a + b; 变量相加是在堆中

Arrays

1. toString

返回数组的字符串形式

Arrays.toString(arr)

2. sort排序(自然排序和制定排序)

  1. 可以直接使用冒泡排序 , 也可以直接使用 Arrays 提供的 sort 方法排序
  2. 因为数组是引用类型,所以通过 sort 排序后,会直接影响到 实参 arr
  3. sort 重载的,也可以通过传入一个接口 Comparator 实现定制排序
  4. 调用 定制排序 时,传入两个参数 (1) 排序的数组 arr (2) 实现了 Comparator 接口的匿名内部类 , 要求实现 compare 方法
  5. 先演示效果,再解释
  6. 这里体现了接口编程的方式 , 看看源码,就明白

源码分析:

(1) Arrays.sort(arr, new Comparator()

(2) 最终到 TimSort 类的 private static void binarySort(T[] a, int lo, int hi, int start, Comparator c)()

(3) 执行到 binarySort 方法的代码, 会根据动态绑定机制 c.compare()执行我们传入的 // 匿名内部类的 compare ()

  1. if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
  2. while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
  3. runHi++;
  4. reverseRange(a, lo, runHi);
  5. } else { // Ascending
  6. while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
  7. runHi++;
  8. }
  9. return runHi - lo;
  10. }

(4)

  1. new Comparator() {
  2. @Override
  3. public int compare(Object o1, Object o2) {
  4. Integer i1 = (Integer) o1;
  5. Integer i2 = (Integer) o2;
  6. return i2 - i1;
  7. }
  8. }

(5) public int compare(Object o1, Object o2) 返回的值>0 还是 <0 // 会影响整个排序结果, 这就充分体现了 接口编程+动态绑定+匿名内部类的综合使用 将来的底层框架和源码的使用方式,会非常常见

Arrays.sort(arr); // 默认排序方法 //定制排序

  1. Arrays.sort(arr, new Comparator() {
  2. @Override
  3. public int compare(Object o1, Object o2) {
  4. Integer i1 = (Integer) o1;
  5. Integer i2 = (Integer) o2;
  6. return i2 - i1;
  7. }
  8. });
  9. System.out.println("===排序后===");
  10. System.out.println(Arrays.toString(arr));

3.接口+动态排序实现(一天看一遍)

  1. public class ArraysSortCustom {
  2. public static void main(String[] args) {
  3. int[] arr = {1, -1, 8, 0, 20};
  4. //bubble01(arr);
  5. bubble02(arr, new Comparator() {
  6. @Override
  7. public int compare(Object o1, Object o2) {
  8. int i1 = (Integer) o1;
  9. int i2 = (Integer) o2;
  10. return i2 - i1;// return i2 - i1;
  11. }
  12. });
  13. System.out.println("==定制排序后的情况==");
  14. System.out.println(Arrays.toString(arr));
  15. }
  16. //结合冒泡 + 定制
  17. public static void bubble02(int[] arr, Comparator c) {
  18. int temp = 0;
  19. for (int i = 0; i < arr.length - 1; i++) {
  20. for (int j = 0; j < arr.length - 1 - i; j++) {
  21. //数组排序由 c.compare(arr[j], arr[j + 1])返回的值决定
  22. if (c.compare(arr[j], arr[j + 1]) > 0) {
  23. temp = arr[j];
  24. arr[j] = arr[j + 1];
  25. arr[j + 1] = temp;
  26. }
  27. }
  28. }
  29. }
  30. }

4.binarySearch通过二分搜索法查找,要求必须排好序

  1. int index = Arrays.binarySearch(arr,3);
  1. 使用 binarySearch 二叉查找
  2. 要求该数组是有序的. 如果该数组是无序的,不能使用 binarySearch
  3. 如果数组中不存在该元素,就返回 return -(low + 1); // key not found.

5. copyOf 数组元素的复制

  1. 从 arr 数组中,拷贝 arr.length 个元素到 newArr 数组中
  2. 如果拷贝的长度 > arr.length 就在新数组的后面 增加 null
  3. 如果拷贝长度 < 0 就抛出异常 NegativeArraySizeException
  4. 该方法的底层使用的是 System.arraycopy()

BigInteger和BigDecimal类

应用场景:

  1. BigInteger适合保存比较大的整形

  2. BigDecimal适合保存精度更高的浮点型(小数)
    当我们编程中,需要处理很大的整数,long 不够用 可以使用 BigInteger 的类来搞定

    1. BigInteger bigInteger = new BigInteger("23788888899999999999999999999");
    2. BigInteger bigInteger2 = new
    3. BigInteger("10099999999999999999999999999999999999999999999999999999999999999999999999999999999");
    4. System.out.println(bigInteger);


当我们需要保存一个精度很高的数时,double 不够用 可以使用 BigDecimal

  1. double d = 1999.11111111111999999999999977788d;
  2. // System.out.println(d);
  3. BigDecimal bigDecimal = new BigDecimal("1999.11");
  4. BigDecimal bigDecimal2 = new BigDecimal("3");
  5. System.out.println(bigDecimal);

BigInteger运算

  1. 在对 BigInteger 进行加减乘除的时候,需要使用对应的方法,不能直接进行 + - * /
  2. 可以创建一个 要操作的 BigInteger 然后进行相应操作
  1. BigInteger add = bigInteger.add(bigInteger2);
  2. System.out.println(add);//加
  3. BigInteger subtract = bigInteger.subtract(bigInteger2);
  4. System.out.println(subtract);//减
  5. BigInteger multiply = bigInteger.multiply(bigInteger2);
  6. System.out.println(multiply);//乘
  7. BigInteger divide = bigInteger.divide(bigInteger2);
  8. System.out.println(divide);//除

BigDecimal运算

  1. 如果对 BigDecimal 进行运算,比如加减乘除,需要使用对应的方法
  2. 创建一个需要操作的 BigDecimal 然后调用相应的方法即可
  1. System.out.println(bigDecimal.add(bigDecimal2));
  2. System.out.println(bigDecimal.subtract(bigDecimal2));
  3. System.out.println(bigDecimal.multiply(bigDecimal2));
  4. System.out.println(bigDecimal.divide(bigDecimal2));
  5. //可能抛出异常 ArithmeticException
  6. //在调用 divide 方法时,指定精度即可. BigDecimal.ROUND_CEILING
  7. //如果有无限循环小数,就会保留 分子 的精度
  8. System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));

math类

  1. public class MathMethod {
  2. public static void main(String[] args) {
  3. //看看 Math 常用的方法(静态方法)
  4. //1.abs 绝对值
  5. int abs = Math.abs(-9);
  6. System.out.println(abs);//9
  7. //2.pow 求幂
  8. double pow = Math.pow(2, 4);//2 的 4 次方
  9. System.out.println(pow);//16
  10. //3.ceil 向上取整,返回>=该参数的最小整数(转成 double);
  11. double ceil = Math.ceil(3.9);
  12. System.out.println(ceil);//4.0
  13. //4.floor 向下取整,返回<=该参数的最大整数(转成 double)
  14. double floor = Math.floor(4.001);
  15. System.out.println(floor);//4.0
  16. //5.round 四舍五入 Math.floor(该参数+0.5)
  17. long round = Math.round(5.51);
  18. System.out.println(round);//6
  19. //6.sqrt 求开方
  20. double sqrt = Math.sqrt(9.0);
  21. System.out.println(sqrt);//3.0
  22. //7.random 求随机数
  23. // random 返回的是 0 <= x < 1 之间的一个随机小数
  24. // 思考:请写出获取 a-b 之间的一个随机整数,a,b 均为整数 ,比如 a = 2, b=7
  25. // 即返回一个数 x 2 <= x <= 7
  26. // 老韩解读 Math.random() * (b-a) 返回的就是 0 <= 数 <= b-a
  27. // (1) (int)(a) <= x <= (int)(a + Math.random() * (b-a +1) )
  28. // (2) 使用具体的数给小伙伴介绍 a = 2 b = 7
  29. // (int)(a + Math.random() * (b-a +1) ) = (int)( 2 + Math.random()*6)
  30. // Math.random()*6 返回的是 0 <= x < 6 小数
  31. // 2 + Math.random()*6 返回的就是 2<= x < 8 小数
  32. // (int)(2 + Math.random()*6) = 2 <= x <= 7
  33. // (3) 公式就是 (int)(a + Math.random() * (b-a +1) )
  34. for(int i = 0; i < 100; i++) {
  35. System.out.println((int)(2 + Math.random() * (7 - 2 + 1)));
  36. }
  37. //max , min 返回最大值和最小值
  38. int min = Math.min(1, 9);
  39. int max = Math.max(45, 90);
  40. System.out.println("min=" + min);
  41. System.out.println("max=" + max);
  42. }
  43. }

reserve方法

将字符串中指定部分翻转

  1. String str = "abcdef";
  2. System.out.println("===交换前===");
  3. System.out.println(str);
  4. try {
  5. str = reverse(str, 1, 4);
  6. } catch (Exception e) {
  7. System.out.println(e.getMessage());
  8. return;
  9. }
  10. System.out.println("===交换后===");
  11. System.out.println(str);

String VS StringBuffer VS StringBuilder

  1. StringBuilder 和 StringBuffer 非常相似,均代表可变的字符序列,而且方法也一样

  2. String : 不可变字符序列,效率低.但是复用率高

  3. StringBuffer : 可变字符序列,效率较发哦(增删),线程安全,看源码

  4. StringBuilder : 可变字符序列,效率最高,线程不安全

  5. String使用注意说明 :
    string s = "a"; 创建了一个字符串
    s += "b"; 实际上原来的”a”字符串对象已经丢了,现在又产生了一个字符串s + “b”(也就是”ab”).如果多次执行这些改变串内容的操作,会导致大量副本字符串0对象存留在内存中,降低效率.如果这样的操作放到循环中,会极大影响程序的性能 => 结论:

    1. 如果字符串存在大量的修改操作,一般使用StringBuffer和StringBuilder.

    2. 如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder.

    3. 如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer.

    4. 如果我们的字符串很少修改,被多个对象引用,使用String,比如配置信息等.

效率: StringBuilder > StringBuffer > String

String类

String 类的理解和创建对象

第13章 常用类 - 图4

  1. String 对象用于保存字符串,也就是一组字符序列

  2. “jack” 字符串常量, 双引号括起的字符序列

  3. 字符串的字符使用 Unicode 字符编码,一个字符(不区分字母还是汉字)占两个字节

  4. String 类有很多构造器,构造器的重载
    常用的有 :
    String s1 = new String();
    String s2 = new String(String original);
    String s3 = new String(char[] a);
    String s4 = new String(char[] a,int startIndex,int count)
    String s5 = new String(byte[] b)

  5. String 类实现了
    接口 Serializable【String 可以串行化:可以在网络传输】
    接口 Comparable [String 对象可以比较大小]

  6. String 是 final 类,不能被其他的类继承

  7. String 有属性 private final char value[]; 用于存放字符串内容

  8. 一定要注意:value 是一个 final 类型, 不可以修改(需要功力):即 value 不能指向新的地址,但是单个字符内容是可以变化

String()方法

https://www.runoob.com/java/java-string.html

创建 String 对象的两种方式

  1. String s = "hsp";
  2. String s = new String("hsp");

两种创建 String 对象的区别

  1. 方式一:先从常量池查看是否有”hsp”数据空间,如果有,直接指向;如果没有则重新创建,然后指向.s最终指向的是常量池的空间地址

  2. 方式二:先从堆中创建空间,里面维护了value属性,指向常量池的hsp空间.如果常量池没有”hsp”,重新创建,如果有,直接通过value指向.最终指向的是堆中的空间地址.
    第13章 常用类 - 图5

intern() 方法

https://blog.csdn.net/csdn_0911/article/details/79953177

  1. Q:下列程序的输出结果:
  2. String s1 = abc”;
  3. String s2 = abc”;
  4. System.out.println(s1 == s2);
  5. Atrue
  6. 分析一下:程序执行,常量池中生成一个字符串,并将栈中的引用指向 s1s2 先去查询常量池中是否有已经存在,存在,则返回常量池中的引用,所以s1 = s2
  1. Q:下列程序的输出结果:
  2. String s1 = new String(“abc”);
  3. String s2 = new String(“abc”);
  4. System.out.println(s1 == s2);
  5. Afalse,两个引用指向堆中的不同对象。
  6. 分析一下:第一步、常量池中生成一个字符串“abc”,并在堆中生成一个s1引用指向的对象,第二步、先去查询常量池中是否有已经存在“abc”,因为已经存在,所以不在生成,但堆中仍然会生成一个s2引用指向的对象,所以s1 s2引用不一样。
  1. Q:下列程序的输出结果:
  2. String s1 = abc”;
  3. String s2 = a”;
  4. String s3 = bc”;
  5. String s4 = s2 + s3;
  6. System.out.println(s1 == s4);
  7. Afalse,因为s2+s3实际上是使用StringBuilder.append来完成,会生成不同的对象。
  8. 分析一下:程序执行,s1,s2,s3在常量池中分别生成字符串,并将栈中的引用指向s1,s2,s3,而s4在编译的时候,其方法内部创建StringBuilder来拼接对象,在堆中生成了新的对象。

引号声明的字符串都是会直接在字符串常量池中生成的,而 new 出来的 String 对象是放在堆空间中的。

  1. public static void main(String[] args) {
  2. String str1 = "abc";
  3. String str2 = new String("abc");
  4. String str3 = str2.intern();
  5. System.out.println(str1==str2);//#1
  6. System.out.print (str1==str3);//#2
  7. }
  8. 输出结果为: false true
  9. #1str1指向常量池中的对象引用,str2指向堆中的对象引用,所以返回false;
  10. #2str2.intern()指向str1的在常量池中的对象引用,所以str1==str3
  1. public static void main(String[] args) {
  2. String abc = "abc";
  3. final String abcFinal = "abc";
  4. String str1 = "abc01";
  5. String str2 = "abc"+"01";
  6. String str3 = abc + "01";
  7. String str4 = abcFinal+"01";
  8. String str5 = new String("abc01").intern();
  9. System.out.println(str1 == str2);//#3
  10. System.out.println(str1 == str3);//#4
  11. System.out.println(str1 == str4);//#5
  12. System.out.println(str1 == str5);//#6
  13. }
  14. 输出的结果为:true false true true
  15. #3str1指向常量池中的对象引用,而str2在编译期间,+号会自动合并为一个字符串,因为常量池中已经生成了str1的对象,所以str2不在生成,直接将常量池对象的引用赋值给栈中的str2
  16. #4str4实际上是使用StringBuilder.append来完成,会生成不同的对象。
  17. #5final修饰的变量,在编译期间会自动进行常量替换,这是与#4不同。所以不在生成新的对象,直接将常量池对象的引用str1赋值给栈中的str4
  18. #6:都是指向常量池中的对象引用。
  1. public static void main(String[] args) {
  2. String str2 = new String("abc")+new String("01");
  3. str2.intern();
  4. String str1 = "abc01";
  5. System.out.println(str2==str1);//#7
  6. }
  7. 输出的结果为:true
  8. #8str1指向常量池中的对象引用,而str2指向堆中的对象引用,并在常量池生成俩个对象,“abc”和“01”,接着str2.intern()返回str1指向常量池中的对象引用,但是对于str2没有影响,结果为false,如果是str2 = str2.intern();则最终结果将是true

当调用 intern 方法是,如果池已经包含一个等于此 String 对象的字符串(用equals(Object)方法确定),则返回池中的字符串.否则,将此String对象添加到池中,并返回此String对象的引用.

b,intern()方法最终返回的是常量池的地址(对象)

format()方法

http://c.biancheng.net/view/4700.html

语法1

  1. format(String format,Object……args)

参数说明:

  • format:格式字符串。
  • args:格式字符串中由格式说明符引用的参数。参数数目是可变的,可以为 0。

第13章 常用类 - 图6

charAt()方法

charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。

  1. public char charAt(int index)

substring() 方法

  1. public String substring(int beginIndex)
  2. public String substring(int beginIndex, int endIndex)

第13章 常用类 - 图7

StringBuffer类

基本介绍

  1. StringBuffer代表可变的字符序列,可以对字符内容进行增删.
  2. 很多方法与String相同,但StringBuffer是可变长度的
  3. StringBuffer是一个容器

基础

  1. StringBuffer 的直接父类 是 AbstractStringBuilder

  2. StringBuffer 实现了 Serializable, 即 StringBuffer 的对象可以串行化

  3. 在父类中 AbstractStringBuilder 有属性 char[] value,不是 final
    该 value 数组存放 字符串内容不是final的,因此存放在堆中的 (不在常量池)

  4. StringBuffer 是一个 final 类,不能被继承

  5. 因为 StringBuffer 字符内容是存在 char[] value, 所有在变化(增加/删除)

String VS StringBuffer

  1. String保存的是字符串常量,里面的值不能修改,每次String类的更新实际上就是更改地址,效率低(根本原因是final类型的char数组
    1. private final char value[]


存放在常量池中

  1. StringBuffer 保存的是字符串变量,里面的值可以更改,每次StringBuffer实际上可以更新内容,不用每次更新地址,效率较高.(空间不够时,才更新地址)
    1. char[] value


存放在堆中

String -> StringBuffer

  1. String str = "hello tom";

方式一 : 使用构造器

注意 : 返回的才是StringBuffer对象,对str本身没有影响

  1. StringBuffer stringbuffer = new StringBuffer(str);

方式二 : 使用的是append方法

  1. StringBuffer stringBuffer1 = new StringBuffer();
  2. stringBuffer1 = stringBuffer1.append(str);

StringBuffer -> String

  1. StringBuffer stringBuffer3 = new StringBuffer("韩顺平教育");

方式 1 : 使用 StringBuffer 提供的 toString 方法

  1. String s = stringBuffer3.toString();

方式 2 : 使用构造器来搞定

  1. String s1 = new String(stringBuffer3);

StringBuffer方法

  1. public class StringBufferMethod {
  2. public static void main(String[] args) {
  3. StringBuffer s = new StringBuffer("hello");
  4. //增
  5. s.append(',');// "hello,"
  6. s.append("张三丰");//"hello,张三丰"
  7. s.append("赵敏").append(100).append(true).append(10.5);//"hello,张三丰赵敏 100true10.5" System.out.println(s);//"hello,张三丰赵敏 100true10.5"
  8. //删
  9. /*
  10. * 删除索引为>=start && <end 处的字符
  11. * 解读: 删除 11~14 的字符 [11, 14)
  12. */
  13. s.delete(11, 14);
  14. System.out.println(s);//"hello,张三丰赵敏 true10.5"
  15. //改
  16. //老韩解读,使用 周芷若 替换 索引 9-11 的字符 [9,11)
  17. s.replace(9, 11, "周芷若");
  18. System.out.println(s);//"hello,张三丰周芷若 true10.5"
  19. //查找指定的子串在字符串第一次出现的索引,如果找不到返回-1
  20. int indexOf = s.indexOf("张三丰");
  21. System.out.println(indexOf);//6
  22. //插
  23. //老韩解读,在索引为 9 的位置插入 "赵敏",原来索引为 9 的内容自动后移
  24. s.insert(9, "赵敏");
  25. System.out.println(s);//"hello,张三丰赵敏周芷若 true10.5"
  26. //长度
  27. System.out.println(s.length());//22
  28. System.out.println(s);
  29. }
  30. }

练习

  1. public class StringBufferExercise01 {
  2. public static void main(String[] args) {
  3. String str = null;// ok
  4. StringBuffer sb = new StringBuffer(); //ok
  5. sb.append(str);//需要看源码 , 底层调用的是 AbstractStringBuilder 的 appendNull
  6. System.out.println(sb.length());//4
  7. System.out.println(sb);//null
  8. //下面的构造器,会抛出 NullpointerException
  9. StringBuffer sb1 = new StringBuffer(str);//看底层源码 super(str.length() + 16);//直接抛出空指针异常NullpointerException
  10. System.out.println(sb1);
  11. }
  12. }

AbstractStringBuilder 的 appendNull

  1. private AbstractStringBuilder appendNull() {
  2. ensureCapacityInternal(count + 4);
  3. int count = this.count;
  4. byte[] val = this.value;
  5. if (isLatin1()) {
  6. val[count++] = 'n';
  7. val[count++] = 'u';
  8. val[count++] = 'l';
  9. val[count++] = 'l';
  10. } else {
  11. count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
  12. }
  13. this.count = count;
  14. return this;
  15. }

appendNull() 函数会把 null 放在数组 value 中

StringBuilder

基本介绍

  1. 一个可变的字符序列.此类提供一个与 StringBuffer 兼容的 API ,但不保证同步(StringBuilder 不是线程安全).该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候.如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快.

  2. 在 StringBuilder 上的主要操作是 append 和 insert 方法.可重载这些方法,以接收任意类型的数据.

  3. StringBuffer 的直接父类 是 AbstractStringBuilder

  4. StringBuffer 实现了 Serializable, 即 StringBuffer 的对象可以串行化

  5. 在父类中 AbstractStringBuilder 有属性 char[] value,不是 final
    该 value 数组存放 字符串内容,引出存放在堆中的

  6. StringBuffer 是一个 final 类,不能被继承

  7. 因为 StringBuffer 字符内容是存在 char[] value, 所有在变化(增加/删除)
    不用每次都更换地址(即不是每次创建新对象), 所以效率高于 String

System类

  1. exit 退出当前程序

    1. exit(0) 表示程序退出
    2. 0 表示一个状态 , 正常的状态
  2. arraycopy 复制数组元素,比较适合底层调用,一般使用 Arrays.copyOf 完成复制数组

    1. 主要是搞清楚这五个参数的含义

    2. 源数组
      * @param src the source array. // srcPos: 从源数组的哪个索引位置开始拷贝 // @param srcPos starting position in the source array. // dest : 目标数组,即把源数组的数据拷贝到哪个数组 // @param dest the destination array. // destPos: 把源数组的数据拷贝到 目标数组的哪个索引 // @param destPos starting position in the destination data. // length: 从源数组拷贝多少个数据到目标数组 // @param length the number of array elements to be copied | 含义 | 参数 | 内容 | | —- | —- | —- | | 源数组 | src | the source array | | 从源数组的哪个索引位置开始拷贝 | srcPos | starting position in the source array | | 目标数组,即把源数组的数据拷贝到哪个数组 | dest | the destination array | | 把源数组的数据拷贝到 目标数组的哪个索引 | destPos | starting position in the destination data. | | 从源数组拷贝多少个数据到目标数组 | length | the number of array elements to be copied |