- 比较字符串内容值是否相同。
package com.holmes.java04;
import org.junit.Test;
public class StringTest {
@Test
public void test1(){
String s1 = “abc”;
String s2 = “abc”;
System.out.println(s1 == s2);//比较s1和s2的地址是否相同。
System.out.println(s1.equals(s2));//比较字符串内容值是否相同。
}
}
String字符串,什么情况下,重新指定内存区域进行赋值:
无论,重复赋值,还是拼接字符串,还是修改指定替换字符串等,都是要重新指定内存区域进行赋值!!!
========================================================================================
String对象创建的四种方式:
整体上,也就两种方式:一种字面量,一种new创建对象。
-
通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
-
通过 new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对象的值。
package com.holmes.java04;
import org.junit.Test;
public class StringTest {
@Test
public void test1(){
//通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
String s1 = “javaEE”;
String s2 = “javaEE”;
//通过 new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对象的值。
String s3 = new String(“javaEE”);
String s4 = new String(“javaEE”);
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s3 == s4);//false
}
}
==================================================================================
字面形式和new + 对象的内存存储原理:
面试题:String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?
两个,一个是堆空间中new的对象,另一个是char[]对应常量池中的数据:“abc”。
=================================================================================
下面的拼接效果必须牢记!!!!
package com.holmes.java04;
import org.junit.Test;
public class StringTest {
@Test
public void test1(){
String s1 = “javaEE”;
String s2 = “hadoop”;
String s3 = “javaEEhadoop”;
String s4 = “javaEE”+“hadoop”;
String s5 = s1 + “hadoop”;
String s6 = “javaEE” + s2;
String s7 = s1 + s2;
String s8 = (s1 + s2).intern();
//没有变量相加,仅仅只是字符串,这样声明的s4的内存地址就仅仅在常量池中。
System.out.println(s3 == s4); //true
//只要有变量相加的,那么该创建方式就是new对象形式,也就是要存储到堆内存地址。
System.out.println(s3 == s5); //false
System.out.println(s3 == s6); //false
System.out.println(s5 == s6); //false
System.out.println(s3 == s7); //false
System.out.println(s5 == s7); //false
System.out.println(s6 == s7); //false
//通过调用intern()方法,返回值就在常量池中!
System.out.println(s3 == s8); //true
}
}
=====================================================================================
package com.holmes.java04;
public class StringTest2 {
//也算涉及到了String类型的不可变性。
//这里与下面change函数中的str的内存地址不同!
String str = new String(“good”);
char[] ch = {‘t’,‘e’,‘s’,‘t’};
public void change(String str,char ch[]){
//这里的str与上面的str不同!!地址不同,这里是形参是参数!!!
str = “test ok”;
ch[0] = ‘b’;
}
public static void main(String[] args) {
StringTest2 ex = new StringTest2();
ex.change(ex.str,ex.ch);
//有人疑惑这里为什么不是test ok, 原因很简单,因为这里的ex.str是作为形参传入。
System.out.println(ex.str); //good
//至于数组没有不可变形,对应地址相同,只不过内容中的第一个值变化了而已。
System.out.println(ex.ch); //best
}
}
==============================================================================
JDK1.6版本,字符串常量池都在方法区中:
JDK除了1.7版本,字符串常量池在堆中:
JDK1.8以及以后的版本,字符串常量池都在方法区中:
============================================================================
问题一:什么情况下,indexOf(str) 和 lastIndexOf(str)返回值相同?
**答:情况一:存在唯一的一个str。情况二:不存在str时。
此外,indexOf 和 lastIndexOf方法如果未找到都是返回-1。**
上面的replaceAll()函数方法,matches()函数方法,涉及到正则表达式内容,如下:
======================================================================================
首先,纠正一个经常犯下的错误:
String str = “123”;
//错误的,强转的前提必须是子父类的前提下!!!
int num = (int)str;
String 转 int:(调用包装类的静态方法,Integer.parseXxx())
String str = “123”;
//调用包装类的静态方法,才是正确的
int num = Integer.parseInt(str)
int 转 String:(调用包装类的静态方法,Integer.toString() 和 String.valueOf())
String s2;
String s3;
int num2 = 123;
//方式一:Integer.toString()方法
s2 = Integer.toString(num2);
//方式二:String.valueOf()方法
s3 = String.valueOf(num2);
System.out.println(s2.getClass()+ “,” +s3.getClass());
//class java.lang.String , class java.lang.String
//方式三:就是通过加空字符串 “” 。
String s4 = 123 + “”;
牢记toCharArray()函数方法:
package com.holmes.java04;
import org.junit.Test;
public class StringTest {
@Test
public void test1(){
String str1 = “abc123”;
//调用String的toCharArray()拆分字符串 转为 字符数组。
char[] charArray = str1.toCharArray();
//遍历一下charArray
for (int i=0;i<charArray.length;i++){
System.out.println(charArray[i]);
}
char[] arr = new char[]{‘h’,‘e’,‘l’,‘l’,‘o’};
//直接将字符数组当作参数放入字符串对象,就直接形成了字符串
String str2 = new String(arr);
System.out.println(str2);
}
}
8.4 String字符串 和 byte[]字节数组 之间的转换
这里就会出现一个编码和解码的一个效果:
**String 转为 byte[]:
(调用String的getBytes()方法)**
package com.holmes.java04;
import org.junit.Test;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.util.Arrays;
public class StringTest {
@Test
public void test1() throws UnsupportedEncodingException {
//调用String的getBytes()方法
String str1 = “abc123中国”;
byte[] bytes = str1.getBytes(); //使用默认的字符集(utf-8),进行转换
//Arrays.toString()方法显示字符串。
System.out.println(Arrays.toString(bytes));
//[97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67],这里结果就是aciII码
//此外,在utf-8当中一个汉字是占3个字节。
//使用gbk编码,就要添加参数
byte[] gbks = str1.getBytes(“gbk”);
System.out.println(Arrays.toString(gbks));
//[97, 98, 99, 49, 50, 51, -42, -48, -71, -6] 在gbk中一个汉字包含两个字节。
}
}
**byte[]字节数组 转 String字符串:
(new对象参数传入,来转换)**
package com.holmes.java04;
import org.junit.Test;
import java.io.UnsupportedEncodingException;
public class StringTest {
@Test
public void test1() throws UnsupportedEncodingException {
//调用String的getBytes()方法
String str1 = “abc123中国”;
byte[] bytes = str1.getBytes(); //使用默认的字符集(utf-8),进行转换
byte[] gbks = str1.getBytes(“gbk”);
//同样这里也是用默认的字符集(utf-8)来进行解码
String str2 = new String(bytes);
System.out.println(str2);
//因为这里是通过gbk编码的,但使用utf-8来解码就会乱码
String str3 = new String(gbks);
System.out.println(str3);
//abc123中国
//abc123�й�
}
}
===============================================================================
因为一个final,就导致结果不同,牢记常量与常量拼接的结果是存储在常量池中,且常量池不会存在相同内容的常量。final声明后变量就变成了常量!
package com.holmes.java04;
import org.junit.Test;
public class StringTest {
@Test
public void test1(){
String s1 = “javaEEhadoop”;
String s2 = “javaEE”;
String s3 = s2 + “hadoop”;
System.out.println(s1 == s3); //false
//final声明后,s4就变成了常量,常量和常量的拼接结果就在常量池中,因此返回true。
final String s4 = “javaEE”;
String s5 = s4 + “hadoop”;
System.out.println(s1 == s5); //true
}
}
10. StringBuffer 和 StringBuilder 介绍
=================================================================================================
本质上字符串存储规则,其实就是个char[]数组,String不可变,StringBuffer和StringBuilder可变。
String , StringBuffer , StringBuilder三者的异同?
String:不可变的字符序列。
StringBuffer:可变的字符序列:线程安全的,效率偏低。
StringBuilder:可变的字符序列:jdk5.0新增,线程不安全的,效率高。
上面三者底层使用char[]存储。(StringBuffer和StringBuilder因为继承AbstractStringBuilder,因此也是char[] value存储。)
11. String ,StringBuffer,StringBuilder 源码分析
=========================================================================================================
String源码分析:
String str = new String();
//执行实际源码为:char[] value = new char[0];
String str1 = new String(“abc”);
//执行实际源码为:char[] value = new char[]{‘a’,‘b’,‘c’};
StringBuffer源码分析:(StringBuilder源码差不多,就是安不安全的问题)
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]; 字符串的长度外加16个长度数组。
//问题1:System.out.println(sb2.length()); 输出为3呢,还是3+16呢?
//答案:其实和加不加16没关系,因为length返回的count,是数组中有多少数据。
//问题2:既然开始定义长度为16,一旦满了就会有一个扩容问题?
//如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
//append方法中,调用了ensureCapacityInternal(确保容量完整的)方法,进而满足扩容。
//默认情况下扩容为原来容量的2倍(向左进位1,就是乘于2)+2,同时将原有数组中的元素复制到新的数组中。
开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)。可以直接定义容量大小,区别就是安全不安全。
12. StringBuffer 和 StringBuilder类常用的方法
====================================================================================================
StringBuffer和StringBuilder的常用方法差不多,都是一样:
当append和insert时,如果原来value数组长度不够,可扩容。
package com.holmes.java04;
import org.junit.Test;
public class StringBufferBuilderTest {
@Test
public void test1(){
StringBuffer sb1 = new StringBuffer(“abc”);
sb1.append(1);
sb1.append(‘1’);
System.out.println(sb1);
//注意:像delete这样的方法,删除的索引是左闭右开!!
sb1.delete(2,4);
System.out.println(sb1);
sb1.replace(2,4,“hello”);
System.out.println(sb1);
sb1.insert(2,“c”);
System.out.println(sb1);
sb1.reverse();
System.out.println(sb1);
System.out.println( sb1.indexOf(“c”));
System.out.println(sb1.substring(2,4));
System.out.println(sb1.charAt(5));
sb1.setCharAt(0,‘m’);
System.out.println(sb1);
}
}
方法链是一个很重要的形式,方法链的原理:
13. 对比String ,StringBuffer,StringBuilder的效率
=========================================================================================================
package com.holmes.java04;
import org.junit.Test;
public class StringBufferBuilderTest {
@Test
public void test1(){
long startTime = 0;
long endTime = 0;
String text = “”;
StringBuffer buffer = new StringBuffer(“”);
StringBuilder builder = new StringBuilder(“”);
startTime = System.currentTimeMillis();
for (int i = 0;i < 20000; i++){
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println(“StringBuffer的执行时间:” + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0;i < 20000; i++){
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println(“StringBuilder的执行时间:” + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0;i < 20000; i++){
text += i;
}
endTime = System.currentTimeMillis();
System.out.println(“String的执行时间:” + (endTime - startTime));
//String的效率远远小于前两者
//效率从高到低排列: StringBuilder > StringBuffer > String
//考虑是否有线程安全问题是否要同步,就要使用StringBuffer. StringBuffer线程安全,StringBuilder线程不安全。
}
}
==================================================================================
计算世界时间的主要标准有:
方法一:
java.lang.System类的日期时间:(计算时间差)
-
System.currentTimeMillis()返回当前时间于1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
-
此方法经常用来计算时间差。
方法二:
java.util.Date类表示特定的瞬间,精确到毫秒:
package com.holmes.java04;
/*
方式一:两个构造器使用
构造器一:Date() :创建一个对应当前时间的Date对象。
构造器二:创建指定毫秒数(时间戳)的Date对象。
方式二:两个方法的使用
调用toString()方法:显示当前的年,月,日,时,分,秒。
getTime()方法:获取当前Date对象对应的毫秒数(时间戳)。
*/
import org.junit.Test;
import java.util.Date;
public class DateTimeTest {
@Test
public void test2(){
//构造器一:Date() :创建一个对应当前时间的Date对象
Date date1 = new Date();
//调用toString()方法:显示当前的年,月,日,时,分,秒
System.out.println(date1.toString());//Sat Nov 06 14:55:02 CST 2021
//getTime()方法:获取当前Date对象对应的时间戳
System.out.println(date1.getTime());//1636181996537
//构造器二:创建指定毫秒数(时间戳)的Date对象
Date date2 = new Date(1636181996537L);
System.out.println(date2.toString());
}
}
在sql也有一个,java.sql.Date类,对应着数据库中的日期类型的变量。
package com.holmes.java04;
/*
java.sql.Date类的Date对象:
同样调用toString()方法和getTime()方法
*/
import org.junit.Test;
import java.sql.Date;
public class DateTimeTest {
@Test
public void test2(){
//创建java.sql.Date的对象
Date date1 = new Date(23453456342L);
System.out.println(date1.toString()); //1970-09-29
System.out.println(date1.getTime()); //23453456342
}
}
怎么将sql.Date 转为 util.Date对象?
因为多态性,直接赋值就可。
package com.holmes.java04;
import org.junit.Test;
public class DateTimeTest {
@Test
public void test2(){
//创建java.sql.Date的对象
java.sql.Date date1 = new java.sql.Date(23453456342L);
//创建java.util.Date的对象
java.util.Date date2 = new java.util.Date();
//sql.Date 转 util.Date 多态性直接赋值就可
date2 = date1;
System.out.println(date2);
}
}
怎么将util.Date 转为 sql.Date对象?
因为参数都有毫秒(时间戳),所以我们可以通过getTime()的方式来解决这种问题!!
package com.holmes.java04;
import org.junit.Test;
public class DateTimeTest {
@Test
public void test2(){
//创建java.sql.Date的对象
java.sql.Date date1 = new java.sql.Date(23453456342L);
//创建java.util.Date的对象
//情况一:左边是util,右边是sql,多态性,这样就可以强转。
java.util.Date date2 = new java.sql.Date(32453476342L);
java.sql.Date date3 = (java.sql.Date)date2;
System.out.println(date3); //1971-01-11
//情况二:都是util直接强转会报错!!cannot be cast
java.util.Date date4 = new java.util.Date(32453476342L);
//java.sql.Date date5 = (java.sql.Date)date4; 错误的!
//但是有一个方法getTime(),来获得毫秒数就可以直接当作参数传递过去,就完美解决了
java.sql.Date date6 = new java.sql.Date(date4.getTime());
System.out.println(date6); //2021-11-06
}
}
================================================================================
16. JDK8之前日期时间API SimpleDateFormat类
=================================================================================================
SimpleDateFormat是对日期Date类的格式化和解析。
-
使用format()方法,格式化:日期 转为 字符串。
-
使用parse()方法,解析:格式化的逆过程,字符串 转为 日期
package com.holmes.java05;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTimeTest {
@Test
public void testSimpleDateFormat() throws ParseException {
//实例化SimpleDateFormat:使用默认的构造器
SimpleDateFormat sdf = new SimpleDateFormat();
//格式化:日期 转为 字符串
Date date = new Date();
String formatStr = sdf.format(date);
System.out.println(formatStr);
//解析:格式化的逆过程,字符串 转为 日期
//需要注意的是字符串的格式也必须和date格式一样,不然就抛出异常了
String str = “21-11-7 下午3:04”;
Date date1 = sdf.parse(str);
System.out.println(date1);
}
}
SimpleDateFormat的参数,不同格式的参数对应不同返回的结果。可以查看java参考手册这对SimpleDateFormat有参数的构造器这一节。
package com.holmes.java05;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTimeTest {
@Test
public void testSimpleDateFormat() throws ParseException {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy.MM.dd G ‘at’ HH:mm:ss z”);
System.out.println(sdf.format(date));
//常用格式如下:
//年:小写y,月:大写M,时分秒:小写hms。
SimpleDateFormat sdf1 = new SimpleDateFormat(“yyyy-MM-dd hh:mm:ss”);
//格式化format:日期 转为 字符串
System.out.println(sdf1.format(date));
//解析,同样这里parse解析的格式也必须和参数定义的格式一样!!否则抛出异常
System.out.println(sdf1.parse(“1999-11-07 04:07:55”));;
//2021.11.07 公元 at 16:09:21 CST
//2021-11-07 04:09:21
//Sun Nov 07 04:07:55 CST 1999
}
}
很多页面传字符串"2020-09-08" 转为java.sql.Date(以方便存储数据库中)。
package com.holmes.java05;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class DateTimeTest {
@Test
public void testExer() throws ParseException {
String str = “2020-09-08”;
//参数格式有一种为:“yyyy-MM-dd hh:mm:ss”
//要对应前端传过来的数据,像后面的hh:mm:ss,忽略就行。
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”);
//util下的date
java.util.Date dateUtil = sdf.parse(str);
java.sql.Date dateSql = new java.sql.Date(dateUtil.getTime());
System.out.println(dateSql);
}
}
总天数差的一些计算,可以用到方法类和getTime类方法。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
难道这样就够了吗?不,远远不够!
提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。
备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记
我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。
今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!
ws ParseException {
String str = “2020-09-08”;
//参数格式有一种为:“yyyy-MM-dd hh:mm:ss”
//要对应前端传过来的数据,像后面的hh:mm:ss,忽略就行。
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”);
//util下的date
java.util.Date dateUtil = sdf.parse(str);
java.sql.Date dateSql = new java.sql.Date(dateUtil.getTime());
System.out.println(dateSql);
}
}
总天数差的一些计算,可以用到方法类和getTime类方法。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-AsXkF6vm-1711692406432)]
[外链图片转存中…(img-mNCCYhNI-1711692406432)]
[外链图片转存中…(img-TVZi6ous-1711692406433)]
[外链图片转存中…(img-Ck2IB3sf-1711692406433)]
[外链图片转存中…(img-fXdpBu5E-1711692406433)]
[外链图片转存中…(img-I2iCfyuH-1711692406434)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-M4LiQdO4-1711692406434)]
难道这样就够了吗?不,远远不够!
提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。
备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记
我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。
今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!
[外链图片转存中…(img-hEE5JvTE-1711692406434)]
[外链图片转存中…(img-FBNgKe9H-1711692406435)]
[外链图片转存中…(img-jrnCpdeo-1711692406435)]