1 前言
亲爱的小伙伴萌,目前我们看到的是Java基础部分的一个新的部分API,这是个啥,又能做啥呢?
其实可以概括成一句话:帮助我们站在巨人的肩膀上,实现更加高效的开发,那么我们来一探究竟吧~
2 什么是API
API(Application Programming Interface,应用程序接口)是一些预先定义的函数。目的是提供应用程序与开发人员基于某软件可以访问的一些功能集,但又无需访问源码或理解内部工作机制的细节.
API是一种通用功能集,有时公司会将API作为其公共开放系统,也就是公司制定自己的系统接口标准,当需要进行系统整合,自定义和程序应用等操作时,公司所有成员都可以通过该接口标准调用源代码.
Java.util包是java中的工具包,包含各种实用工具类/集合类/日期时间工具等各种常用工具包
import java.util.Scanner;
import java.util.Arrays;包括基本Object类/Class类/String类/基本数学类等最基本的类,这个包无需导入,默认会自动导入
import java.lang.Object;
import java.lang.String;
import java.lang.StringBuilder/StringBuffer;
正则表达式
包装类等等 –
那么接下来我们会学习一些常用的类,帮助大家完成"基建工程",首先第一位选手就是传说中的Object类
3 Object
3.1概念
Object类是所有Java类的祖先,也就是说我们所说的”顶级父类”
它存在于java.lang.Object,这个包不需要我们手动导包
需要注意的是:每个类都使用Object作为超类.所有对象(包括数组)都实现这个类的方法.
在不明确给出超类的情况下,Java会自动把Object类作为要定义类的超类.
3.2 常用方法介绍
本方法用于返回对应对象的字符串表示
本方法用于返回对应对象的哈希码值
小贴士:哈希码值的得出是通过一种算法,意在让不同的对象具有不同的哈希码值,用于区分不同的对象.
但是有时候也存在不同对象哈希码值相同的特殊情况,我们称之为”哈希碰撞”现象
本方法用于指示其他某个对象是否与当前对象”相等”
3.3 练习: Object类练习
创建包: cn.tedu.api
创建类: TestObject.java
package cn.tedu.api;
import java.util.Objects;
/**本类用于测试顶级父类Object*/
//总结:
//1.如果想要查看对象的属性值,需要重写toString()
// 否则使用的就是Object的默认实现,打印的是对象的地址值
//2.如果要判断两个对象间的所有属性值相同,比较结果为true,就需要重写equals()
// 否则使用的就是Object的默认实现,通过==比较的是两个对象的地址值,不是属性
public class TestObject {
public static void main(String[] args) {
//4.创建对象进行测试
Student s = new Student("海绵宝宝",3);
Student s2 = new Student("海绵宝宝",3);
/*测试toString():返回的是该对象的字符串表示*/
/*查看源码的方式:按住Ctrl键,移到目标位置,鼠标点击即可*/
//5.打印s对象
//5.1测试1打印的是cn.tedu.api.Student@1b6d3586,是地址值,因为Object默认实现:
//return getClass().getName() + "@" + Integer.toHexString(hashCode());
//5.2测试2打印的是Student{name='海绵宝宝', age=3},是重写toString()以后的结果
System.out.println(s);
/*测试hashcode()*/
//6.测试hashCode()
System.out.println(s.hashCode());//460141958
//7.测试equals()
//7.1第一次测试执行结果是false
//底层:用了==进行对象间的比较,==比较的是两个对象的地址值,s和s2是两个对象,地址值不同
//public boolean equals(Object obj) { return (this == obj);}
//需求:比较s与s2对象,如果属性值相同,就认为是同一个对象,并让equals()返回true
//7.2第二次测试执行结果是true
System.out.println(s.equals(s2));
}
}
//1.创建学生类
class Student{
//2.定义属性
String name;//姓名
int age;//年龄
//3.生成构造方法
//右键-Generate-Constructor-按住Shift可以全选属性
//3.1定义无参构造
public Student() { }
//3.2定义全参构造
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//6.添加重写的toString()
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
//Objects.equals(name, student.name)
//因为name是String类型
//有可能传入的姓名不是“rose”,而是new String("rose"),那两个String对象比较地址值就是不等的。
//所以需要使用String类中的equlas()方法比较,不能直接使用==比较,==比较的是地址值,我们只是想比较姓名字符串而已
}
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”;
- 如果是第一次使用字符串,java会在字符串堆中常量池创建一个对象。
- 再次使用相同的内容时,会直接访问堆中常量池中存在的对象。
4.3 常见方法
String API总结
int hashCode() 返回此字符串的哈希码。
boolean equals(Object anObject) 将此字符串与指定的对象比较,比较的是重写后的串的具体内容
String toString() 返回此对象本身(它已经是一个字符串!)。
int length() 返回此字符串的长度。
String toUpperCase() 所有字符都转换为大写。
String toLowerCase() 所有字符都转换为小写
boolean startsWith(String prefix) 测试此字符串是否以指定的元素开头。
boolean endsWith(String suffix) 测试此字符串是否以指定的字符串结束。
char charAt(int index) 返回指定索引/下标处的 char 值/字符
int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。
int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。
String concat(String str) 将指定字符串连接/拼接到此字符串的结尾,注意:不会改变原串
String[] split(String regex) 根据给定元素来分隔此字符串。
String trim() 返回去除首尾空格的字符串
byte[] getBytes() 把字符串存储到一个新的 byte 数组中
String substring(int beginIndex) 返回一个新子串,从指定下标处开始,包含指定下标
String substring(int beginIndex, 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类对象
String s11 = new String(value);//触发含参构造来创建String类对象
//2.练习创建String的方式二:
/**2.此种方式创建底层也会new String(),存放在堆中常量池,效率高*/
String s2 = "abc";
String s22 = "abc";
String s3 = "aaa";
//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,有高效效果,但值不一样
/**3.==比较的是两个对象的地址值
* Object类中equals()默认实现比较的也是==地址比较
* 但String类重写了此方法,不再比较地址值,而是两个串的具体内容
* 也就是说,不论创建方式,只要串的内容一致,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 s = "abc";
char[] value = {'a','b','c'};
String ss = new String(value);
//2.测试常用方法
System.out.println(s.charAt(1));//b,获取指定下标处的字符
String s2 = s.concat("cxy");//用于拼接指定的字符串,但注意不会改变原串
System.out.println(s);//abc,不会改变原串
System.out.println(s2);//abccxy,打印的是拼接后s2指向的串abccxy
System.out.println(s.concat("cxy"));
System.out.println(s.endsWith("y"));//false,判断是否以指定元素结尾
System.out.println(s.startsWith("a"));//true,判断是否以指定元素开头
System.out.println( s == ss );//false,比较的是地址值
System.out.println(s.equals(ss));//比较的是内容
//1,获取指定元素首次出现的下标值
System.out.println(ss.indexOf("b"));
ss = "abcbb";
//4,获取指定元素最后一次出现的下标值
System.out.println(ss.lastIndexOf("b"));
System.out.println(ss.length());//5,获取指定字符串的长度
String s3 = "a b c d e";
//根据指定规则分割字符串,注意返回值类型是String[],需要使用数组工具类打印
System.out.println(s3.split(" "));//[Ljava.lang.String;@1b6d3586
System.out.println(Arrays.toString(s3.split(" ")));
//根据指定下标截取子串,如果只有一个下标,那就从指定位置处开始截取,包含指定下标
//如果有两个下标,就截取这两个下标之间的子串,注意含头不含尾
System.out.println(s3.substring(3));// c d e,[3,结束]
System.out.println(s3.substring(1,5));// b c,[1,5)
System.out.println(s3.toUpperCase());//A B C D E,把指定字符串转为全大写
System.out.println(s3.toLowerCase());//a b c d e,把指定字符串转为全小写
s3 = " abcde ";
System.out.println(s3.trim());//abcde,去除指定字符串首尾空格
System.out.println(String.valueOf(10));//10,转为String类型的"10"
System.out.println("20"+10);//2010,String20与int10不能计算,拼接
System.out.println(String.valueOf(80)+10);//8010,int80转String80,拼接
System.out.println(10+10);//20,int+int->int
}
}
5 StringBuilder/StringBuffer
5.1 特点
- 封装了char[]数组
- 是可变的字符序列
- 提供了一组可以对字符内容修改的方法
- 常用append()来代替字符串做字符串连接”+”
- 内部字符数组默认初始容量是16:super(str.length() + 16);
- 如果大于16会尝试将扩容,新数组大小原来的变成2倍+2,容量如果还不够,直接扩充到需要的容量大小。int newCapacity = value.length * 2 + 2;
- StringBuffer 1.0出道线程安全,StringBuilder1.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) {
//method();//完成通过"+"进行拼接
method2();//优化"+"拼接
}
public static void method2() {
//1.定义字符串
String str = "abcdefghijklmnopqrstuvwxyz";
//2.将指定的字符串拼接10000次
/**优化1:String-->StringBuffer/StringBuilder*/
StringBuffer sb = new StringBuffer();//创建工具类对象1
StringBuilder sb2 = new StringBuilder();//创建工具类对象2
//2.2拼接10000次
/**4.可以添加一个计时功能*/
//4.1获取系统当前时间作为开始时间
long t1 = System.currentTimeMillis();//ms
for(int i = 0; i < 10000 ; i++) {
/**优化2:+ -->append() */
//result = result + str;
sb.append(str);
//sb2.append(str);
}
//4.2获取系统当前时间作为结束时间
long t2 = System.currentTimeMillis();//ms
//3.打印拼接好的字符串
//注意:eclipse控制台显示数据有限制,都打印在同一行了,所以控制台看不出来打印的内容
//可以通过全选,复制拿出来看数据是否拼接成功
//4.3打印拼接总共花费的总时长
System.out.println(sb.toString());//打印拼接的结果
System.out.println(t2-t1);
}
public static void method() {
//1.定义字符串
String str = "abcdefghijklmnopqrstuvwxyz";
//2.将指定的字符串拼接10000次
//2.1定义变量,用来保存最终拼接的结果
String result ="";
//2.2拼接10000次
/**4.可以添加一个计时功能*/
//4.1获取系统当前时间作为开始时间
long t1 = System.currentTimeMillis();//ms
for(int i = 0; i < 10000 ; i++) {
result = result + str;
}
//4.2获取系统当前时间作为结束时间
long t2 = System.currentTimeMillis();//ms
//3.打印拼接好的字符串
//注意:eclipse控制台显示数据有限制,都打印在同一行了,所以控制台看不出来打印的内容
//可以通过全选,复制拿出来看数据是否拼接成功
System.out.println(result);
//4.3打印拼接总共花费的总时长
System.out.println(t2-t1);
}
}
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把代码加了同步关键字,使得程序可以保证线程安全问题。