java程序中的对象在运行时表现为两种类型,即编译时类型和运行时类型。例如Person p =new Student();,此时会生成一个p变量,该变量的编译类型为Person,运行时类型为Student。
有时候程序在运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象的运行时类型的方法,这就程序需要在运行时发现对象和类的真实信息,解决这个问题有两个方法:
- 假设在编译和运行时都完全知道类型的具体信息,可以使用instanceof运算符进行判断,在通过强制类型转换将其转换成运行时类型的变量即可;
- 编译时无法预知该对象属于哪些类,程序只能靠运行时信息来发现该对象和类的真实信息,这就必须使用反射机制。
通过反射机制可以实现如下操作:
- 程序运行时,可以通过反射获得任意一个类的Class对象,并通过这个对象查看这个类的信息;
- 程序运行时,可以通过反射创建任意一个类的实例,并访问该实例的成员;
- 程序运行时,可以通过反射机制生成一个类的动态代理类或动态代理对象。
补充:Java的引用变量有两个类型,一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定,如果编译时类型和运行时类型不一致,会出现多态。
2、反射常见的应用场景- 使用JDBC时,如果要创建数据库的连接,则需要先通过反射机制加载数据库的驱动程序;
- 大多数框架支持注解/XML配置,从配置中解析出来的类是字符串,需要使用反射机制实例化;
- 面向切面编程(AOP)的实现是在程序运行时创建目标对象的代理类,这必须由反射机制来实现;
java集合有个缺点就是把一个对象放进集合中后,集合无法识别当前对象的数据类型,当再次取出该对象时,该对象的编译类型就变成了Object类型,运行时类型未改变。
这样设计的原因:集合的设计者不知道我们会用什么样的集合来保存什么类型的对象,所以设计成为能保存任意类型的对象,具有很好的通用性,但会导致如下两个问题:
- 集合对元素的类型没有限制,这样可能会引发一些问题,例如,想创建一个只能保存Dog对象的集合,但程序也可以将Cat对象存储进去,所以会引发异常;
- 对象放进集合中后,集合无法识别当前对象的数据类型,当再次取出该对象时,该对象的编译类型就变成了Object类型,因此取出集合元素后还需要进行强制类型转换,增加了编程的复杂度,还可能会引发异常。
泛型允许程序在创建集合时制定集合元素的类型,使得程序不会再将其他类型存储到当前集合中。同时也使得程序更加简洁,集合自动记住所有集合元素的数据类型,从而无须对集合元素进行强制类型转换。
4、如何处理异常一般按照以下三个步骤进行处理:
-
捕获异常
将业务代码包裹在try块内部,当业务代码发生异常时,系统都会为这个异常创建一个异常对象。异常对象创建后,JVM会在try块之后寻找可以处理他的catch块,并将异常对象交给这个catch块处理; -
处理异常
在catch块中处理异常时,应该先记录日志,便于之后追溯这个异常,然后根据这个异常的类型、结合当前业务的情况进行相应的处理。比如,给变量赋予一个默认值、直接返回一个默认、直接返回空值、向外抛出一个新的业务异常交给调用者处理等; -
回收资源
如果业务代码打开了某个资源,比如数据库连接、网络连接、磁盘文件等等,则需要在这段业务代码执行完毕后关闭这项资源。并且,无论是否发生异常,都需要关闭这些资源,可以写在finally块中。
通常情况下,不要在finally中使用return、throw等导致方法终止的语句,一旦使用将会导致try、catch中的return、throw语句失效
6、finally中的语句一定会被执行吗不一定!存在一些特殊情况会导致finally中的语句不被执行
- 直接返回到未执行到try-finally语句块
- 抛出异常未执行到try-finally语句块
- 系统退出到未执行到try-finally语句块
不可以!抽象类是被用于继承的,final修饰代表不可修改、不可继承。
8、throw和throws的区别throw(不常用):
- 表示方法内抛出某种异常对象(只能是一个);
- 用于程序员自产生并抛出异常;
- 位于方法体内部,可以作为单独语句只用;
- 如果异常对象非RuntimeException则需要在方法的声明时加上该异常的抛出;
- 执行到throw语句则后面的语句块不再执行
throws:
- 方法的定义上使用throws表示这个方法可能抛出某些异常(可能有多个);
- 用于声明在该方法内部抛出异常;
- 必须跟在参数列表的后面,不能单独使用;
- 需要由方法的调用者进行异常处理。
- final:表示最终的、不可改变的。用于修饰类、方法和变量。表示属性不可变,方法不可重写,类不可被继承;
- finally:异常处理的一部分,只能使用在try catch中,并且附带一个语句块表示这段语句最终一定会执行,经常用在需要释放资源的情况下,作为异常的统一出口;
- finalize():是Object类的一个方法,在垃圾回收器执行时会调用被回收的对象的finalize()方法。
补充:final修饰基本类型变量,值不能改变;修饰引用变量,栈内存中的引用不能改变,所指向的堆内存中的对象的属性值可以改变。
10、接口和抽象类的区别- 抽象类可以有构造方法,接口不能有构造方法;
- 抽象类可以有成员变量,接口中没有成员变量;
- 抽象类中可以包含非抽象的普通方法;
- 抽象类中的抽象方法访问权限可以是public、procted和default,接口中的抽象方法只能是public类型;
- 抽象类中可以包含静态方法。
- 一个类可以实现多个接口,但只能继承一个抽象类;
- 接口不可以实现接口,但可以继承接口,并且可以多继承。
&
- 逻辑与,&两边的表达式都会进行运算;
- 整数的位运算符;
&&
- 短路与,&&左边的表达式结果为flase时,&&右边的表达式不参与运算。
|
- 逻辑或,|两边的表达式都会进行运算;
- 整数的或运算符;
||
- 短路或,||左边的表达式结果为true时,||右边的表达式不参与运算。
this:
2. 对象内部指代自身的引用;
3. 解决成员变量和局部变量同名问题;
4. 可以调用成员变量;
5. 不能调用局部变量;
6. 可以调用成员方法;
7. 在普通方法中可以省略this;
8. 在静态方法中不允许出现this;
super:
9. 代表当前对象的直接父类对象的引用;
10. 可以调用父类的非私有成员变量和方法;
11. 可以调用父类的构造方法,只限构造方法中使用,且必须是第一句。
- 可以修饰变量、方法、代码块、内部类;
- static变量是这个类所有,由该类创建的所有对象共享同一个static属性;
- static修饰的变量只能是类的成员变量;
- static代码块在类被第一次加载时执行静态代码块,且只被执行一次,主要作用是实现static属性的初始化;
instanceof是一个运算符,用来在运行时判断对象是否是指定类极其父类的一个实例,比较的是对象,不能比较基本类型。
16、为什么String类被设计用final修饰- String类是最常用的类之一,为了效率,禁止被继承和重写;
- 为了安全,防止被恶意植入代码、破坏程序。



