java之常见API和异常
API
1.API
Api即Application ProgrammingInterface(应用程序编程接口)。java中的API指的是JDK中提供的各种功能的java类,这些类把提层封装,我们不关系如何实现,只关心如何使用即可。
// 例如 生成随机数、控制台输出、字符串等
new Random().nextInt();
System.out.println("");
new Strng();
2.Object类
-
问:Object中都有哪些方法呢?
- 答:在Object中只有一个无参数的构造方法。我们子类会默认调用父类中的无参构造方法。
-
- clone() 克隆方法(复制对象)
equals(Object obj):比较两个对象是否相等- finalize() -----jvm的gc机制(已经过时)
- getClass ---获取该对象的class 运行时类
hashCode---返回该对象的哈希码值 hashMap集合- notify(), notifyAll(),wait(),wait(long timeoutMillis) --多线程之间的通讯会使用到
- toString() ---返回对象的字符串表示形式
3. Object类 toString()
对于System.out.println()
- println方法调用了 String s = String.valueOf(obj类的对象);
- valueOf: return (obj == null) ? "null" : obj.toString();
- obj.toString : return getClass().getName() + "@" + Integer.toHexString(hashCode());
- 即 toString 获得该类的路径 + @+ 对象的哈希值 转换为字符串输出回来
重写toString()方法
一般情况下 对象重写了toString 输出对象中成员属性值
- Object中toString()的目的就是给我们对象重写的,输出对象中的成员属性值
4. String字符串
String的底层实现
String str = "lanshuqian";
System.out.println(str); //lanshuqian
// 如果想使用char保存字符串的话 我们需要要创建一个char[] 数组
char[] value = {'l','a','n','s','h','u','q','i','a','n'};
System.out.println(value); //lanshuqian
jdk8中String底层就是基于 char[]实现的jdk9中String底层是基于byte[]数组实现的
4.1 String中split()方法
split表达式 其实就是一个正则表达式 * ^ | 等符号必须加转义字符 \
String str = "兴城市|北京市|上海市|孝感市";
// 通过 | 来进行分割字符串 最终返回数组类型
String[] split = str.split("\|");
System.out.println(split[0]);
System.out.println(split[1]);
System.out.println(split[2]);
System.out.println(split[3]);
--------------------------
console:
兴城市
北京市
上海市
孝感市
4.2 IndexOf()
//查找字符 wjy
String str = "lanshuqianwjy";
// 1. 如果存在 wjy 就返回 开始时的下标位置 不存在返回-1
int findWjy = str.indexOf("wjy");
System.out.println(findWjy); //10
// 2. 我想知道 第二个wjy开始的下标 从13开始计数
String str2 = "lanshuqianwjyAndwjy";
int secondWjy = str2.indexOf("wjy", 12);
System.out.println(secondWjy); //16
public static void main(String[] args) {
String str = "MaA644";
// 65 为 'A'
int a = str.indexOf(65);
int i = str.indexOf(97);
System.out.println(a); //2
System.out.println(i); //1
}
4.3 StringApi帮助文档
- toLowerCase()
- toUpperCase()
5. String中的equals()方法
String str1 ="lanshuqian1";
String str2 = "lanshuqian2";
//比较两个字符串的值是否相等 相等返回true
System.out.println(str1.equals(str2)); //false
第一个对象最好确认是非空的,否则会出现NPE,所以编码习惯应该把可能为空的写在后面
-
底层原理解析:
- Object类中equals方法 默认比较两个对象的内存地址是否相同
- 比较两个字符串 值(value) 对应的char[]数组 存放的元素值 是否都是相同的 相同true 不相同false
public boolean equals(Object anObject) {
// String.equals()先比较两个字符串的地址是否相同
if (this == anObject) {
return true;
}
// 判断比较的类型是否是String类型
if (anObject instanceof String) {
//强转 String 开始
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String中equals()方法原理
package com.wang.day01;
public class Test05 {
public static void main(String[] args) {
/**
* 定义两个char类型数组
*/
char[] str1 = {'m', 'a', 'y', 'i', 'k', 't'};
char[] str2 = {'m', 'a', 'y', 'i', 'k', 't'};
System.out.println(compare(str1, str2));
}
public static boolean compare(char[] str1, char[] str2) {
//默认返回true;
// 1.比较两个char类型的长度是否相同
if(str1.length != str2.length){
//两个char类型长度都不一致没必要比较char[]中的元素是否相同
return false;
}
int n = str1.length; //获取str1的长度
int i = 0;
while (n-- != 0){
// 通过循环的形式比较两个char类型数组 对应的 index 下标位置元素值 是否是相同的
if(str1[i] != str2[i]){
// 直接退出while循环
return false;
}
i++;
}
// 如果两个char类型数组中的 元素值 相同 直接返回true
return true;
}
}
6. Object中的equals()方法
- equals 比较两个对象的值是否相同
- == 比较两个对象的内存地址是否相同
但这么说不严谨,条件:==如果自定义的对象没有重写object父类的话,则是在比较两个对象的 内存地址是否相同 也就是说 和 ==一样
Object中equals()源码:
public boolean equals(Object obj) {
return (this == obj);
}
1.equals():如果对象不重写equals方法,他的作用和==是一样的,都是比较地址的值!但是大部分的类 都会重写父类的equals方法,来判断两个对象的内容是否相等。例如 String就重写了equals方法,用来比较字符串的内容是否相同。
2.==:比较引用数据类型的时候,如果该对象没有重写equals方法,那么比较的是地址。如果重写了,就按照重写规则来比较对象。
`基本数据类型 只能用==来判断两个值是否相同,因为基本数据类型不是类 不存在方法`
重写Object中的equals() 比较成员属性是否相同
public boolean equals(Object obj){
// this指的是s1对象
if(this==obj){ //两个对象的内存地址相同 直接返回true
return true;
}
if(obj == null || obj.getClass() != this.getClass()){
return false; // 类型不一样 没必要比较成员属性值
}
//开始比较属性值
retutn this.age == obj.age && this.name.equals(obj.name);
}
7. arrays中的常用方法
- Arrays.toString()
将数组转成字符串
int[] arrs = {99, 87, 22, 33, 7};
String str = Arrays.toString(arrs);// 将数组转换成字符串
System.out.println(str); //[99, 87, 22, 33, 7]
- Arrays.sort()
排序数组内的值
// 定义一个数组
int[] arrs = {99, 87, 22, 33, 7};
//排序
Arrays.sort(arrs); //底层封装了 冒泡排序!!
System.out.println("排序后的结果" + Arrays.toString(arrs)); //[7, 22, 33, 87, 99]
char[] ch = {'d','a','c','e'};
//sort方法 如果int类型是从小到大牌 char类型是abcd
Arrays.sort(ch);
System.out.println(Arrays.toString(ch)); //[a, c, d, e]
8. jdk9为何把String底层改为byte[]
节省String占用jvm的内存空间
9. String遍历字符串
public class Test06 {
public static void main(String[] args) {
/**
* 实现遍历字符串
*/
String str1 = "lanshuqian";
// 因为string底层是用char[]封装的 我们遍历char[]数组即可
// charAt(): 根据 char value[index下标]获取对应的字符
for(int i=0; i< str1.length();i++){
System.out.println(str1.charAt(i));
}
// 底层源码实现: return value[index]
}
}
10. System类
- System类中常用方法
| public static void exit(int status) | 终止当前运行的java虚拟机;0为正常退出,非0为异常退出 |
|---|---|
| public static long currentTimeMills() | 返回系统当前时间,以毫秒为单位(监考点位1970年1月1日) |
- 计算代码运行时间 (毫秒为单位)
long start = System.currentTimeMillis();//获取当前系统时间 1970/1/1---当前时间(for执行前)
for (int i = 0; i < 10000; i++) {
System.out.println("lanshuqian"); //36ms
}
long end = System.currentTimeMillis();//获取当前系统时间 1970/1/1---当前时间(for执行后)
System.out.println("执行该for循环1w次花费的时间:"+(end-start)+"毫秒");
11、工具类的设计思想
- 构造方法使用
private关键字修饰,禁止外部实例化 - 成员方法public
static关键字修饰 工具类中的方法 直接通过 类名.方法名()即可
12、包装类概念
- 八种基本数据类型:byte,short,int,long,float,double,char,boolean
- 八种基本数据类型都有对应的包装类
- 包装类是对基本数据类型做的包装
- 包装类目的在于
基本数据类型和字符串之间做转化
13、 Integer包装类 (.valueOf)
| 方法名称 | 说明 |
|---|---|
| public Integer(int value) | 根据int值创建Integer对象(过时) |
| public Integer(String s) | 根据String值创建Integer对象(过时) |
| public static Integer valueOf(int i) | 返回表示指定int值的Integer实例 |
| public static Integer valueOf(String s) | 返回一个保存指定值的Integer对象String |
public class util {
public static void main(String[] args) {
Integer integer = Integer.valueOf(100);
System.out.println(integer);
Integer testData = Integer.valueOf("30"); //把字符串转换成Integer 但!前提是字符串不能是非数字(比如"3tsd9")
System.out.println(testData);
}
}
13.1 包装类的基本规则
/**
* long类型 如何与String 相互的转换
* @param args
*/
public static void main(String[] args) {
// str ---> long
String str = "123456789";
// 方法一
Long aLong = Long.valueOf(str);
long l1 = aLong.longValue();
System.out.println(l1);
//方法二
long l2 = Long.parseLong(str);
System.out.println(l2);
}
-------------------------------------------
String falg = "sadsa";
boolean b = Boolean.parseBoolean(flag); //false
13.2 Integer包装类底层设计原理
int与Integer的区别
-
int 是基本数据类型 Integer属于int的包装类对象 是一个类
-
基本数据类型 存放在栈空间中的 局部变量表(方法) (了解)
-
包装类属于对象 存在堆空间中
Integer integerA = 60; --------------------- public static Integer valueOf(int i) { return new Integer(i); } --------------------- private final int value; public Integer(int value) { this.value = value; }-
为什么输入 对象名称 输出的不是内存地址 而是值呢
- 包装类重写了toString()方法 输出对应的基本数据类型
-
- Integer属于包装类 包装类默认值为 null int 基本数据类型 默认值为0
- 包装类--->引用传递 基本数据类型---->值传递
int byte short long floag这些数字类型的默认值都是0
boolean的默认值是false
13.3 装箱和拆箱
- 装箱: 就是自动将
基本数据类型转换为包装器类型 - 拆箱: 就是自动将
包装类型转换为基本数据类型
public static void main(String[] args) {
/**
* 装箱原理走的是: Integer.valueOf(基本数据类型`60`)
* 拆箱原理走的是: public int intValue(){return value} 获取包装类中的基本数据类型
*/
Integer a = 60; // 60 是基本数据类型int Integet a 是一个包装类 ,这里就是 `自动装箱`
int z = a; //包装类 赋值 给 int类型 拆箱 ,这里是 `自动拆箱`
Integer j = 0;
j += 1;
// j += 1: 即 j = j + 1; 因为j 是包装类 j+1先 自动拆箱
// j+1的值 赋值给j 因为j是 包装类 包装类 = (0+1) 自动装箱
}
14、String类中的valueOf()方法
- 需求: 把int转换成字符串
/**
* 使用String.valueOf方法 将int long double char boolean都可以转成string
*/
int a = 66;
//方式一(空字符串+int)
String a1 = a + "";
//方式二(valueOf方法)
String a2 = String.valueOf(a);
15、 String如何转换成int类型
字符串转int
// String 转换成 int
/**
* String类型存放的字符串是 数字
*/
String str = "123";
Integer integer = Integer.valueOf(str); //Integer类型的123
//intValue 该方法不是静态方法 先new对象 对象实例.intValue方法
// 也就是调用intValue 方法 获取Integer 包装的 int基本数据类型 返回int类型
int i = integer.intValue(); //int类型的123
// 方法二 实际开发中使用以下这种方法
int i1 = Integer.parseInt(str);
System.out.println();
16、String的替换方法
public static void main(String[] args) {
String str = "lanshuqian1111"; //define a string , we'll replace 1111 to 'wjy'
/**
* 参数1: 需要替换的字符串内容 (1111)
* 参数2: 替换后的字符串内容(wjy)
*/
System.out.println("替换前"+ str);
String newStr = str.replace("1111", "wjy");
System.out.println("替换后"+newStr); //lanshuqianwjy
}
replaceFirst: 替换第一次匹配到的字符 并且之更改这个
repalceAll: 替换所有
replaceAl()l和replace()都是替换所有的字符串 replace()是不支持正则,replaceAll()支持正则
17、Date类
- Date代表了一个特定的时刻 ,精确到毫秒
构造方法
| 方法名 | 说明 |
|---|---|
| public Date() | 分配一个Date对象,并初始化,以便代表它所分配的时间,精确到毫秒 |
| public Date(Long Date) | 分配一个Date对象,并初始化为从标准时间基准起指定的毫秒数 |
public static void main(String[] args) {
// 使用Date日期类 引入java.util.Date
Date date1 = new Date();
System.out.println(date1); // 输出当前系统时间
//获取的时间从1970/1/1的 08:00:00 + 1 h GMT(格林威治时间)
long time = 1000 * 60 * 60 ;
Date date2 = new Date(time);
System.out.println(date2); // 1970/1/1的 09:00:00
}
常用方法
| 方法名称 | 说明 |
|---|---|
| public long getTime() | 获取的日期对象从1970/1/1 00:00:00 到现在毫秒值(时间戳) |
| public void setTime(Long time) | 设置时间 给的是毫秒值 和构造器的 public Date(Long Date) 同样效果 |
Date date = new Date();
// 1970/1/1/ 00:00:00 -------- 2022/9/25 系统毫秒数 时间戳
System.out.println(date.getTime());
// 1970/1/1/ 00:00:00 时间差8h + 1个小时 和构造器的public Date(Long date)相同
long time = 1000 * 60 * 60;
date.setTime(time);
System.out.println(date);
SimpleDateFormat
构造方法
| 方法名 | 说明 |
|---|---|
| public new SDF() | 构造一个sdf,使用默认格式和日期 |
| public new SDF(String pattern) | 构造一个sdf,使用给定的模式和默认样式 |
-
格式化 解析日期 将Date对象转化为 年月日时分秒 格式字符串 -
把字符串转化为Date对象Date parse(String source) -
常用的模式字母:
- y 年
- M 月
- d 日
- h 时 在上午或下午(1~12)
- H 时 在一天中(0~23)
- m 分
- s 秒
date转成str
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String strDate = sdf.format(date);
System.out.println("格式化后的日期" + strDate);
}
字符串日期转为date
// 日期字符串转换为date
String strDate = "2021-10-22 04:45:30";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//将 string 字符串类型日期 转换成Date类型
Date date = simpleDateFormat.parse(strDate);
System.out.println(date);
日期工具类的设计
/**
* 日期工具类
*/
public class DateUtils {
private static final String FORMAT_1 = "yyyy-MM-dd HH:mm:ss";
private DateUtils(){
}
//1. 将Date 转为 字符串
public static String dateToString(Date date,String format){
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
}
// 获取当前的系统时间转化为字符串
public static String getCurrentDateString(){
return dateToString(new Date(),FORMAT_1);
}
//2. 将字符串 转为 Date
public static Date StringToDate(String date,String format){
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
return sdf.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
18、 Calendar抽象类
-
一个
抽象类(当然 无法实例化)- 所以理所应当子类实现它
- 它的子类有 1. BuddhistCalendar 2.GregorianCalendar 3.JapaneseImperialCalendar
public static void main(String[] args) {
// 获取Calendar 对象
Calendar c = Calendar.getInstance();
System.out.println(c);
//获取年月日(注意 月分下标从0开始)
int year = c.get(Calendar.YEAR); //获取年份
int month = c.get(Calendar.MONTH);//获取月分
int date = c.get(Calendar.DATE); // 获取日
System.out.println(year+"年"+(month + 1)+"月"+date+"日");
}
常用api方法
- 修改年月日
Calendar c = Calendar.getInstance();
//修改获取的系统时间
c.add(Calendar.YEAR,-20); //对年份修改
c.add(Calendar.MONTH,-2); // 月分修改
c.add(Calendar.DATE,13); // 对日修改
- 直接设置时间
Calendar c = Calendar.getInstance();
c.set(2080,8,9);
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int date = c.get(Calendar.DATE);
19、 二月份有多少天
public static void main(String[] args) {
System.out.println("键入年份:");
Scanner sc = new Scanner(System.in);
int year = sc.nextInt();//get year
Calendar c = Calendar.getInstance();
//设置时间为3/1 前一天就是2月的最后一天 (month从0开始)
c.set(year,2,1);
//修改日
c.add(Calendar.DATE,-1);
System.out.println(c.get(Calendar.DATE));
}
20、内存图解
- 方法
没有被调用的时候,在方法区中的字节码文件存档 - 方法
被调用的时候,需要进入到栈内存中运行
类似手枪的子弹 弹夹 就是方法区 放到枪的活塞里才能打出去(这个区域理解成栈内存)
main方法 从方法区 载入 到栈内存中 在栈内存中调用其他函数(其他函数入栈)
21、java元空间
- JDK1.8之前称作为方法区、永久代 jdk1.8之后称为 元空间
/**
* 1. JDK1.8之前称为 方法区 永久代 存放静态变量 class信息
* 2. 堆中 new出来的东西
* 定义的字符串 存放在 字符串常量池中
* jdk1.7之前 字符串常量池存放在方法区中
* jdk1.7开始 字符串常量池存在堆里面
*/
异常
1. 什么是异常?
- 异常:就是程序执行报错或者出现了不正常现象
2. 异常的处理
-
JVM默认的情况下 如果程序执行报错 则会中断JVM 报错之后的代码不会再执行了
-
解决方法:
- try...catch...
- throws
3.catch顺序问题
try {
}catch (){
}catch (){
}........
4. Exception异常
Throwable是java语言中所有异常的超类
try {
}catch (Exception e){
sout("捕获了所有异常")
}
----------------
try {
}catch (Exception e){
sout("捕获了所有异常")
}catch(ArrayIndexOutOfIndex e){
// 上面已经捕获了所有异常 下面这个catch不会执行 也不会通过编译
}
---------------------
try {
}catch(ArrayIndexOutOfIndex e){
// 顺序执行 先检测是不是数组访问下标越界异常
}catch (Exception e){
sout("捕获了所有异常") //如果不是以上的任意一个exeption 捕获所有
}
5. Throwable成员方法
| 方法名 | 说明 |
|---|---|
| public String getMessage | 返回此throwable的详细消息字符串(异常错误信息内容) |
| public String toString | 返回此可抛出的简短描述 |
| public void printStackTrace() | 把异常的错误信息输出在控制台 |
6. 编译时异常和运行时异常
-
java中主要分成两大类
- 编译时异常(受检异常) --------必须显示处理,否则程序会发生错误,不能编译
- 运行时异常(非受检异常)-------
无需显示处理,可以编译通过,但是程序运行时可能发生异常
区分异常: RunTimeException类以及子类 都是运行时异常 其余的异常都是编译时异常
7. throws
- java允许在方法的后面使用throws关键字对声明该方法可能有异常,这样调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理(try catch 或者 抛出去),否则编译无法通过。
- 一个注意点:
public void a1(){
a2(); //此时的a2()爆红,我们需要处理异常(try catch或者给虚拟机)
}
public static void a2() throws Exception{
}
//但是还有一现象
------------------
public void a1(){
a2(); //a2()不爆红,因为a2()抛出的异常是运行时异常 不需要强制要求做捕获异常的
}
public static void a2() throws ArrayIndexOutOfBoundsException{
}
8.自定义异常
- 自定义异常类 继承异常类即可
//运行时异常
public class XXXException extends RuntimeException{
}
//编译时异常
public class XXXException extends RunTimeException{
}