包装类
含义:Java为纯面向对象语言(万物皆对象),而8种基本数据类型不能创建对象,破坏了Java纯面向对象的特征,所以Java给这8中基本数据类型分别匹配了对应的类,这些类叫做包装类/封装类
注意:每个基本数据类型都有一个与之匹配的类
继承关系:
基本数据类型 引用数据类型 继承关系 byte Byte extends Number extends Object short Short extends Number extends Object int Integer extends Number extends Object long Long extends Number extends Object float Float extends Number extends Object double Double extends Number extends Object char Character extends Object boolean Boolean extends Object 注意:
- 数值类型的包装类都继承Number
- int的包装类为 Integer
- char的包装类为 Character
装箱与拆箱
装箱
含义:将基本数据类型转换成包装类
int i = 100;
Integer integer = Integer.valueOf(i);//装箱
System.out.println(integer);
拆箱
含义:包装类—>基本数据类型
Integer integer = new Integer(100);
int i = integer.intValue();//拆箱
System.out.println(i);
JDK1.5的新特性:自动装箱、自动拆箱
自动装箱
含义:基本数据类型 —> 包装类
int i = 100;
Integer integer = i;//自动装箱(底层实现:Integer.valueOf(i);)
System.out.println(integer);
自动拆箱
含义:包装类 —> 基本数据类型
Integer integer = new Integer(100); int i = integer;//自动拆箱(底层实现:integer.intValue();) System.out.println(i);
应用场景
集合是类似数组的容器,但集合只能存储引用数据类型,如果想存储基本数据类型,就可以把基本数据类型转换为对应的包装类对象
实例应用
需求:把字符串数组{“1”,“2”,“3”,“4”,“5”}转换为int数组
String[] ss = {"1","2","3","4","5"}; int[] is = new int[ss.length]; for (int i = 0; i < is.length; i++) { //1.将String转换为Integer对象 //2.Integer对象自动拆箱成int数据 int num = Integer.valueOf(ss[i]); is[i] = num; } for (int element : is) { System.out.println(element); }
深入包装类底层源码
面试题: Integer integer1 = Integer.valueOf(100); Integer integer2 = Integer.valueOf(100); System.out.println(integer1 == integer2);//true Integer integer3 = Integer.valueOf(200); Integer integer4 = Integer.valueOf(200); System.out.println(integer3 == integer4);//false 总结:Integer底层有一个缓存类,缓存类中有一个数组,存储了-128~127的Integer对象,Integer.valueOf(num)底层会判断num是否在-128~127这个区间,如果在就从缓存数组中获取数据,如果不在这个区间就重新new对象
字符串相关类
String类
注意:String是一个不可变的类,即一旦String对象被创建,这个对象中的字符序列是不可变的,直至该对象被销毁
String类的常用方法
public static void main(String[] args) {
String str = "123abc";
str = str.concat("DEF123");//在此字符串末尾追加字符串,并返回新的字符串
str = str.substring(2);//从开始下标处截取到字符串末尾,并返回新的字符串
str = str.substring(1, 7);//从开始下标处(包含)截取到结束下标处(不包含),并返回新的字符串
str = str.toUpperCase();//转大写,并返回新的字符串
str = str.toLowerCase();//转小写,并返回新的字符串
str = " 123 a bcD EF 123 ";
str = str.trim();//去除首尾空格,并返回新的字符串 "123 a bcD EF 123"
str = str.replace('2', '-');//替换字符,并返回新的字符串
str = str.replaceFirst("3", "小明");//替换第一个出现的字符串,并返回新的字符串
str = str.replaceAll("1", "xxx");//替换字符串,并返回新的字符串
str = str.replaceAll(" ", "");//替换字符串,并返回新的字符串(去掉字符串中所有的空格)
System.out.println("判断两个字符串内容是否相同:(区分大小写)" + str.equals("xxx-小明abcDEFxxx-3"));
System.out.println("判断两个字符串内容是否相同:(不区分大小写)" + str.equalsIgnoreCase("XXX-小明ABCdefxxx-3"));
System.out.println("判断此字符串是否以某个字符串开头:" + str.startsWith("xxx"));
System.out.println("判断此字符串是否以某个字符串结尾:" + str.endsWith("-3"));
System.out.println("查询此字符串第一次在目标字符串中的下标:" + str.indexOf("-"));
System.out.println("查询此字符串最后一次在目标字符串中的下标:" + str.lastIndexOf("-"));
System.out.println("获取指定下标上的字符:" + str.charAt(4));
//xxx-小明abcDEFxxx-3
System.out.println(str);
}
实例应用
练习:完成一个邮箱格式的校验
(1),“@”不能在第一位
(2),“.”不能在最后一位
(3),“@”和“.”中间应该有字符
(4), hhy@qq.compublic static void main(String[] args) { String email = "@hhyqq.com"; int index1 = email.indexOf("@"); int index2 = email.indexOf("."); if(index1 == 0 || index2 == email.length()-1 || (index2-index1)<=1){ System.out.println("邮箱格式错误"); } }
其他类型转字符串
直接使用 String.valueOf() 方法
int i = 100; System.out.println(String.valueOf(i)); boolean bool = true; System.out.println(String.valueOf(bool));
深入String创建对象问题
面试题1:下列代码创建几个String对象(考点:常量池中的值必须是唯一的)
String str1 = “abc”;
String str2 = “abc”;
答案:一个
//str1存在栈中,字符串常量对象 abc 存在常量池中,str1指向常量abc,声明str2时,会先检查常量池中是否存在abc,如果存在就直接把该对象abc的地址赋给str2面试题2:下列代码创建几个String对象(考点:常量池中的值必须是唯一的)
String str1 = new String(“abc”);
//2个。先创建字符串常量对象abc,再new对象,再把常量abc赋值给new出来的对象
String str2 = new String(“abc”);//因为常量池中已存在"abc",所以直接new对象,再赋值
答案:三个
public static void main(String[] args) { String str1 = "abc"; String str2 = "abc"; System.out.println(str1 == str2);//true.把字符串常量abc分别赋值给引用str1和str2 //两个常量字符串直接在编译时拼接 String str3 = "ab" + "c"; //等价于 String str3 = "abc"; System.out.println(str3 == str1);//true //两个常量字符串直接在编译时拼接 final String s1 = "ab"; final String s2 = "c"; String str4 = s1+s2; //等价于 String str4 = "abc"; System.out.println(str4 == str1);//true //两个变量字符串拼接底层是创建StringBuilder对象 String s3 = "ab"; String s4 = "c"; String str5 = s3+s4;//(new StringBuilder(s3)).append(s4).toString() System.out.println(str5 == str1);//false }
StringBuffer
- StringBuffer代表可变的字符序列,
StringBuffer称为字符串缓冲区. 是线程安全的- 它的工作原理是:
- 预先申请一块内存,存放字符序列 (底层是一个默认大小为16的字符数组)
- 如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列
- StringBuffer对象中的字符序列可变,这是与String最大的不同
public static void main(String[] args) { /** * 知识点:StringBuffer * 继承关系:StringBuffer extends AbstractStringBuilder */ //默认字符串缓冲区:16个字符 //StringBuffer sb = new StringBuffer(); //自定义字符串缓冲区:100个字符 //StringBuffer sb = new StringBuffer(100); //自定义字符串缓冲区:"123abc".length() + 16 : 22个字符 StringBuffer sb = new StringBuffer("123abc"); sb.append("DEF123");//在末尾追加字符串 sb.insert(6, "xxx");//在指定下标处插入字符串 sb.setCharAt(3, 'A');//替换指定下标上的字符 sb.replace(6, 9, "用良心做教育");//从开始下标处(包含)替换到结束下标处(不包含)的字符串 sb.deleteCharAt(1);//删除指定下标上的字符 sb.delete(5, 11);//从开始下标处(包含)删除到结束下标处(不包含)的字符串 sb.reverse();//反转字符串 //321FEDcbA31 System.out.println(sb); }
StringBuilder
使用上和StringBuffer一模一样,是线程不安全的
字符串频繁拼接问题
经验:频繁的拼接字符串请使用StringBuilder或StringBuffer
public static void main(String[] args) { //获取自1970.1.1 0:0:0到现在的毫秒数 //long startTime = System.currentTimeMillis(); //String str = "小明"; //for (int i = 0; i < 50000; i++) { //str += "睡觉!"; //底层实现 //str = str + "睡觉!" //str = new StringBuilder(str).append("睡觉!").toString(); //} //long endTime = System.currentTimeMillis(); //System.out.println("消耗时长:" + (endTime-startTime));//5746 //获取自1970.1.1 0:0:0到现在的毫秒数 long startTime = System.currentTimeMillis(); StringBuilder sb = new StringBuilder("林成"); for (int i = 0; i < 50000; i++) { sb.append("睡觉!"); } long endTime = System.currentTimeMillis(); System.out.println("消耗时长:" + (endTime-startTime));//5 }