Java基础知识——异常 反射 内部类 序列化 泛型,String继承,多态,Object,抽象,数据,Collection,JDBC,代理,接口的静态和默认方法,this和super,复制,1.8

异常

在这里插入图片描述
参考资料
Error【非检查异常】:是指 java 运行时系统的内部错误和资源耗尽错误。应用程序不会抛出该类对象。如果出现了这样的错误,除了告知用户,剩下的就是尽力使程序安全的终止。(内存溢出,系统崩溃)
RuntimeException【非检查异常】:用空指针,越界(运行时报错)
非RuntimeException【检查异常】:试图文件尾部读取数据,试图打开错误的url(编译时报错)

自定义异常:
非RuntimeException: 自定义类 并继承于java.lang.Exception。
RuntimeException:自定义类 并继承于java.lang.RuntimeException。

注意:
对于非RuntimeException,如果需要throw,需要在方法申明时加上该异常的抛出(即需要加上 throws 语句)或者在方法体内 try-catch 处理该异常,否则编译报错
对于RuntimeException:可以直接throw,由JVM进行处理

抛出异常:
系统自动抛异常的本质就是throw
对于检查异常,系统编译时报错
对于非检查异常,运行时有JVM处理
1:越界,throw new ArrayIndexOutOfBoundsException
2:是否有try-catch。如果有则给catch,如果没有则直接抛给虚拟机JVM
在这里插入图片描述

在这里插入图片描述
位置不同:
throws 用在函数上,后面跟的是异常类,可以跟多个;而 throw 用在函数内,后面跟的是异常对象。
功能不同:
1:throws 用来声明异常,让调用者只知道该功能可能出现的问题,可以给出预先的处理方式;throw 抛出具体的问题对象,执行到 throw,功能就已经结束了,一定抛出异常
2:两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常这里我理解为throw直接抛出异常程序结束,而throws必须由try-catch实现才能做到处理异常

try catch finally
如果try,catch中有return,那么会将return的值缓存起来,等try catch finally全部执行完后再返回缓存值。所以
如果finally中无return语句,finally的操作不会影响之前return的值,因为已经缓存。
如果finally块中有return 语句,则try或catch中的返回语句忽略,此时finally的操作生效。
参考资料

反射

参考资料
反射的意义:
1:半动态性在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法并且对于任意一个对象,都能够调用它的任意一个方法,包括私有的变量
2:对RTTI来说,时打开和检查.class文件。对于反射机制来说,.class文件在编译时是不可获取的,所以在运行时打开和检查.class文件
所以说可以动态的修改代码
例子:
一个项目,Mysql数据库宕掉,改用Oracle
RTTI:停止服务器,修改源代码,将Mysql驱动改为Oracle驱动,重新编译运行,再放到服务器上
反射:修改配置文件就可以动态加载这个类,Class.forName()生成的结果在编译时是不可知的,只有在运行的时候才能加载这个类,换句话说,此时我们是不需要将程序停下来,只需要修改配置文件里面的信息就可以
这句话我的理解为,配置文件一般是解释性文件,修改后可以直接运行并且不会影响源代码各个框架也正是运用这一点Spring
3:通过反射越过泛型检查。即对List< String>能够add(Integer)
ArrayList strList = new ArrayList<>();
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod(“add”, Object.class);
//调用add()方法
m.invoke(strList, 100);
原理是泛型只在编译的时候检查,而在字节码文件中是擦除泛型的

Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
Method 类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
Constructor 类: Java.lang.reflec 包中的类,表示类的构造方法

获取class对象的方法:
1:调用某个对象的 getClass()方法
Person p=new Person();
Class clazz=p.getClass();
2:调用某个类的 class 属性来获取该类对应的 Class 对象
Class clazz=Person.class;注意Person为类名
3:使用 Class 类中的 forName()静态方法(最安全/性能最好)
Class clazz=Class.forName(“类的全路径”); (最常用)
调用获取其方法,属性,构造方法

Method[] method=clazz.getDeclaredMethods();
利用invoke, method.invoke(fruit,null); //执行无参方法

Field[] field=clazz.getDeclaredFields();
利用set和get调用field.set(fruit,“Apple”); //为无参对象实例属性赋值
要调用setAccessible(true)方法,把原本不可访问的私有成员变为可以访问以后,才能进行成功的访问或调用。

Constructor[] constructor=clazz.getDeclaredConstructors();
Class 对象的 newInstance()
1.调用 Constructor 对象的 newInstance()
使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。
2:先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例

newInstance()和new的不同
1:类的加载方式不同
new:类可以没有被加载
在使用newInstance()方法的时候,必须保证这个类已经加载并且已经连接了,而这可以通过Class的静态方法forName()来完成的。
2:所调用的构造方法不尽相同
new关键字能调用任何构造方法。
newInstance()只能调用无参构造方法。
3:执行效率不同
new关键字是强类型的,效率相对较高。
newInstance()是弱类型的,效率相对较低。
4:new是一个关键字, newInstance()是一个方法
既然使用newInstance()构造对象的地方通过new关键字也可以创建对象,为什么又会使用newInstance()来创建对象呢?
假设定义了一个接口Door,开始的时候是用木门的,定义为一个类WoodenDoor,在程序里就要这样写 Door door = new WoodenDoor() 。假设后来生活条件提高,换为自动门了,定义一个类AutoDoor,这时程序就要改写为 Door door = new AutoDoor() 。虽然只是改个标识符,如果这样的语句特别多,改动还是挺大的。于是出现了工厂模式,所有Door的实例都由DoorFactory提供,这时换一种门的时候,只需要把工厂的生产模式改一下,还是要改一点代码。
而如果使用newInstance(),则可以在不改变代码的情况下,换为另外一种Door。具体方法是把Door的具体实现类的类名放到配置文件中,通过newInstance()生成实例。这样,改变另外一种Door的时候,只改配置文件就可以了。示例代码如下:
String className = 从配置文件读取Door的具体实现类的类名;
Door door = (Door) Class.forName(className).newInstance();
再配合依赖注入的方法,就提高了软件的可伸缩性、可扩展性。

参考资料
注意区分class类,class对象,实例对象
java文件编译后生成class文件,class文件加载进JVM后,成为class对象存储在本地方法区中,之后创建其对应类的实例就根据其创建
class类是一个单独的类,可以看到在java.lang中,并且也自带很多方法,但是没有公共的构造方法(有一个private)。
通过上述可以看到class对象不是由class类实例化的,而是通过JVM进行加载的。可以理解为多个实例对象对应一个class对象,多个class
对象对应一个class类

在这里插入图片描述

Java注解

在这里插入图片描述
参考资料
(01) Annotation 就是个接口。
一个Annotation对象有唯一的RetentionPolicy属性和1-n个ElementType属性
(02) ElementType 是Enum枚举类型,它用来指定Annotation的类型。
取值有:FIELD,METHOD,CONSTRUCTOR等
若一个Annotation对象是METHOD类型,则该Annotation只能用来修饰方法。
(03) RetentionPolicy 是Enum枚举类型,它用来指定Annotation的策略。
取值有:SOURCE,CLASS,RUNTIME
1: SOURCE 此注解类型的信息只会记录在源文件中,编译时将被编译器丢弃,也就是说不会保存在编译好的类信息中
2:CLASS 编译器将注解记录在类文件中,但不会加载到JVM中。如果一个注解声明没指定范围,则系统默认值就是Class
3:RUNTIME 注解信息会保留在源文件、类文件中,在执行的时也加载到Java的JVM中,因此可以反射性的读取。

元注解:
如图,定义了一个叫MyAnnotation1的注解,而注解其的即为元注解
在这里插入图片描述@interface 定义注解,@interface是必须的。他本身不是一个注解
四个元注解
(1) @Documented
类和方法的Annotation在缺省情况下是不出现在javadoc中的。如果使用@Documented修饰该Annotation,则表示它可以出现在javadoc中。
javadoc 工具将你 Java 程序的源代码作为输入,输出一些包含你程序注释的HTML文件
(2) @Target(ElementType.TYPE)指定该Annotation的ElementType是ElementType.TYPE。
(3)@Retention(RetentionPolicy.RUNTIME)指定该Annotation的策略是RetentionPolicy.RUNTIME。
(4)@Inherited – @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。

标准注解:注意,下面每一个注解都是按照上图的定义方式进行定义的
@Deprecated – @Deprecated 所标注内容,不再被建议使用。
@Override – @Override 只能标注方法,表示该方法覆盖父类中的方法。如果此方法在父类中没有出现,则会报错。目的是防止重写方法时把名字写错,是可以删除的。
@SuppressWarnings – @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。

注解的作用:提供一种为程序提供元数据的方法
1:生成文档 Documented
2:编译检查 标准注解
3:跟踪代码依赖性,实现替代配置文件功能。例如spring中就用注解替换pom.xml文件

Java内部类

静态内部类:
内部类用static修饰
1:静态内部类可以访问外部类所有的静态变量和方法,即使是 private 的也一样。但是不能访问非静态的。也不能定义非静态的
2:静态内部类就属于外部类本身,而不属于外部类的某个对象,即所有外部类实例共享静态内部类
3:Java 集合类 HashMap 内部就有一个静态内部类 Entry。Entry 是 HashMap 存放元素的抽象,HashMap 内部维护 Entry 数组用了存放元素,但是 Entry 对使用者是透明的。像这种和外部类关系密切的,且不依赖外部类实例的,都可以使用静态内部类。
因为是静态内部类,所以线程不安全

成员内部类:普普通通
局部内部类:定义在方法中的类。如果一个类只在某个方法中使用,则可以考虑使用局部类。
匿名内部类:必须要继承一个父类或者实现一个接口。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191212153617298.png在这里插入图片描述
参考资料
匿名内部类:
特点:没有构造方法
上图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值