1前言
亲爱的小伙伴萌,目前我们看到的是java基础部分的一个新的部分API,这是个啥,又能做啥呢?
其实我们可以概括成一句话:帮助我们站在巨人的肩膀上,实现更加高效的开发,我们来一探究竟吧~
2什么是API
API(Application Programming Interface,应用程序接口)是一些预先定义的函数。目的是提供应用程序与开发人员基于软件可以访问的功能集,有时公司会将API作为其公共开放系统,也就是公司制定自己的系统接口标准,当需要进行系统整合,自定义和程序应用等操作时,公司所有成员都可以通过该接口标准调用源代码。
java.util包是java的核心工具包,包括各种实用工具类/集合类/日期时间工具等各种常用工具包
import java.util.Scanner;
import java.util.Arrays;
java.lang包是Java的核心,包含了java基础类
包括基本Object类/Class类/String类/基本数学类等最基本的类,这个包无需导入,默认会自动导入
import java.lang.Object;
import java.lang.String;
import java.lang.StringBuilder/StringBuffer;
正则表达式
包装类等——
那么我们接下来会学习一些常用的类,帮助大家完成“基建工程”,首先第一位选手就是传说中的Object类
3Object
3.1概念
Object类是所有java类的祖先(基础),也就是我们所说的“顶级父类”
他存在于java.lang.Object,这个包不需要我们手动导包
需要注意的是:每个类都使用Object作为超类,所有对象(包括数组)都实现这个类的方法
在不明确给出超类的情况下,Java会自动把Object类作为要定义类的超类
3.2常用方法介绍
toString()
本方法用于返回对应对象的字符串表示
hashCode()
本方法用于返回对象的hash码值
小贴士:hash码值的得出是通过一种算法,意在不同的对象具有不同的hash码值,用于区分不同的对象,
但是有时候也存在不同对象hash码值相同的特殊情况,我们称之为“hash碰撞”现象
equals()
本方法用于指示其他某个对象的是否与当前对象“相等”
3.3 练习: Object类练习
创建包: cn.tedu.api
创建类: TestObject.java
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);
}
}
4 String
4.1特点
String是一个封装char[]数组的对象,字符串不可变
通过下图的底层实现可以看出:被final修饰的,是常量
String str = "abc";等效于:char[] data = {‘a’,'b','c'};
4.2 创建String对象的方式
方式一:
String(char[] value)分配一个新的String,使其表示字符数组参数中当前包含的字符序列。
方式二:String str = "abc";
4.3 常见方法
String SPI总结
int hashCode()返回此字符串的哈希码。
boolean equals(Object anObject)将此字符串与指定的对象比较,比较的是重写后的串的具体内容
String toString()返回此对象本身(他已经是一个字符串!)。
int length() 返回此对象的长度。
String toUpperCase()所有字符都转为大写。
String toLowerCase()所有字符串都转换为小写。
boolean startsWith(String prefix) 测试此字符串是否以指定元素开头。
boolean endsWith(Sting suffix)测试此字符串是否以指定的字符串结束。
char charAt(int index) 返回指定索引/下标处的char值字符
int indexOf(String str)返回指定字符串在此字符串中最后一次出现出的索引。
String concat(String str)将指定字符串连接/拼接到此字符串的末尾,注意:不会改变原串
String[] split(String regex) 根据给定元素来分割此字符串。
String trim()返回取出首尾空格的字符串
byte[] getBytes()把字符串存储到一个新的byte数组中
String substring(int beginlndex)返回一个新子串,从指定下标处开始,包含指定下标
String substring(int beginlndex,int endindex)返回一个新子串,从指定下标开始到指定下标结束,但不包含结束下标
static String valueOf(int i)把int转换成String
4.4练习:String常用方法练习
创建包: cn.tedu.api
创建类: TestString.java
package cn.tedu.api;
/*本类用于练习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
}
}
创建包: cn.tedu.api
创建类: TestString2.java
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[]
}
}
5StringBuider/StringBuffer
5.1特点
1.封装了char[]数组
2.是可变的字符序列
3.提供了一组可以对字符内容修改的方法
4.常用append()来代替字符串做字符串拼接“+”
5.内部字符数组默认初始容量:super(str.length()+16);
6.如果大于16会尝试将扩容,新数组大小原来的变成两倍+2,容量如果还不够,直接扩容到需要的容量的大小。int newCapacity=value.length*2+2;
7.StringBuffer 1.0出道线程安全,StringBuiler1.5出道线程不安全
5.2常见方法
append()
5.3练习3.测试字符串连接
创建包:cn.tedu.api
创建类:TestString3.java
package cn.tedu.api;
/*本类用于测试字符串的拼接*/
public class TestString3 {
public static void main(String[] args) {
//需求:将26个字母拼接10000次
String s = "abcdefghijklmnopqrstuvwxyz";
//method1(s);//使用方式一拼接字符串
method2(s);//使用方式二拼接字符串
}
//使用方式二拼接字符串
private static void method2(String s) {
//1.创建工具类对象
StringBuffer sb = new StringBuffer();
StringBuilder sb2 = new StringBuilder();
//5.添加一个计时的功能
//5.1拼接之前获取系统当前时间作为开始时间
long t1 = System.currentTimeMillis();
//2.拼接10000次
for (int i = 0; i < 10000; i++) {
//3.使用工具类对象的append()进行拼接
//sb.append(s);
sb2.append(s);
}
//5.2拼接之后获取系统当前时间作为结束时间
long t2 = System.currentTimeMillis();
//4.打印拼接的效果
//System.out.println(sb);
System.out.println(sb2);
//5.3打印拼接总共消耗的时间
System.out.println(t2-t1);
}
//使用方式一完成字符串的拼接
private static void method1(String s) {
//1.创建一个变量用来保存拼接后的效果
String result = "";
//5.给程序添加一个计时的功能
//5.1获取循环开始的系统当前时间
long t1 = System.currentTimeMillis();
//2.创建循环执行10000次
for (int i = 0; i < 10000; i++) {
//3.进行字符串的拼接
result = result + s;
}
//5.2获取循环拼接之后的系统当前时间
long t2 = System.currentTimeMillis();
//4.打印拼接后的效果
System.out.println(result);
//5.打印花费的时间
System.out.println(t2-t1);
System.out.println(t2);
}
}
6 拓展
6.1 ==和equals的区别
1.当使用= =比较时,如果相比较的两个变量是引用类型,那么比较的是两者的物理地值(内存地址),如果相比较的两个变量都是数值类型,那么比较的是具体数值是否相等。
2.当使用equals()方法进行比较时,比较的结果实际上取决于equals()方法的具体实现
众所周知,任何类都继承自Object类,因此所有的类均具有Object类的特性,比如String、integer等,他们在自己的类中重写了equals()方法,此时他们进行的是数值的比较,而在Object类的默认实现中,equals()方法的底层是通过==来实现的。
6.2 练习: ==与equals测试
创建包: cn.tedu.api
创建类: Test.java
package cn.tedu.api;
/**本类用于测试==与equlas的区别*/
public class Test{
public static void main(String[] args) {
Person p1 = new Person("凹凸曼",16);
Person p2 = new Person("凹凸曼",16);
System.out.println(p1 == p2);//false,new了两个对象,p1和p2保存的地址值不同
System.out.println(p1.name == p2.name);//true,name是String类型,保存在常量池中,值是同一个
System.out.println(p1.age == p2.age);//true,age是int基本类型,保存的值都是18
//第一次测试:结果false,使用的是Object默认的逻辑,也是用==来比较的
//第二次测试:结果true,重写equals()后,就会使用子类重写后的功能,也就是说此时比较的不再是地址,而是类型&属性值
System.out.println(p1.equals(p2));
}
}
//1.创建Person类
class Person {
String name;
int age;
public Person() {
System.out.println("我是手动添加的无参构造");
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
//需求:比较两个对象的属性值,如果属性值都一样,就是"同一个对象",要求equals返回true
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
6.3 StringBuilder和StringBuffer的区别
1.在线程安全上 :
–StringBuffer是旧版本就提供的,线程安全的。@since JDK1.0
–StringBuilder是jdk1.5后产生,线程不安全的。@since 1.5
2. 在执行效率上,StringBuilder > StringBuffer > String
3.源码体现:本质上都是在调用父类抽象类AbstractStringBuilder来干活,只不过Buffer把代码加了同步关键字,使得程序可以保证线程安全问题。