Java基础----常用类

0. Intellij Idea

快捷键

ALT+SHIFT+0:生成构造器或setter、getter

IDEA的Debug

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

IDEA导入已有的模块

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

1 字符串相关的类

1.1 String类

String源码

public final class String implements java.io.Serializable, Comparable<String>, CharSequence{
	private final char value[];
	private int hash;
	...
}

String的实例化

String s1="hello";//字面量实例化
String s2=new String();//本质是this.value=new char[0];
String s3=new String(String original);//本质是this.value=original.value;
String s4=new String(char[] a);//this.value=Arrays.copyOf(value, value.length);
String s5=new String(char[] a, int startIndex, int count);

总体来说:
String的实例化方式:
 * 方式1:通过字面量定义的方式:存放到方法区中的字符串常量池中
 * 方式2:通过new + 构造器的方式:存放到堆中

String:字符串,使用一对""引起来表示

  • 1.String声明为final的,不可被继承
  • 2.String实现Serializable接口:表示字符串是支持序列化的
    实现Comparable接口:表示字符串可以比较大小
  • 3.String内部定义了final char[] value用于存储字符串数据
  • 4.String代表不可变的字符序列。简称:不可变性
    体现:1.当对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值。//见内存解析
    2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。s1+="def";则内存地址已经变了
    3.当调用String的replace()方法修改指定的字符或字符串时,也需要重新指定内存区域赋值。String s3="abc"; String s4=s3.replace('a', 'm');
  • 5.通过字面量的方式(如String s1=“abc”;)(区别于new的方式)给一个字符串赋值,此时的字符串值声明在方法区的字符串常量池中
  • 6.字符串常量池中是不会存储相同内容的字符串的

面试题

面试题:String s=new String(“abc”);方式创建对象,在内存中创建了几个对象?
2个:1个是堆空间中new的结构,另一个是char[]对应的字符串常量池中的数据,即"abc"

小结论

1.常量与常量的拼接结果在常量池中,且常量池中不会存在相同内容的常量
2.只要其中有一个是变量,结果就在堆中
3.intern()方法可以返回字符串常量池中的地址值

内存解析1

在这里插入图片描述

内存解析2

在这里插入图片描述

内存解析3

在这里插入图片描述

内存解析4

String s1="hello";
String s2="world";
String S3="helloworld";
String s4="hello"+"world";
String s5=s1+"world";
String s6=s1+s2;
String s7=s5.intern();//此时返回的s7是常量池中已经存在的"helloworld"的地址值

解析:

在这里插入图片描述

1.2 String的一些方法

  • 1.int length():返回字符串的长度
  • 2.char charat(int index):返回某索引处的字符
  • 3.boolean isEmpty():判断是否是空字符串
  • 4.String toLowerCase():使用认语言环境,将String中的所有字符转换为小写
  • 5.String toupperCase():使用认语言环境,将String中的所有字符转换为大写
  • 6.String trim():返回字符串的副本,忽略前导空白和尾部空白如" h ello "返回的是"h ello"
  • 7.boolean equals(Object obj):比较字符串的内容是否相等
  • 8.boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
  • 9.String concat(String str):将字符串str连接到此字符串的结尾。等价于”+“
  • 10.int compareto(String anotherString):比较两个字符串的大小
    若返回是负数,则当前对象小;返回0,相等。对比是把字符串从前往后的每一个字符的ASCII码做对比
  • 11.String substring(int beginIndex):返回一个新的字符串,它是此字符串从beginIndex开始截取到最后一个的子字符串
  • 12.String substring(int beginIndex, int endindex):返回一个新字符串,它是此字符串从beginIndex开始截取到endindex(不包含)的一个子字符串
    一般java中都是左闭右开的
  • 13.boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
  • 14.boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
  • 15.boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始//意思就是字符串中的第toffset个开始的字符串是否是prefix
  • 16.boolean contains(CharSequence s):当且仅当此字符串包含字符序列(字符串)s时,返回true
  • 17.int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的开头索引,若没有找到,则返回-1
  • 18.int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
  • 19.int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
  • 20.int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
  • 注:indexOf和lastIndexOf方法如果未找到都是返回-1。调用indexOf(str)和lastIndexOf(str)返回值相同的情况:存在唯一的str或不存在str
  • 21.String replace(char oldChar, char newChar):返回一个新的字符串,它是通过newChar替换此字符串中出现的所有oldChar得到的
  • 22.String replace(CharSequence target, CharSequence replacement):使用指定的字符序列替换所有的目标字符序列
  • 23.String replaceAll(String regex, String replacement):使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串
  • 24.String replaceFirst(String regex, String replacement):使用给定的replacement替换此字符串匹配给定的正则表达式的第一个字符串
  • 25.boolean matches(String regex):告知此字符串是否匹配给定的正则表达式
  • 26.String[] split(String regex):(切片)根据正则表达式的匹配拆分此字符串
  • 27.String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。

String与char[]之间的转换

String—>char[]:调用String的一个方法tochararray():char[] arr=str.tochararray();
char[]—>String:调用String的构造器:String str = new String(arr);

String与byte[]之间的转换

String—>byte[]:调用String的一个方法getBytes():byte[] b = str.getBytes();
byte[]—>String:调用String的构造器:String str = new String(b);

  • 编码:字符集—>字节(看得懂—>看不懂的二进制数据)(String—>byte[])
  • 解码:编码的逆过程,字节—>字符串(看不懂的二进制数据—>看得懂)(byte[]—>String)
    说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码
String s1="abc123中国";
byte[] b = s1.getBytes();//使用认的字符集进行转换编码,因为我们之前给idea设置的是utf-8,所以认的是utf-8
System.out.println(Arrays.toString(b));

byte[] b2 = s1.getBytes("gbk");//使用gbk字符集来进行编码
System.out.println(Arrays.toString(b2));
//utf-8和gbk都可以把汉字编码成数字,前者用三个数字来表述一个汉字,后者用两个数字表述一个汉字;二者存放英文字符的编码都是一样的

String s2 = new String(b);//使用认的字符集进行解码,即使用utf-8来解码
System.out.println(s2);

String s3 = new String(b2, "gbk");//需要使用gbk来解码,若使用utf-8解码,则会出现乱码
System.out.println(s3);

1.3 StringBuffer和StringBuilder

String,StringBuffer,StringBuilder三者的异同?

  • String:不可变的字符序列
  • StringBuffer:可变的字符序列:线程安全的(里面的方法都是同步方法),效率低
  • StringBuilder:可变的字符序列:线程不安全的,效率高
    三者底层都是使用char[]存储的,只不过String加了final,后面两个没加
    正是因为String是不可变的字符序列,所以它的对字符串操作的一些方法都有返回值类型,如String toupperCase()
    而StringBuffer和StringBuilder是可变的字符序列,所以对字符串操作的一些方法虽然有返回值类型的,如StringBuffer append(xxx),但是一般不接受,如str.append(),因为s已经变了,很少用两一个字符串去接收

String与StringBuffer、StringBuilder之间的转换

  • String—>StringBuffer,StringBuilder:调用StringBuffer,StringBuilder的构造器
  • StringBuffer,StringBuilder—>String:调用String的构造器或者调用StringBuffer,StringBuilder的toString()方法

对比String,StringBuffer,StringBuilder的效率:
从高到低排列:StringBuilder > StringBuffer > String

String源码分析:
String s=new String();/底层是char[] value=new char[0];
String s=new String(“abc”);底层是char[] value=new char[]{'a', 'b', 'c'};
StringBuffer源码分析(StringBuilder类似):
StringBuffer s=new StringBuffer();char[] value=new char[16];底层创建了一个长度是16的char数组
s.append(‘a’);value[0]='a';
StringBuffer s=new StringBuffer(“abc”);char[] value=new char["abc".length()+16];底层创建了一个长度为3+16=19的char数组
StringBuffer常见问题和错误(StringBuilder类似)

  • 问题1:System.out.println(s);//输出是3
  • 问题2:扩容问题:如果要添加的数据底层的数组存不下了,那就需要扩容底层的数组。认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。特殊情况见源码
  • 指导意义:开发中如果需要一个字符串经常变,如经常调用append(),则尽量用StringBuffer(当可能出现线程安全问题时)和StringBuilder(当没有线程安全问题时),而少使用String。开发中建议使用StringBuffer(int capacity)和StringBuilder(int capacity)构造器,尽量避免去扩容

1.4 StringBuffer和StringBuilder的方法

  • 1.StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串的拼接s1.append(1);s1.append('1');
  • 2.StringBuffer delete(int start, int end):删除指定位置的内容s1.delete(2,4);
  • 3.StringBuffer replace(int start, int end, String str):把[start, end)位置替换为strs2.replace(2,4,"hello");
  • 4.StringBuffer insert(int offset, xxx):在指定位置插入xxxs3.insert(2,false);
  • 5.StringBuffer reverse():把当前字符序列反转s3.reverse();
  • 6.public int indexOf(String str):返回str在字符串中首次出现的位置
  • 7.public String subString(int start, int end):返回[start, end)的子字符串,此时此StringBuffer或StringBuilder的字符串没有改变,只是返回String类型的子串
  • 8.public int length()
  • 9.public char charat(int n):返回第n个的字符
  • 10.public void setCharat(int n, char ch):将第n个的字符换成ch

由于append()等方法返回的是StringBuffer或StringBuilder字符串本身,因此可以使用方法链原理,即多次调用s.append().append().append().append();
总结

  • 增: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()
  • 遍历:直接sout输出,或sout输出toString()方法,或for循环+charat(n)输出

1.5 练习题:滑动窗口

import org.junit.Test;

import java.util.Arrays;

/**
 * @author JiaMing
 * @create 08-22 18:05
 * @description 获取两个字符串中最大相同字串。比如:str1="abcwerthelloyuiodef12345",str="cvghellobnm12345"
 * 提示:将短的那个串进行长度依次递减的子串与较长串比较
 */
public class Exer5 {
    public String maxSubString(String s1, String s2){
        //由于可能存在多个长度相同的最大相同子串,因此创建builder等会方便存进去,不用数组存是因为不知道有几个最大相同子串,所以不知道数组的长度该创建多大
        StringBuilder builder = new StringBuilder();
        //先选出哪个长哪个短
        String maxStr = s1.length() >= s2.length() ? s1 : s2;
        String minStr = s1.length() < s2.length() ? s1 : s2;

        //外层循环逐次加一
        for (int i = 0; i < maxStr.length(); i++) {
            //内层循环的意思是:第一次比较的是subStr即"cvghellobnm12345",maxStr不包含subStr
            //第二次比较的是:subStr="cvghellobnm1234","vghellobnm12345",maxStr不包含subStr
            //第三次比较的是:subStr="cvghellobnm123","vghellobnm1234","ghellobnm12345",maxStr不包含subStr
            //...这样依次循环
            for (int x=0,y=minStr.length()-i; y<=minStr.length(); x++,y++) {
                String subStr=minStr.substring(x,y);
                if(maxStr.contains(subStr)){
                    //如果maxStr包含subStr,则存到builder中,并且把此次循环继续执行,看看是否有多个长度相同的最大相同子串并存到builder中
                    builder.append(subStr+",");
                }
            }
            //当这一次的内层循环结束并且builder中已经有最大子串时,则结束外层循环,不需要再找了
            if(builder.length()!=0){
                break;
            }
        }

        //先把builder转换成String类型,再去掉最后的","   然后并切片成多份,命名到数组中
        String[] split = builder.toString().replaceAll(",$", "").split("\\,");
        return Arrays.toString(split);//将数组转换成String类型并返回
    }

    @Test
    public void test() {
        String str1="abcwerthelloyuiodef12345";
        String str2="cvghellobnm12345";
        String maxSubString = maxSubString(str1, str2);
        System.out.println(maxSubString);
    }
}

2 JDK8 之前日期和时间的API测试

2.1 java.lang.System

System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差

2.2 java.util.Date类

①两个构造器的使用
->空参构造器:Date():创建一个对应当前时间的Date对象。Date d1 = new Date();
->参数为long型整数的构造器:Date(long date):创建指定毫秒数的Date对象,参数中的date是与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。Date d2 = new Date(1661156872226L); System.out.println(d2.toString());//输出是Mon Aug 22 16:27:52 CST 2022
②两个方法的使用
->toString():显式当前的年、月、日、星期几、时、分、秒。
->getTime():获取当前Date对象对应的毫秒数(时间戳),和java.lang.System.currentTimeMillis()功能一致。System.out.println(d1.getTime());

2.3 java.sql.Date类

java.sql.Date类是对应数据库中的日期类型的变量,只有在和数据库交互中才会使用这个(注:java.sql.Date是java.util.Date的子类)
->创建java.sql.Date对象。java.sql.Date d3 = new java.sql.Date(135646872313L);
java.sql.Date也可以调用toString()方法
->如何将java.util.Date对象转换为java.sql.Date对象。

java.util.Date d1 = new java.util.Date();
java.sql.Date d4 = new java.sql.Date(d1.getTime());

2.4 java.text.SimpleDateFormat类

SimpleDateFormat的使用:SimpleDateFormat是对日期Date类的格式化和解析的类
①当使用认构造器进行SimpleDateFormat的实例化,按照认的方式格式化和解析:SimpleDateFormat sdf = new SimpleDateFormat();
 两个操作:
 ->格式化:日期—>字符串

Date d1 = new Date();
String s2 = sdf.format(d1);
System.out.println(s2);//输出的是中文:2022/8/22 下午7:42

  ->解析:格式化的逆过程,字符串—>日期

String s3="2022/9/27 上午11:20";//字符串必须是这种格式,如果不是这种格式,会抛"ParseException"异常
System.out.println(d2);//此时输出的就又是Tue Sep 27 11:20:00 CST 2022

②当调用带参构造器进行SimpleDateFormat的实例化,按照指定的方式格式化和解析:SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
其中,yyyy代表4位数是年份,MM代表2位数的月份,dd代表2位数的日期,hh代表2位数的小时,mm代表2位数的分钟,ss代表2位数的秒
当然构造器的参数还有其他格式,如"yyyyy.MMMMM.dd GGG hh:mm:aaa"输出的格式是"02001.July.04 AD 12:08 PM"等等,具体可见java API
 两个操作:
 ->格式化:日期—>字符串

String s4 = sdf2.format(d1);//输出2022-08-22 07:55:07,
//这个格式和构造器中的参数类型是相同的

 ->解析:格式化的逆过程,字符串—>日期

Date d3 = sdf2.parse("2021-05-05 2:12:12");//要求字符串必须符合
//SimpleDateFormat的构造器的参数格式,否则会抛异常,
//输出为Wed May 05 02:12:12 CST 2021

2.5 java.util.Calendar类(日历类)

java.util.Calendar类是一个抽象类,主要用于完成日期字段之间相互操作的功能
①实例化
 方式一:创建其子类(GregorianCalendar)的对象
 方式二:调用其静态方法getInstance()

Calendar c1 = Calendar.getInstance();//因为Calendar是抽象类,
//所以getInstance得到的不是Calendar类,而是其子类GregorianCalendar,
//这是一个匿名子类的非匿名对象

②常用方法

  • int get(int field):获取想得到的时间信息;field可取YEAR,MONTH,DAY_OF_WEEK,DAY_OF_YEAR,HOUR_OF_DAY,MINUTE,SECOND,即获取年份、月份、这一周的第几天、这一年的第几天,这一天的第几个小时,分钟,秒。int days = c1.get(Calendar.DAY_OF_MONTH);//本月的第几天:此时为8月22日,所以是第22天
  • void set(int field, int value):修改日历中field为value,c1.set(Calendar.DAY_OF_MONTH,23);//修改本月的第几天为第23天
  • void add(int field, int amount):把日历中filed加上amount。c1.add(Calendar.DAY_OF_MONTH,3);//把本月的第几天加上3即23+3=26 c1.add(Calendar.DAY_OF_MONTH,-1);//把本月的第几天减去1天即25
  • final Date getTime():日历类转换成Date,Date d1 = c1.getTime();
  • final void setTime(Date date):Date转换成日历类,Date d2 = new Date(); c1.setTime(d2);//没有返回值,直接把d2的时间赋给c1

注意:Calendar有偏移量
获取月份时:一月是0,二月是1…十二月是11。
获取星期时,周日是1,周一是2…周六是7

2.6 练习题:”三天打鱼两天晒网“

/**
 * @author JiaMing
 * @create 08-22 21:50
 * @description 练习二:从1990-01-01开始”三天打鱼两天晒网“,在2022年5月15日是打鱼还是晒网
 * 分析:可知五天一循环,则可以求这一天是五天中的第几天(总天数%5==1,2,3:打鱼,总天数%5==4,0:晒网),即求出2022-05-15与1990-01-01中间隔了多少天
 */
public class DaYu480 {
    @Test
    public void test() throws ParseException {
        String s1="1990-01-01";
        String s2="2022-05-15";

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Date d1 = sdf.parse(s1);
        Date d2 = sdf.parse(s2);

        long time=d2.getTime()-d1.getTime();//两个时间段中间隔了多少毫秒

        long days=0;//两个时间段中间隔了多少天
        //一天有24*60*60*1000毫秒
        if(time%(24*60*60*1000)==0){
            //当全部除尽时,那么中间隔了天就是算出来的商
            days=time/(24*60*60*1000);
        }else {
            //当除不尽时就向上取整
            days=time/(24*60*60*1000)+1;
        }

        long doWhat=days%5;//五天循环中的第几天

        if(doWhat==1 || doWhat==2 || doWhat==3){
            System.out.println("打鱼");
        }else System.out.println("晒网");
    }
}

上述几个时间类之间的关系

在这里插入图片描述

3 JDK8 中新日期时间API

引出

由于JDK8之前的关于时间的包、类等具有可变性(如Calendar可以设置改变)、偏移性(如Date中的年份是从1900开始算的,月份是从0开始的,这和生活中不符)、格式化麻烦、线程不安全、不能处理闰秒等,因此JDK8之后有了更合适的关于时间操作的API:java.time,java.time.chrono,java.time.format,java.time.temporal,java.time.zone等

  • java.time:包含值对象的基础包
  • java.format:格式化和解析时间和日期
  • java.time.temporal:包含底层框架和扩展特性
  • java.time.zone:包含时区支持的类

3.1 java.time.LocalDateTime类

java.time使用的最频繁,包含本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(zoneddatetime)、持续时间(Duration)、时间线上的瞬时点(Instant)。其中LocalDateTime使用的频率更高,以下以LocalDateTime为例使用其方法,LocalDate、LocalTime类似

LocalDateTime ldt = LocalDateTime.Now(); 
System.out.println(ldt);//2022-08-23T10:32:54.146038400
  • of():(静态方法)设置指定的年、月、日、时、分、秒;并且没有偏移量。也属于实例化
LocalDateTime ldt2 = LocalDateTime.of(2022, 8, 23, 10, 6, 23);
//也可以只设置时分秒,具体选择of()方法中的参数
System.out.println(ldt.getDayOfMonth());//获取本月的第几天:23
System.out.println(ldt.getMinute());//获取现在是这个小时的几分:11
System.out.println(ldt.getMonth());//获取月份:AUGUST
System.out.println(ldt.getMonthValue());//获取月份的的数字:8
System.out.println(ldt.getDayOfWeek());//获取星期几:TUESDAY
  • withXxx():设置相关属性;具有不可变性
LocalDateTime ldt3 = ldt.withDayOfMonth(30);
//此时ldt是今天的日期23,ldt3是返回修改过的日期30,因为ldt没有变,
//所以是不可变性
  • plusXxx(),minusXxx():加减相关属性,具有不可变性
LocalDateTime ldt5 = ldt.plusMonths(3);//ldt5是ldt月份往后推3个月的日期
LocalDateTime ldt6 = ldt.minusDays(6);//ldt6是ldt往前推6天的日期

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...