目录
5.3 StringBuilder和StringBuffer的区别
1. 什么是API
API(Application Programming Interface,应用程序接口)是一些预先定义的函数。目的是提供应用程序与开发人员基于某软件可以访问的一些功能集,但又无需访问源码或理解内部工作机制的细节.
API是一种通用功能集,有时公司会将API作为其公共开放系统,也就是公司制定自己的系统接口标准,当需要进行系统整合,自定义和程序应用等操作时,公司所有成员都可以通过该接口标准调用源代码.
Java.util包是java中的工具包,包含各种实用工具类/集合类/日期时间工具等各种常用工具包 import java.util.Scanner; import java.lang.Object; |
2. Object
2.1概念
Object类是所有Java类的祖先,也就是说我们所说的”顶级父类”
它存在于java.lang.Object,这个包不需要我们手动导包
需要注意的是:每个类都使用Object作为超类.所有对象(包括数组)都实现这个类的方法.
在不明确给出超类的情况下,Java会自动把Object类作为要定义类的超类.
2.2 常用方法介绍
toString()
本方法用于返回对应对象的字符串表示
hashCode()
本方法用于返回对应对象的哈希码值
小贴士:哈希码值的得出是通过一种算法,意在让不同的对象具有不同的哈希码值,用于区分不同的对象.
但是有时候也存在不同对象哈希码值相同的特殊情况,我们称之为”哈希碰撞”现象
equals()
本方法用于指示其他某个对象是否与当前对象”相等”
2.3 练习: Object类练习
package cn.tedu.api;
import java.util.Objects;
/*本类用于顶级父类Object的入门案例*/
//1.查API手册
//2.连点两下Shift打开IDEA的搜索,注意勾选"include non-Project items",再搜Object
//3.按住Ctrl点hashCode()
//4.在拓展库External Libraries找到jdk1.8->rt.jar->java.lang.Object
public class TestObject {
public static void main(String[] args) {
//4.创建学生类的对象做测试
Student s = new Student();
Student s1 = new Student("海绵宝宝",3);
Student s2 = new Student("海绵宝宝",3);
//5.测试hashCode()
/*本方法的作用是返回对应对象的int类型的哈希码值
* 本方法力求不同的对象返回的哈希码不同
* 这样我们就可以根据哈希值区分不同的对象*/
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
//6.测试toString()
//打印s对象的是println(),这个方法会层层调用,一直到Object中的toString()
/*Object中toString()的默认实现:对象的名字@十六进制的哈希码值
* 子类重写了toString()以后:打印是对象的类型+属性+属性值*/
//return getClass().getName() + "@" + Integer.toHexString(hashCode());
System.out.println(s);
System.out.println(s1);
// 8.测试equals()
/*Object中equals()的默认实现使用的是==比较
* ==比较的是左右两边的值,如果是基本类型,比较的就是字面值,比如1和1,3.4和3.4
* 如果是引用类型,比较的是引用类型变量保存的地址值
* 子类重写了equals()与hashCode()以后,比较的就是对象的类型+属性+属性值*/
System.out.println(s1.equals(s2));//false
System.out.println(s.equals(s1));
}
}
//1.创建一个学生类
class Student{
//2.定义属性
String name;//姓名
int age;//年龄
//3.1添加本类的无参构造
public Student() {
System.out.println("无参构造");
}
//3.2添加本类的全参构造
public Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("全参构造");
}
//7.在Student类中添加重写的toString()
//右键->Generate->toString
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//9.添加重写的equals与hashCode()
/*equals()与hashCode()逻辑要保持一致,要重写都重写,要不重写,都不重写
* Object默认实现:hashCode()的哈希码值根据地址值生成
* equals()底层使用==比较两个对象的地址值
* Student类重写后:hashCode()的哈希码值根据重写后传入的对象的属性生成
* equals()比较两个对象的类型+所有属性与属性值
* */
@Override
public boolean equals(Object o) {
//前提:this代表的是调用本方法对象s1 o代表的是传入的对象s2
//1.比较的是两个对象的地址值,如果==为true,证明直接就是同一个对象
//后续就不用比较了,直接返回true
if (this == o) return true;
//2.1如果传入的对象是null,说明实际上并没有对象,还是引用类型的默认值
//2.2如果两个对象获取类型不一致,比如一个是Cat类型,一个是Car类型
//以上两种情况只要满足任意一种,不符合条件,直接返回false
if (o == null || getClass() != o.getClass()) return false;
//3.传入对象的类型是Object,父类无法使用子类的特有属性,所以需要强转
/*多态:向上造型:把子类型看作是父类型,花木兰替父从军 Animal a = new Cat();
向下造型:之前转成父类型的子类对象,又想使用子类自己的特有功能了,可以向下转型
写法:Cat c = (Cat) a; 比如花木兰打仗完了想用自己的特有功能:化妆*/
//向下造型:把父类型Object转回子类型Student
Student student = (Student) o;
//4.比较的是两个对象的属性与属性值
//如果是基本类型,直接比较值,所以用==比较
//如果是引用类型,比如String,还需要使用bjects.equals()做比较
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
//重写后根据属性生成
return Objects.hash(name, age);
}
}
3. String
3.1 特点
String是一个封装char[]数组的对象,字符串不可变
通过下图中的底层实现可以看出:被final修饰,是常量
String str = “abc”; 等效于:char data[] = {‘a’, ‘b’, ‘c’};
3.2 创建String对象的方式
方式一:
String(char[] value) 分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。
方式二: String str = “abc”;
- 如果是第一次使用字符串,java会在字符串堆中常量池创建一个对象。
- 再次使用相同的内容时,会直接访问堆中常量池中存在的对象。
3.3 常见方法
String API总结
int hashCode() 返回此字符串的哈希码。
boolean equals(Object anObject) 将此字符串与指定的对象比较,比较的是重写后的串的具体内容
String toString() 返回此对象本身(它已经是一个字符串!)
|
|
|
3.4 练习:String常用方法练习
public class TestString {
public static void main(String[] args) {
//1.创建String的方式一
/*1.字符串类型底层维护的是char[],存在堆中*/
char[] value = {'a','b','c'};
String s1 = new String(value);//触发String(char[])的含参构造来创建对象
String s11 = new String(value);//触发String(char[])的含参构造来创建对象
//2.创建String的方式二
String s2 = "abc";
String s22 = "abc";
String s3 = "ccc";
//3.测试
System.out.println(s1 == s2);//false,一个在堆里,一个在堆中常量池
System.out.println(s1 == s11);//false,两个不同的对象,地址值不同
System.out.println(s2 == s22);//true,都在堆中常量池,并且指向同一个,所以地址值相同
System.out.println(s2 == s3);//false,都在堆中常量池,但是数据不同,指向两个地址
/*Object类中equals()的默认实现是通过==来比较的。
但是String类已经重写过了继承自Object中的equals()
重写后,不再按照==比较,而是比较两个字符串的具体内容
也就是说,不论创建方式,只要是串的内容一致,equals()就返回true
* */
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals(s11));//true
System.out.println(s2.equals(s3));//false
}
}
package cn.tedu.api;
import java.util.Arrays;
/*本类用来测试String类的常用方法*/
public class TestString2 {
public static void main(String[] args) {
//1.创建字符串
String s1 = "abc";
char[] values = {'a','b','c'};
String s2 = new String(values);
//2.测试常用方法
/*String重写了hashCode(),是根据字符串的内容生成哈希码值,而不是根据地址值生成
* 所以虽然s1与s2一个在堆的常量池中,一个在堆中,它两的哈希码值一样*/
System.out.println(s1.hashCode());//96354
System.out.println(s2.hashCode());//96354
System.out.println(s1.equals(s2));//true,重写了,比较的是具体内容
System.out.println(s1.toString());//不需要写,底层会自动调用s1对象的toString()
System.out.println(s1);//abc,String重写了toString(),直接打印的是串的具体内容
System.out.println(s1.length());//3,查看当前字符串的长度
System.out.println(s1.toUpperCase());//ABC,将本字符串转为全大写
System.out.println(s1.toLowerCase());//abc,将本字符串转为全小写
System.out.println(s1.startsWith("a"));//true,判断本字符串是否以指定元素a开头
System.out.println(s2.endsWith("a"));//false,判断本字符串是否以指定元素a结尾
System.out.println(s1.charAt(0));//a,根据下标获取本字符串中对应的元素
String s3 = "abcbdbba";
System.out.println(s3.indexOf("b"));//1,返回本字符串中指定元素第一次出现的下标
System.out.println(s3.lastIndexOf("b"));//6,返回本字符串中指定元素最后一次出现的下标
System.out.println(s2.concat("cxy"));//abccxy,将指定字符串拼接到本字符串的结尾
System.out.println(s2);//abc,说明上面的拼接是临时的,不会改变原串的内容
String s4 = s2.concat("aaa");//如果想要多次使用拼接后的结果,需要定义一个字符串来保存结果
System.out.println(s4);//abcaaa
String s5 = "afbfcfdfe";
//返回值类型是String[],所以需要使用Arrays.toString()打印
//以指定字符作为分割符,分割当前的字符串
//我们只是直接打印了split()的结果,没有使用变量保存
System.out.println(Arrays.toString(s5.split("f")));//[a, b, c, d, e]
//由于split()的返回值类型是String[],所以我们执行这个方法,可以拿到这个方法的返回值
//所以a数组就是这个方法执行以后得到的结果,只不过我们保存下来了
String[] a = s5.split("f");
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
String s6 = " hh hhh ";//去除本字符串首尾两端的空格
System.out.println(s6.trim());//hh hhh
String s7 = "abcdefgh";
System.out.println(s7.substring(3));//defgh,从指定下标处截取子字符串[3,结束]
System.out.println(s7.substring(3,6));//def,从指定下标处截取子字符串[3,6)含头不含尾
System.out.println(String.valueOf(10));//10,将int类型的参数10转为String类型
System.out.println("20"+10);//2010,String与int拼接
System.out.println(20+10);//30,int与int相加
System.out.println(String.valueOf(80)+10);//8010,将int类型的参数80转为String类型,所以拼接
byte[] bs = s7.getBytes();//将指定字符串转为byte[]
}
}
4. StringBuilder/StringBuffer
4.1 特点
1.封装了char[]数组
2.是可变的字符序列
3.提供了一组可以对字符内容修改的方法
4.常用append()来代替字符串做字符串连接”+”
5.内部字符数组默认初始容量是16:super(str.length() + 16);
6.如果大于16会尝试将扩容,新数组大小原来的变成2倍+2,容量如果还不够,直接扩充到需要的容量大小。int newCapacity = value.length * 2 + 2;
7.StringBuffer 1.0出道线程安全,StringBuilder1.5出道线程不安全
4.2 常见方法
append()
4.3 练习3:测试字符串连接
|
5 拓展
5.1 ==和equals的区别
1.当使用= =比较时,如果相比较的两个变量是引用类型,那么比较的是两者的物理地值(内存地址),如果相比较的两个变量都是数值类型,那么比较的是具体数值是否相等。
2.当使用equals()方法进行比较时,比较的结果实际上取决于equals()方法的具体实现
众所周知,任何类都继承自Object类,因此所有的类均具有Object类的特性,比如String、integer等,他们在自己的类中重写了equals()方法,此时他们进行的是数值的比较,而在Object类的默认实现中,equals()方法的底层是通过==来实现的。
5.2 练习: ==与equals测试
|
5.3 StringBuilder和StringBuffer的区别
1.在线程安全上 :
–StringBuffer是旧版本就提供的,线程安全的。@since JDK1.0
–StringBuilder是jdk1.5后产生,线程不安全的。@since 1.5
2. 在执行效率上,StringBuilder > StringBuffer > String
3.源码体现:本质上都是在调用父类抽象类AbstractStringBuilder来干活,只不过Buffer把代码加了同步关键字,使得程序可以保证线程安全问题。