1、内部类
1.1 内部类的分类
- 成员内部类(实例内部类)
- 静态内部类
- 局部内部类
- 匿名内部类
1.2 什么是内部类
概念:在一个类的内部再定义一个完整的类。
特点:
- 编译之后可生成独立的字节码文件。
- 内部类可直接访问外部类的私有成员,而不破坏封装。
- 可为外部类提供必要的内部功能组件。
1.3 成员内部类(实例内部类)
- 在类的内部定义,与实例变量、实例方法同级别的类。
- 外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。
Outer out = new Outer();
Outer.Inner in = out.new Inner();- 当外部类、内部类存在重名属性时,会优先访问内部类属性。
- 成员内部类不能定义静态成员。
案例演示:实例内部类使用。
package com.qf.pan.inner1;
//主方法
public class Demo01 {
public static void main(String[] args) {
//方法一:实例化外部类
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();
inner.i_id = 11;
System.out.println(inner.i_id);
inner.test();
Outter.Inner inner2 = new Outter().new Inner();
//方法二:实例化外部类
Outter.Inner inner1 = new Outter().new Inner();
inner1.test();
}
}
外部类
package com.qf.pan.inner1;
//外部类
public class Outter {
//实例属性
public int id;
//实例化内部类
public class Inner{
public int i_id;
public void test(){
System.out.println("实例化内部类的方法");
}
}
}
1.4 静态内部类
- 不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
- 只能直接访问外部类的静态成员(实例成员需实例化外部类对象)。
Outer.Inner inner = new Outer.Inner();
Outer.Inner.show();
案例演示:静态内部类使用。
package com.qf.pan.inner2;
//静态内部类
public class Demo01 {
public static void main(String[] args) {
//调用静态属性
System.out.println(Outter.id);
//调用静态内部类的方法
Outter.Inner inner = new Outter.Inner();
inner.test();
}
}
class Outter{
public static int id;
//静态内部类
static class Inner{
public void test(){
System.out.println("静态内部类");
}
}
}
1.5 局部内部类
- 定义在外部类方法中,作用范围和创建对象范围仅限于当前方法。
- 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final。
- 限制类的使用范围。
案例演示:局部内部类使用。
package com.qf.pan.inner3;
//局部内部类
public class Demo01 {
public static void main(String[] args) {
Outter outter = new Outter();
//局部属性外界无法调用
//outter.test1().id;
outter.test2();
}
}
class Outter{
public void test1(){
//局部属性 -- 不存在访问修饰符
int id = 1;
System.out.println(id);
}
public void test2(){
//局部内部类 -- 作用域只在当前方法中
class Inner{
public void test(){
System.out.println("局部内部类");
}
}
Inner inner = new Inner();
inner.test();
}
}
1.6 匿名内部类
- 没有类名的局部内部类(一切特征都与局部内部类相同)。
- 必须继承一个父类或者实现一个接口。
- 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
- 优点:减少代码量。
- 缺点:可读性较差。
案例演示:匿名内部类使用。
package com.qf.pan.inner4;
//匿名内部类
//主方法
public class Demo01 {
public static void main(String[] args) {
//使用多态的方式
IInner inner = new Test();
inner.inner();
//使用匿名内部类的方式 -- 减少类的数量,当方法只使用一次的时候则可以使用匿名内部类
IInner2 inner2 = new IInner2() {
@Override
public void inner() {
System.out.println("匿名内部类");
}
};
inner2.inner();
}
}
接口IInner
package com.qf.pan.inner4;
public interface IInner {
void inner();
}
接口
package com.qf.pan.inner4;
public interface IInner2 {
void inner();
}
类Test
package com.qf.pan.inner4;
public class Test implements IInner{
@Override
public void inner() {
System.out.println("使用多态的方式");
}
}
2、接口回调
package com.qf.pan.inner5;/*
* @author pyh
* @date 2020/11/30 0030 上午 10:46
* @version 1.0
* @since JDK1.8_241
接口回调
*/
import com.qf.pan.utils.TimeUtils;
public class Demo1 {
public static void main(String[] args) {
//返回当前时间 -- 以毫秒为单位
/*long time1 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
for (int j = 0; j < 100000; j++) {
for (int k = 0; k < 10000; k++) {
}
}
}
long time2 = System.currentTimeMillis();
System.out.println(time2-time1);*/
//直接传递对象的方式
//Test test = new Test();
//TimeUtils.testTime(test);
//使用匿名内部类的方式
/*ITest test = new ITest(){
@Override
public void test() {
for (int i = 0; i < 100000; i++) {
for (int j = 0; j < 100000; j++) {
for (int k = 0; k < 10000; k++) {
}
}
}
}
};
TimeUtils.testTime(test);*/
//接口回调
TimeUtils.testTime(new ITest() {//new ITest()相当于直接在这里重写Test的类
@Override
public void test() {
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
for (int k = 0; k < 10000; k++) {
}
}
}
}
});
}
}
接口ITest
package com.qf.pan.inner5;
public interface ITest {
void test();
}
类Test
package com.qf.pan.inner5;/*
* @author pyh
* @date 2020/11/30 0030 上午 10:49
* @version 1.0
* @since JDK1.8_241
*/
public class Test {
public void test(){
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
for (int k = 0; k < 10000; k++) {
}
}
}
}
}
工具类TimeUtils,在另一个包utils下写
package com.qf.pan.utils;/*
* @author pyh
* @date 2020/11/30 0030 上午 10:48
* @version 1.0
* @since JDK1.8_241
*/
import com.qf.pan.inner5.ITest;
//工具类TimeUtils
public class TimeUtils {
public static void testTime(ITest test){//ITest test 调用接口ITest的方法
long time1 = System.currentTimeMillis();
//调用需要测试的方法
test.test();
long time2 = System.currentTimeMillis();
System.out.println("程序运行所用的时间:"+(time2-time1));
}
public static void testTime2(ITest test){
long time3 = System.currentTimeMillis();
test.test();
long time4 = System.currentTimeMillis();
System.out.println("程序运行所用的时间:"+(time4-time3));
}
}
3、异常
3.1 概念
异常:程序在运行过程中出现的特殊情况。
3.2 异常的必要性
任何程序都可能存在大量的未知问题、错误。
如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
3.3异常分类
Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。
3.3.1 错误
- Error: JVM、硬件、执行逻辑错误,不能手动处理。
- 常见错误: StackOverflowError、 OutOfMemoryError等。
3.3.2 异常
- Exception:程序在运行和配置中产生的问题,可处理。
- RuntimeException:运行时异常,可处理,可不处理。
- CheckedException:检查时异常,必须处理。
常见运行时异常:
异常 | 描述 |
---|---|
NullPointerException | 空指针异常 |
ArrayIndexOutOfBoundsException | 数组越界异常 |
ClassCastException | 类型转换异常 |
NumberFormatException | 数字格式化异常 |
ArithmeticException | 算术异常 |
public class Demo1 {
public static void main(String[] args) {
//常见运行时异常
//1NullPointerException
String name=null;
System.out.println(name.equals("zhangsan"));
//2ArrayIndexOutOfBoundsException
int[] arr= {10,30,50};
System.out.println(arr[3]);
//3ClassCastException
Object str="hello";
Integer i=(Integer)str;
//4NumberFormatException
int n=Integer.parseInt("100a");
System.out.println(n);
//5ArithmeticExceptioin
int n=10/0;
System.out.println(n);
try {
FileInputStream fis=new FileInputStream("d:\\hell.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.4异常产生和传递
3.4.1 异常产生
- 自动抛出异常:当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
- 手动抛出异常:语法:throw new 异常类型(“实际参数”)。
- 产生异常结果:相当于遇到 return语句,导致程序因异常而终止。
3.4.2 异常传递
- 异常的传递:
- 按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。
- 受查异常:throws 声明异常,修饰在方法参数列表后端。
- 运行时异常:因可处理可不处理,无需声明异常。
案例演示:异常的产生、传递。
/**
* 演示异常的产生和传递
* 要求:输入两个数字实现两个数字相除
*/
public class TestException1 {
public static void main(String[] args) {
operation();
}
public static void operation() {
System.out.println("---opration-----");
divide();
}
public static void divide() {
Scanner input=new Scanner(System.in);
System.out.println("请输入第一个数字");
int num1=input.nextInt();//出现异常,没有处理,程序中断
System.out.println("请输入第二个数字");
int num2=input.nextInt();
int result=num1/num2;//出现异常没有处理,所以程序中断
System.out.println("结果:"+result);
System.out.println("程序执行完毕了...");
}
}
3.5异常处理
Java的异常处理是通过5个关键字来实现的:
- try:执行可能产生异常的代码 。
- catch:捕获异常 ,并处理。
- finally:无论是否发生异常,代码总能执行。
- throw: 手动抛出异常 。
- throws:声明方法可能要抛出的各种异常。
3.5.1 try…catch…
语法:
try {
//可能出现异常的代码
} catch(Exception e) {
//异常处理的相关代码,如:getMessage()、printStackTrace()
}
public class TestException2 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int result=0;
try {
System.out.println("请输入第一个数字");
int num1=input.nextInt();//InputMismatchException
System.out.println("请输入第二个数字");
int num2=input.nextInt();
result=num1/num2;//发生异常// ArethmicException
}catch (Exception e) {//捕获 Exception:是所有异常的父类
//处理
//e.printStackTrace();
System.out.println(e.getMessage());
}
System.out.println("结果是:"+result);
System.out.println("程序结束了...");
}
}
3.5.2 try…catch…finally…
语法:
try {
//可能出现异常的代码
} catch(Exception e) { //异常处理的相关代码,如:getMessage()、printStackTrace()
} finally{
//是否发生异常都会执行,可以释放资源等。
}
public class TestException3 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int result=0;
try {
System.out.println("请输入第一个数字");
int num1=input.nextInt();//InputMismatchException
System.out.println("请输入第二个数字");
int num2=input.nextInt();
result=num1/num2;//发生异常// ArethmicException
//手动退出JVM
//System.exit(0);
}catch (Exception e) {//捕获 Exception:是所有异常的父类
//处理
//e.printStackTrace();
System.out.println(e.getMessage());
}finally {
System.out.println("释放资源...");
}
System.out.println("结果是:"+result);
System.out.println("程序结束了...");
}
}
注:1、finally块是否发生异常都执行,释放资源等 2、finally块不执行的唯一情况,退出java虚拟机。
3.5.3 多重catch
语法:
try{
//可能出现异常的代码。
}catch(异常类型1){
//满足异常类型1执行的相关代码。
}catch(异常类型2){
//满足异常类型2执行的相关代码。
}catch(异常类型3){
//满足异常类型3执行的相关代码
}
public class TestException4 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int result=0;
try {
// String string=null;
// System.out.println(string.equals("hello"));
System.out.println("请输入第一个数字");
int num1=input.nextInt();//InputMismatchException
System.out.println("请输入第二个数字");
int num2=input.nextInt();
result=num1/num2;//发生异常// ArethmicException
}catch (ArithmeticException e) {//捕获 Exception:是所有异常的父类
System.out.println("算术异常");
}catch (InputMismatchException e) {
System.out.println("输入不匹配异常");
}catch (Exception e) {
System.out.println("未知异常");
}
System.out.println("结果是:"+result);
System.out.println("程序结束了...");
}
}
3.5.4 try…finally…
- try…finally…不能捕获异常 ,仅仅用来当发生异常时,用来释放资源。
- 一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。
语法:
try{
//可能出现异常的代码
}finally{
//是否发生异常都会执行,可以释放资源等
}
public class TestException5 {
public static void main(String[] args) {//JVM
try {
divide();
}catch (Exception e) {
System.out.println("出现异常:"+e.getMessage());
}
}
public static void divide() {
Scanner input=new Scanner(System.in);
int result=0;
try {
System.out.println("请输入第一个数字");
int num1=input.nextInt();//InputMismatchException
System.out.println("请输入第二个数字");
int num2=input.nextInt();
result=num1/num2;//发生异常// ArethmicException
}finally {
System.out.println("释放资源");
}
System.out.println("结果是:"+result);
System.out.println("程序结束了...");
}
}
3.5.5 小结
- try{ } catch{ }
- try{ } catch{ } catch{ }
- try{ } catch{ } finally{ }
- try{ } catch{ } catch{ } finally{ }
- try{ } finally{ }
注:多重catch,遵循从子( 小 )到父( 大 )的顺序,父类异常在最后。
3.6 声明异常
- throws关键字:声明异常
public class TestException6 {
public static void main(String[] args){//JVM
try {
divide();
} catch (Exception e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println(e.getMessage());
}
}
public static void divide() throws Exception {
Scanner input=new Scanner(System.in);
System.out.println("请输入第一个数字");
int num1=input.nextInt();
System.out.println("请输入第二个数字");
int num2=input.nextInt();
int result=num1/num2;
System.out.println("结果:"+result);
}
}
3.7 抛出异常
除了系统自动抛出异常外,有些问题需要程序员自行抛出异常。
- throw关键字:抛出异常
public class Person {
private String name;
private String sex;
private int age;
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String name, String sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
if(sex.equals("男")||sex.equals("女")) {
this.sex = sex;
}else {
throw new RuntimeException("性别不符合要求");
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age>0&&age<=120) {
this.age = age;
}else {
//抛出异常
throw new RuntimeException("年龄不符合要求");
}
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
3.8 自定义异常
- 需继承Exception或Exception的子类,代表特定问题。
- 异常类型名称望文生义,可在发生特定问题时抛出对应的异常。
常用构造方法:
- 无参数构造方法。
- String message参数的构造方法。
public class AgeException extends RuntimeException{
public AgeException() {
super();
// TODO Auto-generated constructor stub
}
public AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public AgeException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public AgeException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public AgeException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
3.9 异常中方法覆盖
带有异常声明的方法重写:
- 方法名、参数列表、返回值类型必须和父类相同。
- 子类的访问修饰符合父类相同或是比父类更宽。
- 子类中的方法,不能抛出比父类更多、更宽的检查时异常。
public class Animal {
public void eat(){
System.out.println("父类吃方法..........");
}
}
子类Dog
public class Dog extends Animal{
@Override
public void eat() throw Exception{
//出现错误,父类没有声明异常,子类不能声明异常
System.out.println("子类的吃的方法..........");
}
}
3.10 自我总结
package com.qf.pan.exception1;/*
* @author pyh
* @date 2020/11/30 0030 上午 11:43
* @version 1.0
* @since JDK1.8_241
Error:错误
Exception:异常
1、一般异常(受检性异常),即在编写代码会有异常需要去处理
2、运行事异常(非受检性异常),即运行的时候会出现的异常
处理异常的方式:
1、抛出异常:throws
当出现异常,方法会终止运行
当不知道该怎么处理异常时,向上抛出给调用方,由调用方处理
2、捕获异常:try/catch
try {
可能会出现异常的代码
}catch (异常类型 异常对象) {
处理异常的方式
}
怎么用:当知道如何处理异常的时候使用try/catch,方法的运行不会被中断,继续执行
try块中出现异常,则不再执行try块中剩余的代码,直接结束try块的代码,执
行catch块中的代码
3、抛出(声明)异常对象:throw
更改异常说明信息,让异常定位更加准确
解决异常:了解异常的类型,明白异常出现的原因,寻找异常出现的位置
*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Demo1 { //throws FileNotFoundException 表示抛出异常
public static void main(String[] args) throws FileNotFoundException {
// ----------------一般异常(受检性异常)------------------
test();
/* try {
FileInputStream file = new FileInputStream("io.text");
}catch (FileNotFoundException e) {
e.printStackTrace();
}*/
// ----------------运行时异常(非受检性异常)------------------
//数组下标越界异常 -- ArrayIndexOutOfBoundsException
//int nums[] = {11,22,23};
//print(nums);
//空指针异常 -- NullPointerException
//String str = null;
//不会报空指针异常
//System.out.println("".equals(str));
//报空指针异常
//System.out.println(str.equals(""));
//类型转换异常 -- ClassCastException
// Animal animal = new Animal();
// Dog dog = (Dog)animal;
//数字转换异常 -- NumberFormatException
// String str = "abc";
// int num = Integer.parseInt(str);
// System.out.println(num);
//算术异常 -- ArithmeticException
// int num1 = 1;
// int num2 = 0;
// int num3 = num1/num2;
}
public static void print(int[] nums){
System.out.println(nums[3]);
}
public static void test() throws FileNotFoundException {
System.out.println("异常开始");
FileInputStream file = new FileInputStream("io.text");
System.out.println("异常结束");
}
}
class Animal{
}
class Dog extends Animal{
}
捕获异常
package com.qf.pan.exception2;/*
* @author pyh
* @date 2020/11/30 0030 下午 4:43
* @version 1.0
* @since JDK1.8_241
捕获异常
*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Test01 {
public static void main(String[] args) {
int num = test();
System.out.println("num:"+num);
}
public static int test(){
try {
return 1;
}finally {
return 11;
}
}
//try/catch后面接finally,finally则一定会执行
/* public static void main(String[] args) {
System.out.println("异常开始");
int num = 0;
try {
int[] nums = {1,2,3};
//会报ArrayIndexOutOfBoundsException
System.out.println(nums[3]);
System.out.println("a");
//会报FileNotFoundException
FileInputStream fis = new FileInputStream("io.txt");
System.out.println("b");
} catch (Exception e) {
//e.printStackTrace();
//手动提示语句
System.out.println("小老弟,出异常啦,赶紧找你老大");
//一定执行的代码
}finally {
num = 11;
}
System.out.println("异常结束");
System.out.println("num:"+num);
}*/
//一个try块多个异常,一个catch处理所有的异常
/* public static void main(String[] args) {
System.out.println("异常开始");
try {
int[] nums = {1,2,3};
//会报ArrayIndexOutOfBoundsException
System.out.println(nums[3]);
System.out.println("a");
//会报FileNotFoundException
FileInputStream fis = new FileInputStream("io.txt");
System.out.println("b");
} catch (Exception e) {
//e.printStackTrace();
//手动提示语句
System.out.println("小老弟,出异常啦,赶紧找你老大");
}
System.out.println("异常结束");
}*/
//一个try块中有多个异常,一个catch块可以处理多个异常,用|分隔开
/* public static void main(String[] args) {
System.out.println("异常开始");
try{
int[] num = {11,23,30};
System.out.println(num[3]);//数组下标越界异常
System.out.println("a");
FileInputStream fis = new FileInputStream("io.txt");
}catch (FileNotFoundException | ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
//自己手动写提示语句
System.out.println("文件不存在,请先创建文件");
}
System.out.println("异常结束");
}*/
//一个try可以捕获多个异常,多个catch分别进行处理
/* public static void main(String[] args) {
System.out.println("异常开始");
try{
int[] num = {11,23,30};
System.out.println(num[3]);//数组下标越界异常
System.out.println("a");
FileInputStream fis = new FileInputStream("io.txt");
}catch (FileNotFoundException e) {
e.printStackTrace();
//自己手动写提示语句
System.out.println("文件不存在,请先创建文件");
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
System.out.println("异常结束");
}*/
}
自定义异常类
package com.qf.pan.exception2;
//自定义异常类
import java.io.FileNotFoundException;
public class FileException extends FileNotFoundException {
public FileException(String str){
//调用父类的构造方法
super(str);
}
}
抛出异常对象
package com.qf.pan.exception2;
//抛出异常对象
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Test02 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("io.txt");
} catch (FileNotFoundException e) {
try {
throw new FileNotFoundException("com.qf.ran.exception2的Demo02的第15代码出错了");
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
/*
自定义异常
try {
throw new FileException("io.txt文件还没创建");
} catch (FileException e1) {
e1.printStackTrace();
}*/
}
}
}