1、昨日复习

  1. 画图说明线程的生命周期,以及各状态切换使用到的方法等状态,方法

  2. 同步代码块中涉及到同步监视器和共享数据,谈谈你对同步监视器和共享数据的理解,以及注意点。
    synchronized(同步监视器){
    //操作共享数据的代码(不能包括多了,也不能包括少了)
    }

  3. sleep()和wait()的区别

  4. 写一个线程安全的懒汉式

    1. class Bank{
    2. private Bank(){
    3. }
    4. private static Bank instance = null;
    5. public static Bank getInstance(){
    6. //方式一
    7. /* synchronized (Bank.class){
    8. if (instance == null){
    9. instance = new Bank();
    10. }
    11. return instance;
    12. }*/
    13. if (instance == null){
    14. synchronized (Bank.class){
    15. if (instance == null){
    16. instance = new Bank();
    17. }
    18. }
    19. }
    20. return instance;
    21. }
    22. }
  5. 创建多线程有哪几种方式:4种
    继承Thread类
    实现Runnable接口
    实现Callable接口
    线程池(响应速度提高了,提高了资源的重用率,便于管理)

    2、String类

    String的特性
    String类:代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
    String是一个final类,代表不可变的字符序列。
    字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
    String对象的字符内容是存储在一个字符数组value[]中的。
    QQ截图20220115101047.png

1、当前字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
2、当对现有的字符串进行连续操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
3、当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
QQ截图20220115103742.png


  1. @Test
  2. public void test2() {
  3. //通过字面量定义的方式:此时的s1和s2的数据JavaEE声明在方法区中的字符串常量池中。
  4. String s1 = "javaEE";
  5. String s2 = "javaEE";
  6. //通过new+构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
  7. String s3 = new String("javaEE");
  8. String s4 = new String("javaEE");
  9. System.out.println(s1 == s2);//true
  10. System.out.println(s1 == s3);//false
  11. System.out.println(s1 == s4);//false
  12. System.out.println(s3 == s4);//false
  13. }

QQ截图20220115104757.png
QQ截图20220115105226.png
QQ截图20220115105453.png
面试题:String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:“abc”


  1. @Test
  2. public void test3() {
  3. String s1 = "javaEE";
  4. String s2 = "hadoop";
  5. String s3 = "javaEEhadoop";
  6. String s4 = "javaEE" + "hadoop";
  7. String s5 = s1 + "hadoop";
  8. String s6 = "javaEE" + s2;
  9. String s7 = s1 + s2;
  10. System.out.println(s3 == s4);//true
  11. System.out.println(s3 == s5);//false
  12. System.out.println(s3 == s6);//false
  13. System.out.println(s3 == s7);//false
  14. System.out.println(s5 == s6);//false
  15. System.out.println(s5 == s7);//false
  16. System.out.println(s6 == s7);//false
  17. }

结论:
1、常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2、只要其中有一个是变量,结果就在堆中(相当于new了一个)
3、如果拼接的结果调用intern()方法,返回值就在常量池中


  1. //面试题
  2. package com.atguigu.java2;
  3. public class StringTest {
  4. String str = new String("good");
  5. char[] ch = {'t', 'e', 's', 't'};
  6. public void change(String str, char ch[]) {
  7. str = "test ok";
  8. ch[0] = 'b';
  9. }
  10. public static void main(String[] args) {
  11. StringTest ex = new StringTest();
  12. ex.change(ex.str, ex.ch);
  13. System.out.print(ex.str + " and ");//good and
  14. System.out.println(ex.ch);//best
  15. }
  16. }

3、String常用方法

QQ截图20220115144106.png
QQ截图20220115144119.png
QQ截图20220115144129.png


复习:
String 与基本数据类型、包装类之间的转换。
String—->基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)
基本数据类型、包装类—->String:调用String重载的valueOf(xxx)

String与char[]之间的转换
String—->char[]:调用String的toCharArray()
char[]—->String:调用String的构造器

String与byte[]之间的转换
String—->byte[]:调用String的getBytes()
byte[]—->String:调用String的构造器

4、StringBuffer和StringBuider的使用

String、StringBuffer、StringBuider三者的异同?
String:不可变的字符序列;底层使用char[]存储
StringBuffer:可变的字符序列,线程安全的,效率低;底层使用char[]存储
StringBuilder:可变的字符序列;线程不安全的,效率高;jdk5.0新增的;底层使用char[]存储

源码分析:
String str = new String();//char[] value = new char[0];
String str1 = new String();//char[] value = new char[0];

StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度是16的数组。
sb1.append(‘a’);//value[0]=’a’;
sb1.append(‘b’);//value[1]=’b’;

StringBuffer sb2 = new StringBuffer(“abc”);//char[] value = new char[“abc”.length()+16]

扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
默认情况下,扩容为原来容量的2倍+2,同时将原有的数组中的元素复制到新的数组中。

指导意义:开发中建议大家使用:StringBuffer(int capacity)或StringBuilder(int capacity);
QQ截图20220115173936.png
方法中范围只要涉及到开始和结束的都是左闭右开(左边是闭区间,右边是开区间)
QQ截图20220115174025.png
总结:
增:append(xxx);
删:delete(int start,int end);
改:setCharAt(int n,char ch)/replace(int start,int end,String str)
查:charAt(int n)
插:insert(int offset,xxx)
长度:length();
遍历:for()+charAt();/toString();
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样


  1. public void test2() {
  2. long startTime = 0L;
  3. long endTime = 0L;
  4. String text = "";
  5. StringBuffer buffer = new StringBuffer("");
  6. StringBuilder builder = new StringBuilder("");
  7. //开始对比
  8. startTime = System.currentTimeMillis();
  9. for (int i = 0; i < 20000; i++) {
  10. buffer.append(String.valueOf(i));
  11. }
  12. endTime = System.currentTimeMillis();
  13. System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
  14. startTime = System.currentTimeMillis();
  15. for (int i = 0; i < 20000; i++) {
  16. builder.append(String.valueOf(i));
  17. }
  18. endTime = System.currentTimeMillis();
  19. System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
  20. startTime = System.currentTimeMillis();
  21. for (int i = 0; i < 20000; i++) {
  22. text = text + i;
  23. }
  24. endTime = System.currentTimeMillis();
  25. System.out.println("String的执行时间:" + (endTime - startTime));
  26. }

5、JDK8之前日期时间API

QQ截图20220115182053.png
System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
此方法适于计算时间差。


java.util.Date类
|——-java.sql.Date类
1、两个构造器的使用
构造器一:new Date();创建一个对应当前时间的Date对象
构造器二:new Date(long time);创建指定毫秒数time的Date对象。
2、两个方法的使用
>toString():显示当前的年、月、日、时、分、秒
>getTime():获取当前Date对象对应的毫秒数。

3、java.sql.Date类对应着数据库中的日期类型的变量
>如何实例化? new Date(long time);创建指定毫秒数time的Date对象。
>如何将java.util.Date对象转换为java.sql.Date对象
情况一:多态中子父类中的强转
情况二:Date date= new Date();
java.sql.Date date1 = new java.sql.Date(date.getTime());
尚硅谷宋红康第9章_Java常用类.pdf