⭐️大一小何,还在学习当中,欢迎交流指正~
目录
内部类
内部类的种类
成员内部类
局部内部类
静态内部类
匿名内部类
成员内部类注意事项
向上转型&向下转型
一,向上转型
二,向下转型
异常处理(important)
Error
Exception
运行时异常
编译时异常
异常处理
异常处理机制一
异常处理机制二
两种机制的选择
自定义异常类
结语
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
Inner class的名字不能与包含它的外部类类名相同;
分类:成员内部类(static成员内部类和非static成员内部类)
局部内部类(不谈修饰符)、匿名内部类
public class Outter {
String s;
class Inner{
}
}
局部内部类是定义在一个方法或者一个作用域里的类。Inner2和Inner都是Outter的内部类。
public class Outter {
public Inner getInner2(){
class Inner2 extends Inner{
String s = "Inner2";
}
return new Inner2();
}
}
class Inner{
String s;
}
其实,就是成员内部类前面加了static。声明为static的类不会持有外部类的引用,可以通过软引用的方式保存外部类的了引用,只有静态内部类不可能造成内存泄漏。
public class Outter {
String s;
static class Inner{
}
}
容易维护,但不常用
public class Outter {
void test() {
new Thread(new Runnable(){
String S;
@Override
public void run(){}
}).start();
}
}
注意
//非静态成员内部类
class Bird{
string name;
public Bird(){
}
public void sing(){
System.out.println("我是一只小小鸟");
Person.this.eat();//调用外部类的非静态属性
}
}
成员内部类:
一,作为外部类的成员:
调用外部类的结构
可以被static修饰
可以被4种不同的权限修饰
二,作为一个类;
类内可以定义属性、方法、构造器等
可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
可以被abstract修饰
在局部内部类的方法中(比如: show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:要求此局部变量声明为final的。
public void method(){
//局部变量
int num = 10;
class AA{
public void show(){
num =20;//哒咩!
System.out.print1n(num);
}
向上转型可以被理解为将子类类型的对象转换为父类类型的对象,即把子类类型的对象直接赋值给父类类型的对象,进而实现按照父类描述子类的效果
举个栗子
class People{}
class Teacher extends People{}
public class Demo3{
public static void main(String[] args){
people tom = new Teacher();
}
}
“People tom = new Techer()”运用了向上转型的语法
(这里我自己画了一个图方便理解)
综上所述,因为人类(People)是教师的父类,所以通过向上转型,能够吧教师类(Teacher)类型的对象(new Teacher();)直接赋值给人类(People)类型的变量(tom)。
也就是说向上转型父类类型的对象可以直接引用子类类型的对象。而且,向上转型是安全的,因为向上转型是将一个较具体的类的对象转换成一个较抽象类的对象。
错误❌(父类的对象无法调用子类独有的属性或者方法)
class Quadrangle{//四边形类
}
public class Parallelogram extends Quadrangle{//平行四边形类,继承了四边形类
int edges = 4;//底边的长度为4
public static void main (String[] args){
Quadrangle p = new Parallelogram();
p.edges = 6;//四边形类,类型的对象p调用变量edges,并将edges的值修改为6
}
}
向上转型可以被理解为将父类类型的对象转换为父类类型的对象
但是,运用向下转型,如果把一个较抽象类的对象转化为一个较具体类的对象,这样的转型通常会出现错误。比如,可以说某只鸽子是一只鸟,不能说某只鸟是一只鸽子。因为鸽子是具体的,鸟是抽象的,一只鸟除了是一只鸽子外,还可能是麻雀,燕子and so on~
所以,向下转型是不安全的!
举个栗子
package com.Test.java;
public class chuxi {
public static void main(String[] args) {
Bird bird = new Pigeon();//某只鸽子是一只鸟
Pigeon pigeon = bird;//某只鸟是一只鸽子 这是哒咩的 会报错
}
class Bird{}
class Pigeon extends Bird {}
}
↓
父类对象不能直接赋值给子类对象
if 想要告诉编译器“某只鸟就是一只鸽子”,应该强制类型转换,也就是说,想要实现向下转型,我们需要借助强制类型转换
语法如下
子类类型 子类对象 = (子类类型)父类类型;
Pigeon pigeon = (Pigeon)bird //通过强制类型转换,告诉编译器 某只鸟就是一只鸽子
***********************************************************************
注意:两个没有继承关系的对象不可以进行向上转型或者向下转型
父类对象可以强制转换为子类对象,but有一个前提就是,这个父类对象要先引用这个子类对象
Bird bird = new Pigeon();//某只鸽子是一只鸟
Pigeon pigeon = (Pigeon )bird;//通过强转,实现“某只鸟是一只鸽子”
Error:Java虚拟机无法解决的严重问题,如 jvm系统内部错误,资源耗尽等严重情况,like StakOverflowError,一般不编写针对性的代码进行处理
Error:
public class ErrorTest {
public static void main( String[]args)i
//1.栈溢出:java. lang.StackOverflowError
main(args);
//2.堆溢出:java.lang.outofMemoryError
Integer[]arr = new Integer[ 1024*1024*1024];
}
}
Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
空指针访问
试图读取不存在的文件网络连接中断
数组角标越界
对于这些错误,一般有两种解决方法:一是遇到错误就终止程序的运行。另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。
java.lang.Throwable
java.lang.Error:一般不编写针对性的代码进行处理。java.lang.Exception :可以进行异常的处理
编译时异常(checked)
IOException
FileNotFoundExceptionlClassNotFoundException
l运行时异常(unchecked)
NullPointerException
ArrayIndexoutOfBoundsException--ClassCastException
NumberFormatExceptionInputMismatchException
ArithmeticException
举几个例子
空指针异常
package com.happy.demo;
public class yichangTest {
//NullPointerExceotion
public void test1() {
int[] arr = null;
System.out.println(arr[3]);
}
}
角标越界
//数组下标越界
String[] str1 = new String[10];
System.out.println(Str1[10]);
//字符串下标越界
String str2 = "abc";
System.out.println(str2.charAt(3));
NumberFormatException
String str = "123";
str = "abc";// 哒咩 不是一个数据类型的
int num = Integer.parseInt(str);
public void test7(){
File file = new File( "he1lo.txt");
FileInputStream fis = new.Ei.leInputStneam(file);
int data = fi.s..nead();
while(data != -1)i
system. out. print( (char)data);
data =fi.s.read();
}
fis.close();
}
在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行xly运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。
Java异常处理
Java采用的异常处理机制,是将异常处理的程序代码集中在一起与正常的程序代码分开,使得程序简洁、优雅,并易于维护。
Java当中提供的是异常处理的抓抛模型
过程一:抛
程序在正常执行的过程中,一旦出现异常,就会在异常代码处对应异常类的对象,并将此对象抛出;一旦抛出对象以后,其后的代码不再执行
关于异常对象的产生
1.系统自动生成的异常对象
2.手动的生成一个异常对象,并抛出(throw)
过程二:抓
可以理解为异常的处理方式: try catch finally / throws+异常类型
try catch finally的使用
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式一
}catch(异常类型2 变量名2){
//处理异常的方式二
}catch(异常类型3 变量名3){
//处理异常的方式三
}
...
finally{
//一定会执行的代码
}
public void test1() {
String str = "123";
str = "abc";
try {
int num = Integer.parseInt(str);
System.out.println("出现数值转换异常了");
}catch(NumberFormatException e) {
System.out.println("666");
}
System.out.println("888");
}
输出:
出现数值转换异常了
888
说明:
1.finally是可选的
2.使用try将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中去匹配
3。一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常处理,一旦处理完成,就跳出当前的try—catch结构(在没有写finally的情况下),继续执行其后的代码
4.catch中的异常类型如果没有子父类的关系,则谁声明在上,谁声明在下无所谓
catch中的异常类型如果满足子父类的关系,则要求子类一定声明在父类上面,否则报错
5.常用的异常处理方式
5.1 String getMessage
5.2 printStackTrace()
6.在try结构中声明的变量,在出了try结构以后,就不能再被调用(这种情况下,可以把变量声明在try外部,先初始化,就可以在被调用了)
7.try-catch-finally的使用可以嵌套
使用try-catch-finally处理编译时异常,是得程序在编译时就不报错,但是运行时仍可能报错,相当于我们用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现
开发中,由于运行时异常比较常见,所以通常不针对运行时异常编写try-catch-finally了,针对于编译时异常,我们一定要考虑异常的处理
finally中声明的是一定会被执行的语句,即使catch中又出现异常了(catch中出现异常直接跳出catch语句),try中有return语句,catch中有return语句等情况
public void test1() {
Public void test() {
try {
int a = 10;
int b = 0;
System.out.println(a/b);
}catch(ArithmeticException e) {
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
}
//System.out.println("111");
finally {
System.out.println("222");输出222
}
}
}
public void test1() {
Public void test() {
try {
int[] arr = new int[10];
System.out.println(arr[10]);
return 1;
}catch(ArithmeticException e) {
e.printStackTrace();
return 2;
}
finally {
System.out.println("一定执行");
}
}
}
输出结果
一定执行
2
像数据库连接,输入输出流,网络编程Socket等资源,jvm是不能自动的回收的,我们需要自己动手进行资源的释放,就需要声明在finally当中
throws+异常类型
1,“throws+异常类型”写在方法的声明处,指明此方法执行时,可能会抛出的异常类型
一旦方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出,异常代码后续的代码,就不再执行
try-catch-finally:真正的将异常给处理掉了,throws的方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉
子类重写的规则之一
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
1,如果父类中被重写的方法没有throws方式处理异常,则子类被重写的方法也不能使用
throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理
2,执行的方法a中,先后又调用了另外的几种方法,这几个方法是递进关系执行的,建议使
用throws方式进行处理,而执行的方法a可以考虑使用try-catch-finally方式进行处理
1,继承于现有的异常结构,RuntimeException Exception
2.提供全局常量 serialVersionUID
3.提供重载的构造器
public class MyException extends RuntimeException{
static final long serialVersionUID = -7034897193246939L;
public MyException(){i
}
public MyException( String msg){
super( msg);
}
}
其实昨天就开始写了,但是效率不高,抢红包抢嗨了哈哈,写了好长时间哇咔咔
2022年第一篇,多多支持嘻嘻~
新年快乐呀呀呀~祝大家红包多多,好运连连,offer连连,开心每一天