内部类
基本介绍
一个类的内部又完整的嵌套了另一个类构造。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员【属性,方法,构造器,代码块,内部类】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
基本语法2
class Outer{ //外部类
class Lnner{
}
}
class Other{ //外部其他类
}
内部类的分类(4种)
定义在外部类局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点)
定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
局部内部类的使用
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位都是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰(使用后不会被继承),因为局部变量也可以使用final
- 作用域:仅仅在定义它的方法或代码块中。
- 局部内部类----访问---->外部类的成员【访问方式:直接访问】
- 外部类----访问---->局部内部类的成员
访问方法:创建对象,在访问(注意:必须在作用域内) - 外部其他类---->不能访问---->局部内部类(因为 局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问
System.out.println(“外部类的n2” + 外部类名.this.n2);
记住: (1)局部内部类定义在方法中/代码块
(2)作用域在方法体或者代码块中
(3)本质仍是一个类
匿名内部类的使用(重要!!)
说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
// 1.本质是类 (2)内部类 (3)该类没有名字 (4)同时还是一个对象
- 匿名内部类的基本语法
new 类或接口 (参数类表){
类体
}; - 匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看成个特点,因此可以调用匿名内部类方法。
- 可以直接访问外部类的所有成员,包含私用的
- 不能添加访问修饰符因为它的地位就是一个局部变量。
- 作用域:仅仅在定义他的方法或代码块中。
- 匿名内部类—访问—>外部类成员 【访问方式:直接访问】
- 外部其他类—不能访问—>匿名内部类(因为 匿名内部类地位是一个局部变量)
- 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
基于接口演示
/*
演示匿名内部类的使用(基于接口)
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04{ //外部类
private int n1 = 10; //属性
public void method() {
//基于接口的匿名内部类
/*
1.需求:想使用接口IA,并创建对象
2.传统方法,写一个类,实现该接口,并创建对象
3.需求是 Tiger 类只能使用一次,后面不再使用
4.可以使用匿名内部类来简化开发
5.tiger 的编译类型是 IA
6.tiger 的运行类型是 就是 匿名内部类 名为 Outer04$1
7.jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1实例,
并把地址返回个 tiger
8.匿名内部类使用一次,就不能再使用
我们
*/
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎");
}
};
tiger.cry();
System.out.println("tiger的运行类型=" + tiger.getClass());
// IA tiger = new Tiger();
// tiger.cry();
}
}
interface IA{ //接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎");
// }
//}
class Father{ //类
public Father(String name) { //构造器
super();
}
public void test() { //方法
}
}
基于类的演示
/*
演示匿名内部类的使用(基于接口)
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04{ //外部类
private int n1 = 10; //属性
public void method() {
//基于接口的匿名内部类
/*
1.需求:想使用接口IA,并创建对象
2.传统方法,写一个类,实现该接口,并创建对象
3.需求是 Tiger 类只能使用一次,后面不再使用
4.可以使用匿名内部类来简化开发
5.tiger 的编译类型是 IA
6.tiger 的运行类型是 就是 匿名内部类 名为 Outer04$1
7.jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1实例,
并把地址返回个 tiger
8.匿名内部类使用一次,就不能再使用
我们
*/
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎");
}
};
tiger.cry();
System.out.println("tiger的运行类型=" + tiger.getClass());
// IA tiger = new Tiger();
// tiger.cry();
//演示基于类的匿名内部类
//分析
//1. father 编译类型 Father
//2. father 运行类型 Outer04$2
Father father = new Father("jack") {
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
System.out.println("father的运行类型=" + father.getClass());
father.test();
}
}
interface IA{ //接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎");
// }
//}
class Father{ //类
public Father(String name) { //构造器
super();
}
public void test() { //方法
}
}
两种调用匿名内部类方式
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
}
}
class Outer05 {
private int n1 = 99;
public void f1() {
//创建一个基于类的匿名内部类
Person p = new Person(){
@Override
public void hi() {
System.out.println("匿名内部类重写了 hi方法");
}
};
p.hi();//动态绑定,运行类型是 Outer05$1
//也可以直接调用,匿名内部类本身也是返回值对象
//class 匿名内部类 extends Person {}
new Person(){
@Override
public void ok(String str) {
super.ok(str);
}
}.ok("jack");
}
}
class Person {//类
public void hi() {
System.out.println("Person hi()");
}public void ok(String str) {
System.out.println("Person ok()" + str);
}
}
案例
package com.zzj.innerclass;
import javafx.scene.control.Cell;
public class InnerClassExercise02 {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
/*
1.传递的是实现了 Bell接口的匿名内部类
2.重写了 ring
3.Bell bell = new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了!!!");
}
}
*/
cellphone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了!!!");
}
});
cellphone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上学了!!");
}
});
}
}
interface Bell { //铃声接口
void ring();
}
class Cellphone { //手机类
public void alarmclock(Bell bell) { //形参是Bell接口类型
bell.ring();//动态绑定
}
}
成员内部类的使用
说明: 成员内部类是定义在外部类的成员位置,并且没有static修饰。
- 可以直接访问内外部类的所有成员包含私有的
- 可以添加任何访问修饰符(public 、protected 、默认 、private) ,因为它的地位就是一个成员。
- 作用域 和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建内部类对象,在调用方法。
- 成员内部类—访问—>外部类(比如:属性)【访问方法:直接访问】
- 外部类—访问—>内部类 访问方式:创建对象,再访问
- 外部其他类—访问—>成员内部类
//外部其他类,使用成员内部类的2种方法
//1
//outer08.new Inner08(); 相当于把 new Inner08()当做是outer08成员
Outer08 outer08 = new Outer08();
Outer08.Inner08 inner08 = outer08.new Inner08();
//2
//在外部类中,编写一个方法,可以返回 Inner08对象
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
Public Inner08 getInner08Instance() {
retrun new Innero8();
}
- 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
静态内部类的使用
说明:静态内部类是定义在外部类的成员位置,并且有static修饰
- 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
- 可以添加任意修饰符(public、protected、默认、private),因为它的地位就是一个成员
- 作用域:同其他的成员,为一个类体
- 静态内部类—访问—>外部类(比如:静态属性)【访问方式:直接访问所有静态成员】
- 外部类—访问—>静态内部类 访问方式:创建对象,再访问
- 外部其他类—访问—>静态内部类
- 如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fPTuzK8V-1656837106707)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1655985071969.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KVNsol5h-1656837106709)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1655985737670.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4QMCDf5x-1656837106710)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1655985681469.png)]
枚举类
- 枚举对应英文(enumeration , 简写 enum)
- 枚举十一组常量的集合。
- 可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象。
实现方式
- 自定义实现枚举
- 使用enum关键字实现枚举
自定义实现枚举
- 不许要提供setXxx方法,因为枚举数组对象值通常为只读。
- 对枚举对象/属性使用 final + static 共同修饰, 实现底层优化。
- 枚举对象名通常使用大写,常量的命名规范。
- 枚举对象根据需要,也可以有多个属性。
package com.zzj.enum_;
/**
* @author 张正杰
* @version 1.0
*/
public class Enumeration02 {
public static void main(String[] args) {
System.out.println(Season.SPRING);
}
}
//演示自定义枚举实现
class Season { //类
private String name;
private String desc; //描述
public static final Season SPRING = new Season("春天","温暖");
public static final Season WINTER = new Season("冬天","寒冷");
public static final Season AUTUMN = new Season("秋天","凉爽");
public static final Season SUMMER = new Season("夏天","炎热");
//1.将构造器私有化,目的防止 直接 new
//2.去掉setXX方法,防止属性被修改
//3.在Season 内部,直接创建固定的对象
//4.优化,可以加入 final 修饰符
private Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
enum关键字实现枚举
- 使用关键字 enum 代替 class
- public static final Season SPRING = new Season(“春天”,“温暖”) 直接使用
Season(“春天”,“温暖”) 解读 常量名(实参列表) - 如果有多个常量(对象), 使用 , 号 间隔即可
- 如果使用 enum 来实现枚举, 要求将定义常量对象,写在前面
package com.zzj.enum_;
/**
* @author 张正杰
* @version 1.0
*/
public class Enumeration03 {
public static void main(String[] args) {
System.out.println(Season.SPRING);
}
}
//演示enum关键字枚举实现
enum Season2 { //类
// public static final Season SPRING = new Season("春天","温暖");
// public static final Season WINTER = new Season("冬天","寒冷");
// public static final Season AUTUMN = new Season("秋天","凉爽");
// public static final Season SUMMER = new Season("夏天","炎热");
// 如果使用了enum 来实现枚举类
SPRING("春天","温暖"),
WINTER("冬天","寒冷"),
AUTUMN("秋天","凉爽"),
SUMMER("夏天","炎热");
private String name;
private String desc; //描述
private Season2(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
enum关键字实现枚举注意事项
- 当我们使用enum 关键字开发一个枚举类时, 默认会继承Enum类【如何证明】
- 当传统的 public static final Season SPRING = new Season(“春天”,“温暖”) 简化成
Season(“春天”,“温暖”) 这里必须知道, 他调用的是哪个构造器。
如果我们使用的是无参构造器,创建常量对象,则可以省略()。 - 如果使用无参构造器 创建 枚举对象, 则实参列表和小括号都可以省略
- 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
- 枚举对象必须放在枚举类的行首
enum 常用方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zsTPTznH-1656837106711)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656224164592.png)]
package com.zzj.enum_;
/**
* @author 张正杰
* @version 1.0
*演示Enum 类的各种方法的使用
*/
public class EnumMethod {
public static void main(String[] args) {
//使用Season2 枚举类, 来演示各种方法
Season2 autumn = Season2.AUTUMN;
//输出枚举对象的名字
System.out.println(autumn.name());
//ordinal() 输出的是该枚举对象的次序/编号,从0开始编号
//AUTUMN 枚举对象是第三个 , 因此输出 2
System.out.println(autumn.ordinal());
//从反编译可以看出 values 方法,返回 Season2[]
//含有定义的所有枚举对象
Season2[] values = Season2.values();
for (Season2 season : values) { //增强for循环
System.out.println(season);
}
//valueof:将字符串转换成枚举对象,要求字符串必须VT为已有的常量名,否则报异常。
//执行流程
//1.根据你输入的“AUTUMN” 到 Season2的枚举对象去查找
//2.如果找到了,就返回,如果没有找到,就报错
Season2 autumn1 = Season2.valueOf("AUTUMN");
System.out.println("autumn1=" + autumn1);
//compareTo:比较两个枚举常量,比较的就是编号
System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));
}
}
enum实现接口
- 使用 enum关键字 后, 就不能在继承其他类了,因为 enum 会隐式继承Enum,而java是单继承机制。
- 枚举类和普通类一样,可以实现接口,如下形式
enum 类名 implements 接口1,接口2{}
注解
- 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等信息。
- 和注释不一样,注解不影响程序逻辑,但注解可以被编译或者运行,相当于嵌入在代码中的补充信息。
- 在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等,在javaEE中注解占据了重要的角色,例如用来配置应用程序的任何切面,代替javaEE 旧版中所遗留的繁冗代码和XML配置等。
Annotation介绍
使用Annotation时要在其前面增加@符号,并把该Annotation当成一个修饰符使用。用于修饰它支持的程序元素
三个基本的Annotation:
- @Override:限定某个方法,是重写父类方法,该注解只能用于方法
- @Deprecated:用于表示某个程序元素(类,方法等)已过时
- @SuppressWarnings:抑制编译器警告
Override使用说明
- @Override便是指定重写父类的方法(从编译层面验证),如果父类没有Fly方法,则会报错。
- 如果不懈@Override注解,而父类仍有 Public void fly() {} ,仍然构成重写
- @Override 只能修饰方法,不能修饰其他类,包、属性等等
- 查看@Override注解原码为 @Target(ElementType.METHOD),说明只能修饰方法
- @Target是修饰注解的注解,成为元注解
Deprecated的说明
- 用于表示某个程序元素(类,方法等)已过时
- 可以修饰方法,类,字段,包,参数 等等
- @Target(value = {CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
- @Deprecated 的作用可以做到新旧版版本的兼容和过渡
SuppressWarnings各种值的说明
- unchecked是忽略没有检查的警告
- rawtypes 是忽略没有指定泛型的警告(传参时没有指定泛型的警告错误)
- unused是忽略没有使用某个变量的警告错误
- @SuppressWarnings 可以修饰的程序元素为,查看@Target
- 生成@SuppressWarnings时,不用背,直接点击左侧的黄色提示,就可以选择(注意可以指定生成的位置)
JDK 的元 Annotation(元注解)
元注解基本介绍
JDK 的 元 Annotation 用于修饰其他 Annotation
元注解:本身作用不大。
元注解的种类
- Retention // 指定注解的作用范围 , 三种 SOURCE,CLASS,RUNTIME
- Target // 指定注解可以在那些地方使用
- Documented //指定该注解是否会在javadoc体现
- Inherited //子类后继承父类注解
练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vaVpkhAY-1656837106712)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656310243568.png)]
package com.zzj.annotaition;
/**
* @author 张正杰
* @version 1.0
*/
public class Homework06 {
public static void main(String[] args) {
Person tang = new Person("唐僧", new Horse());
tang.common(); //一般
tang.passRiver();//过河
}
}
interface Vehicles {
public void work();
}
class Horse implements Vehicles {
@Override
public void work() {
System.out.println("一般情况下使用马儿前进……");
}
}
class Boat implements Vehicles {
@Override
public void work() {
System.out.println("过河情况下使用船儿前进……");
}
}
class VehickesFactory {
private static Horse horse = new Horse(); //饿汉式
private VehickesFactory() {}
public static Horse getHorse() {
// return new Horse();
return horse;
}
public static Boat getBoat() {
return new Boat();
}
}
//在创建人对象时,事先给他分配一个交通工具
class Person {
private String name;
private Vehicles Vehickes;
public Person(String name, Vehicles vehickes) {
this.name = name;
this.Vehickes = vehickes;
}
//涉及一个编程思路,这里可以把具体的要求,封装成方法->这里就是编程思想
public void passRiver() {
//先得到船
//判断一下,当前的 vehicles 属性是null,就获取一艘船
if (!(Vehickes instanceof Boat)) {
Vehickes = VehickesFactory.getBoat();
}
Vehickes.work();
}
public void common() {
//得到马
//判断一下,当前的 vehicles 属性是null,就获取一匹马
if (!(Vehickes instanceof Horse)) {
//这里使用的是多态
Vehickes = VehickesFactory.getHorse();
}
//这里体现的是接口的调用
Vehickes.work();
}
}
内部类练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zTACdnIy-1656837106712)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656311769230.png)]
package com.zzj.annotaition;
/**
* @author 张正杰
* @version 1.0
*/
public class Homework07 {
public static void main(String[] args) {
Car car = new Car(-10);
car.a();
// Car car1 = new Car(50); //需把flow()公开public
// car1.getAir().flow();
}
}
class Car {
private int temperature = 0;
public Car(int temperature) {
this.temperature = temperature;
}
class Air {
private void flow() {
if (temperature >= 40) {
System.out.println("呼呼呼(冷风)");
} else if (temperature < 0) {
System.out.println("呼呼呼(热风)");
}
}
}
public void a() {
new Air().flow();
}
// public Air getAir() { //需把flow()公开
// return new Air();
// }
}
枚举类练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hW7yvnvG-1656837106713)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656313641046.png)]
package com.zzj.annotaition;
/**
* @author 张正杰
* @version 1.0
*/
public class Homework08 {
public static void main(String[] args) {
Color green = Color.GREEN;
green.show();
switch (green) {
case RED:
System.out.println("匹配到红色");
break;
case BLUE:
System.out.println("匹配到");
break;
default:
System.out.println("没匹配到");
}
}
}
interface Show {
public void show();
}
enum Color implements Show {
RED(255, 0 ,0),
BLUE(0, 0, 255),
BLACK(0, 0, 0),
YELLOW(255, 255, 0),
GREEN(0, 255, 0);
private int redValue;
private int greenValue;
private int blueValue;
Color(int redValue, int greenValue, int blueValue) {
this.redValue = redValue;
this.greenValue = redValue;
this.blueValue = blueValue;
}
@Override
public void show() {
System.out.println("属性值是:" + " " + redValue + " " + greenValue + " " + blueValue);
}
}
异常
异常的概念
Java语言中,将程序执行中发生的不正常情况称为"异常"。(开发过程中的语法错误和逻辑错误不是异常)
快捷键 Ctrl + Alt + t
异常时间分为两类
执行过程中发生的异常事件可分为两类
- Error(错误):Java虚拟机无法解决的严重错误。如 JVM系统内部错误、资源耗尽等严重情况。
比如:StackOverflowError【栈溢出】和OOM(out of memory), Error 是严重错误,程序会崩溃。 - Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。
例如:空指针访问,试图读取不存在的文件,网络连接终断等等,
Exception分为两大类:运行时异常【】和编译时异常【】。
异常体系图(!!!)
- 异常分为两大类,运行时异常和编译时异常。
- 运行时异常,编译器不要求强制处理的异常。一般是指编程是的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。
- 对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
- 编译时异常,是编译器要求必须处理的异常。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KExWWk6V-1656837106714)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656317786102.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LoTeuNTe-1656837106715)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656317536664.png)]
常见的异常
运行异常
- NullPointerException空指针异常
当应用程序试图在需要对象的地方使用 null 时, 抛出该异常。 - ArithmeticException数学运算异常
当出现异常的运算条件时,抛出此异常。
例如:一个整数“除以零”时,抛出此类的一个实例 - ArraylndexOutOfBoudsException数组下标越界异常
用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引 - ClassCastException类型转换异常
当试图将对象强制转换为不是实例的子类时,抛出该异常。 - NumberFormatException数组格式不正确异常
当应用程序试图将字符串转换成一种数值类型,当该字符串不能转换为适当格式时,抛出该异常 => 使用异常我们可以确保输入是满足条件数字。
编译异常
编译异常 是指在编译期间,就必须处理的异常,否则代码不能通过编译。
SQLException //操作数据库时,查询表可能发生异常
IOException //操作文件时,发生的异常
FIleNotFoundException //当操作一个不存在的文件时,发生异常
ClassNotFoundException //加载类,而该类不存在时,异常
EoFException // 操作文件,到文件末尾,发生异常
IllegelArguementException //参数异常
异常处理(!!!)
基本介绍
异常处理就是当异常发生时,对异常处理的方式。
异常处理的方式
try-catch-finally
程序员在代码中捕获发生的异常,自行处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YPo5T9yy-1656837106716)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656330806020.png)]
注意事项
- 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块。
- 如果异常没有发生,则顺序执行try的代码块,不会进入catch。
- 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)
则使用如下代码 - finally{} - 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,不如(Exception 在后, NullPointerException 在前),如果发生异常,只会匹配一个catch。
- 可以进行 try—finally 配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
执行顺序
- 如果没有出现异常,则执行try块中所有语句,不执行catch块中语句,如果有finally,最后还需要执行finally里的语句
- 如果出现异常,则try块中异常发生后,try块剩下的语句不在执行。将执行catch块中的语句,如果有finally,最后还需要执行finally里面的语句!
练习
如果用户输入的不是一个整数,就提示它反复输入,直到输入一个整数为止
import java.util.Scanner;
/**
* @author 张正杰
* @version 1.0
*/
public class Main {
public static void main(String[] args) {
//1.创建Scanner对象
//2.使用无限循环,去接收一个输入
//3.然后将该输入的值,转成一个int
//4.如果在转换时,抛出异常,说明输入的内容不是一个可以转成int的内容
//5.如果没有抛出异常,则break 该循环
Scanner scanner = new Scanner(System.in);
int num = 0;
String inputStr = "";
while (true) {
System.out.println("请输入一个整数:");
inputStr = scanner.next();
try {
num = Integer.parseInt(inputStr);
break;
} catch (NumberFormatException e) {
System.out.println("你输入的不是一个整数:");
}
}
System.out.println("你输入的是:" + num);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SU50XWeD-1656837106716)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656393646350.png)]
throws
将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM:直接输出异常信息,退出程序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ps6y236t-1656837106717)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656395662846.png)]
基本介绍
- 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地生命抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
- 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
使用细节
- 对于编译异常,程序中必须处理,比如 try-catch 或者 throws
- 对于运行时异常,程序中如果没有处理,默认就是throws的方法处理
- 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型
- 在throws过程中,如果有方法 try-catch ,就相当于处理异常,就可以不必throws
自定义异常
基本介绍
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
步骤
- 定义类:自定义异常类名(程序员自己写)继承Exception或RuntimeException
- 如果继承Exception,属于编译异常
- 如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)
package com.zzj.Customexception_;
/**
* @author 张正杰
* @version 1.0
*/
public class CustomExeption {
public static void main(String[] args) {
int age = 1;
//要求范围在 18 - 120 之间, 否则抛出一个自定义异常
if (!(age >= 18 && age <= 120)) {
//通过构造器,来设置错误信息
throw new AgeException("年龄需要在 18 ~ 120之间");
}
System.out.println("你的年龄范围正确");
}
}
//自定义异常
class AgeException extends RuntimeException {
public AgeException(String message) {//构造器
super(message);
}
}
throw 和 throws 的对比
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQJmjZZo-1656837106718)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656398398276.png)]
练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4I69oBgY-1656837106718)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656398733309.png)]
包装类
分类
- 针对八种基本数据类型相应的引用类型-包装类
- 有了类的特点,就可以调用类中的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zNp1MVhJ-1656837106719)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656401172176.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fLMSxYWD-1656837106719)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656401756273.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mFarQ69o-1656837106720)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656401912001.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gzdQI0lc-1656837106720)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656401954700.png)]
包装类和基本数据的转换
- jak5 前的手动装箱和拆箱方式 装箱: 基本类型 -> 包装类型 ,反之,拆箱
- jdk5 之后(含jdk5)的自动装箱和拆箱方式
- 自动装箱底层调用的是valueOf方法,比如Interger.valueOf()
//手动装箱
int n1 = 100;
Integer integer = new Integer(n1);
Integer integer1 = Integer.valueOf(n1);
//手动拆箱
int i = integer.intValue();
//jdk5后, 就可以自动装箱和自动拆箱
int n2 = 200;
Integer integer2 = n2; //底层使用的是Integer.valueOf(n2)
//自动拆箱
int n3 = integer2; //底层使用的是intValue()方法
小练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydUnH6K9-1656837106720)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656403069674.png)]
包装类型和String类型相互转换
//包装类(Integer)->String
Integer i = 100; //自动装箱
//方式1
String str1 = i + "";
//方式2
String str2 = i.toString();
//方式3
String str3 = String.valueOf(i);
//String -> 包装类(Intrger)
String str4 = "12345";
Integer i2 = Integer.parseInt(str4);//使用到自动装箱
Integer i3 = new Integer(str4); //构造器
Integer类 和 Character类的常用方法
System.out.println(Integer.MIN_VALUE); //返回最小值
System.out.println(Integer.MAX_VALUE); //返回最大值
System.out.println(Character.isDigit('a')); //判断是不是数字
System.out.println(Character.isLetter('a')); //判断是不是字母
System.out.println(Character.isUpperCase('a')); //判断是不是大写
System.out.println(Character.isLowerCase('a')); //判断是不是小写
System.out.println(Character.isWhitespace('a')); //判断是不是空格
System.out.println(Character.toUpperCase('a')); //转成大写
System.out.println(Character.toLowerCase('A')); //转成小写
练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WuBwNAxh-1656837106721)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656480736565.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BaSRyUzG-1656837106721)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656481779740.png)]
String类
- String对象用于保存字符串,也就是一组字符序列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qyp7fYmj-1656837106722)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656482420220.png)] - 字符串常量对象时用双引号括起来的字符序列
- 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。
- String类较常用构造器(其他看手册):
String s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[] a);
String s4 = new String(char[] a, int startlndex, int count);
String s5 = new String(byte[] b); - String类 实现了接口 Serializable【string 可以串行化:可以在网络传输】
接口 Comparable 【String 对象可以比较大小】 - String 是final类, 不能被其他的类继承
- String 有属性 private final char value[] ; 用于存放字符串内容
- 一定要注意:value 是一个 final类型,不可修改(需要功力):即value不能指向新的地址,但是单个字符内容是可以变化
创建的两种方式
方式一:直接赋值String s = “zzj”;
方式二:调用构造器 String s = new String(“zzj”);
- 方式一:先从常量池查看是否有“zzj”数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址
- 方式二:先从堆中创建空间,里面维护了value属性,指向常量池的zzj空间。
如果常量池没有“zzj”, 重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。 - 画出两种方式的内存分布图
练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-467JqGyr-1656837106723)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656486661838.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bp53y7Gl-1656837106724)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656488397534.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sl6zkOI9-1656837106725)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656489810793.png)]
常用方法
String类 是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此java设计者提供了StringBuilder 和 StringBuffer 来增强String的功能,并提高效率。
- equals //区分大小写 , 判断内容是否相等
- equalslgnoreCase //忽略大小写的判断内容是否相等
- length //获取字符的个数,字符串的长度
- indexOf //获取字符在字符串中第一次出现的索引,索引从0开始,如找不到,返回-1
- lastlndexof //获取字符在字符串中第一次出现的索引,索引从0开始,如找不到,返回-1
- substring //截取指定范围的字串
- trim //去前后空格
- charAt:获取某索引处的字符,注意不能使用Str[index]这种方式。
- toUpperCase //转换大写
- toLowerCase //转换小写
- concat //拼接字符串
- replace //替换字符串中的字符
- split //分割字符串,对于某些分割字符,我们需要转义比如 | \\等
- toCharArray //转换成字符数组
StringBuffer类
基本介绍
java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。
很多方法与String相同,但StringBuffer是可变长度的。
StringBuffer是一个容器。
- StringBuffer 的直接父类 是 AbstractStringBuilder
- StringBuffer 实现了 Serializable, 即StringBuffer的对象可以串行化
- 在父类中 AbstractStringBuilder 有属性 char[] value, 不是 final 该 value 数组存放 字符串内容, 引出存放在堆中的
- StringBuffer 是一个 final类, 不能被继承
- 因为 StringBuffer 字符内容是存在 char[] value ,所有在变化(增加/删除)不用每次都更换(即创建新对象)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UjXNfckW-1656837106726)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656831741729.png)]
String VS StringBuffer
- String 保存的是字符串常量, 里面的值不能更改, 每次String类的更新实际上就是更改的值,效率较低 //private final char value[];
- StringBuffer 保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率较高 //char[] value; //这个放在堆。
StringBuffer的构造器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZECEgf3f-1656837106727)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656656852375.png)]
String 和 StringBuffer 转换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nMzTIWQg-1656837106728)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656657534059.png)]
StringBuffer类常见方法
- 增 append
- 删 delete(start,end)
- 改 replace(start,end,string) //将start----end 间的内容替换掉,不含end
- 查 indexOf //查找字串在字符串地1次出现的索引,如果找不到返回-1次出现的索引,如果找不到返回-1
- 插 insert
- 获取长度 length
练习
package com.zzj.stringbuffer;
import java.util.Scanner;
/**
* @author 张正杰
* @version 1.0
*/
public class StringBufferExercise02 {
public static void main(String[] args) {
/*
1.定义一个Scanner对象,接收用户输入的价格(String)
2.希望使用到 StringBuffer的 insert,需要将String 转成 StringBuffer
3.然后使用相关方法进行字符串的处理
*/
Scanner scanner = new Scanner(System.in);
System.out.print("请输入你的工资:");
String price = scanner.next();
StringBuffer sb = new StringBuffer(price);
//找到小数点的索引,然后该位置的前3位,插入,即可
for (int i = sb.lastIndexOf(".") - 3; i > 0; i -= 3) {
sb = sb.insert(i , ",");
}
System.out.println(sb);
}
}
StringBuilder类
基本介绍
- 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API , 但不保证同步(StringBuilder 不是线程安全)。 该类被设计用作 StringBuffer 的一个建议替换, 用于字符串缓冲区被单一线程使用的时候,如果可能,建议采用该类,因为大多现实中,他比StringBuffer要快。
- 在StringBuilder 上的主要操作是 append 和 insert 方法, 可重载这些方法,一接受任意类型的数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KxJgqBWo-1656837106729)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656831764157.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iggGpBH8-1656837106730)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656832104733.png)]
String StringBuffer StringBuilder 的比较
- StringBuffer 和 StringBuilder 非常相似,均代表可变的字符序列,而且方法也一样
- string: 不可变字符序列,效率低,但是复用率高。
- StringBuffer: 可变字符序列,效率较高(增删),线程安全
- StringBuilder:可变字符序列,效率最高,线程不安全
- String使用注意说明:
String s = “a”; //创建了一个字符串
s += “b”; //实际上原来的“a”字符串对象已经丢弃了,现在又产生了一个字符串s + ”b“;(也就是”ab“)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能 => 结论 : 如果我们对string 做大量修改,不要使用String。
结论
- 如果字符串大量的修改操作,一般使用 StringBuffer 或 StringBuilder
- 如果字符串大量的修改操作,并在单线程的情况,使用 StringBuilder
- 如果字符串大量的修改操作,并在多线程的情况,使用StringBuffer
- 如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等
Math类
基本介绍
Math类 包含用于执行基本数学运算的方法,如初等指数,对数,平方根和三角函数。
常用方法
- abs 绝对值
- pow 求幂
- ceil 向上取整
- floor 向下取整
- round 四舍五入
- sqrt 求开方
- random 求随机数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DLaBBS1f-1656837106731)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656836269277.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZlRy9Jb3-1656837106731)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1656836337497.png)] - max 求两个数的最大值
- min 求两个数的最小值
Arrays类
常见方法应用案例
Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)
- toString返回数组的字符串形式
Arrays.toString(arr)
- sort排序 (自然排序和定制排序)
Integer arr[] = {1,-1,7,0,89}; - binarySearch 通过二分搜索法进行查找,要求必须排好序
int index = Arrays.binarySearch(arr,3); - copyOf 数组元素的赋值
Integer[] newArr = Arrays.copyOf(arr,arr.length); - fill数组元素的填充
Integer[] num = new Integer[]{9,3,2};
Arrays.fill(num,99); - equals 比较两个数组元素内容是否完全一致
boolean equals = Arrays.equals(arr,arr2); - asList 将一组值,转换成list
List asList = Arrays.asList(2,3,4,5,6,1);
删),线程安全
- StringBuilder:可变字符序列,效率最高,线程不安全
- String使用注意说明:
String s = “a”; //创建了一个字符串
s += “b”; //实际上原来的“a”字符串对象已经丢弃了,现在又产生了一个字符串s + ”b“;(也就是”ab“)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能 => 结论 : 如果我们对string 做大量修改,不要使用String。
结论
- 如果字符串大量的修改操作,一般使用 StringBuffer 或 StringBuilder
- 如果字符串大量的修改操作,并在单线程的情况,使用 StringBuilder
- 如果字符串大量的修改操作,并在多线程的情况,使用StringBuffer
- 如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等
Math类
基本介绍
Math类 包含用于执行基本数学运算的方法,如初等指数,对数,平方根和三角函数。
常用方法
- abs 绝对值
- pow 求幂
- ceil 向上取整
- floor 向下取整
- round 四舍五入
- sqrt 求开方
- random 求随机数
[外链图片转存中…(img-DLaBBS1f-1656837106731)]
[外链图片转存中…(img-ZlRy9Jb3-1656837106731)] - max 求两个数的最大值
- min 求两个数的最小值
Arrays类
常见方法应用案例
Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)
- toString返回数组的字符串形式
Arrays.toString(arr)
- sort排序 (自然排序和定制排序)
Integer arr[] = {1,-1,7,0,89}; - binarySearch 通过二分搜索法进行查找,要求必须排好序
int index = Arrays.binarySearch(arr,3); - copyOf 数组元素的赋值
Integer[] newArr = Arrays.copyOf(arr,arr.length); - fill数组元素的填充
Integer[] num = new Integer[]{9,3,2};
Arrays.fill(num,99); - equals 比较两个数组元素内容是否完全一致
boolean equals = Arrays.equals(arr,arr2); - asList 将一组值,转换成list
List asList = Arrays.asList(2,3,4,5,6,1);
System.out.println(“asList=” + asList);