当前位置:   article > 正文

最常见的十道面试题-反射与集合_java反射面试题

java反射面试题

面试题一:Java是值传递还是引用传递?

Java是值传递。这意味着当将一个变量传给一个方法的时候,我们实际上是传递的是这个变量的的副本。

但是对于对象来说,我们传递的是其的副本,我们不可以改变对象的引用本身,但是我们可以调用其方法和修改其字段

  1. class Person {
  2. String name;
  3. Person(String name) {
  4. this.name = name;
  5. }
  6. }
  7. void changeName(Person person, String newName) {
  8. person.name = newName;
  9. }
  10. Person john = new Person("John");
  11. changeName(john, "Jack");
  12. System.out.println(john.name); // 输出 "Jack"
  13. void changeName(Person person, String newName) {
  14. person = new Person(newName);
  15. }
  16. Person john = new Person("John");
  17. changeName(john, "Jack");
  18. System.out.println(john.name); // 输出 "John"

面试题二:反射的使用场景有哪些?如何实现反射?

在Java中,反射一种特性,它允许运行中的Java代码对自身进行检查,并对类,字段,方法进行操作。以下是反射的常见使用场景:

  1. Spring AOP功能:Spring是一个功能强大的企业级开发框架,它广泛使用反射来实现依赖注入,AOP(面向切片编程)等功能。通过反射,Spring能够在运行时动态地构建和管理对象,并且依赖注入到对象中
  2. MyBaits Plus 框架:MyBatis Plus 是一个强大的 ORM (对象关系映射)架,它是基于MyBatis 架的增强框架,MyBatis Plus 中大量使用了反射机制,例如 MyBatis Plus 通过反射来分析实体类的字段和方法,从而动态地生成 SOL 语句和处理数据库操作。通过反射,可以获取实体类的属性、字段名称、数据类型等信息,并将其映射到数据库表的列。
  3. JUnit 测试框架: JUnit 是用于 Java 单元测试的常用框架,它使用反射来实例化测试类、调用测试方法,并进行断言和校验。通过反射,JUnit 能够在运行时动态地执行测试代码,并获取测试方法的结果。

反射的实现主要涉及以下几个步骤:

获取Class对象:首先我们需要获取操作类的对象,通过.getClass()方法,或者通过类名直接获取

  1. MyClass myObject = new MyClass();
  2. Class<?> clazz1 = myObject.getClass();
  3. System.out.println(clazz1.getName()); // 输出 "com.example.MyClass"
  4. Class<?> clazz2 = Class.forName("com.example.MyClass");
  5. System.out.println(clazz2.getName()); // 输出 "com.example.MyClass"

获取和操作成员:我们获得Class对象之后,就可以操作它的成员

  1. Field field = clazz.getField("myField");
  2. Object obj = clazz.newInstance();
  3. field.set(obj, "New Value");

这段代码是使用Java反射API来操作类的字段。让我逐行解释一下:

  1. Field field = clazz.getField("myField");:这行代码是获取名为myField的字段的Field对象。clazz是我们想要操作的类的Class对象。

  2. Object obj = clazz.newInstance();:这行代码是创建一个clazz类的新实例。newInstance()方法会调用类的无参数构造器来创建新的对象。

  3. field.set(obj, "New Value");:这行代码是将obj对象的myField字段设置为"New Value"set()方法需要两个参数:第一个参数是我们想要操作的对象,第二个参数是我们想要设置的新值。

所以,总的来说,这段代码的作用是创建了一个clazz类的新实例,并将其myField字段设置为"New Value"

创建和操作对象:我们还可以使用Class对象来创建新的对象实例,或者调用对象的方法:

  1. public class Person {
  2. public String name;
  3. public Person(String name) {
  4. this.name = name;
  5. }
  6. public void sayHello(String greeting) {
  7. System.out.println(greeting + ", " + name + "!");
  8. }
  9. public static void main(String[] args) throws Exception {
  10. // 获取Person类的Class对象
  11. Class<?> clazz = Class.forName("Person");
  12. // 获取Person类的构造器
  13. Constructor<?> constructor = clazz.getConstructor(String.class);
  14. // 使用构造器创建一个新的Person对象
  15. Object obj = constructor.newInstance("John");
  16. // 获取sayHello方法
  17. Method method = clazz.getMethod("sayHello", String.class);
  18. // 调用sayHello方法
  19. method.invoke(obj, "Hello");
  20. }
  21. }

面试题三:反射有什么优缺点?为什么反射执行的比较慢?

反射优点:

  1. 动态性:反射是的程序在运行时可以动态获取类的信息和操作类或者对象,使得代码更加灵活通用
  2. 通用性:反射可以处理不同的类的对象,是的代码更加通用和复用

反射缺点:

  1. 性能比较低:由于反射需要在运行时动态获取信息和调用方法,会导致性能相对较低,因此在性能要求较高的场景下,应谨慎使用
  2. 安全性问题:反射可以访问和修改对象的私有字段和方法,这可能导致安全性问题。

为什么反射执行的比较慢?

反射执行慢的主要原因是反射涉及到运行时类型检查,访问权限检查,动态方法调用和一些额外的操作。具体要经历以下过程:

  1. 运行时类型检查:在使用反射的是哦胡,需要在运行时进行类型检查,以确保调用的方法,访问的属性等是有效的,这涉及到了额外的云心那个是判断和类型转换
  2. 访问权限检查:Java的反射机制可以突破访问权限的限制,可以直接访问私有的成员。因此在访问私有成员的时候,需要进行额外的权限检查和处理,这样会带来额外的开销
  3. 方法调用的动态性:对于通过反射调用的方法,需要在运行时动态的解析方法的签名,并确定要调用的具体的方法。这需要进行方法查找和动态绑定的过程,相对于直接调用方法会更加耗时
  4. 临时对象的创建:反射会导致对象的多次创建临时对象的产生,这在某些情况下可能会引起额外的开销。反射操作一般不会被JVM的即使编译器优化的,也没有缓存和重用,所以也会比较慢
  5. 禁止编译器优化:由于反射是在运行时进行的,而不是在编译时,这意味着编译器无法进行静态优化和代码优化。这会导致反射的效率比较低

面试题四:动态代理的使用场景有哪些?它和静态代理有什么区别?

  • 动态代理:动态代理是在程序运行时,动态的创建目标对象的代理对象,并对目标对象中的方法啊进行功能性增强的一种技术
  • 静态代理:静态代理其实就是事先写好代理类,可以手工编写也可以使用工具生成,但它的缺点是每个业务类都要对应一个代理类,特别不灵活,也不方便。

二者最大的区别就是:静态代理是在编译期确定的代理类,动态代理是在运行时由JVM根据反射机制确定的代理类

动态代理的使用场景如下:

  1. 统计每个API的请求耗时
  2. 统一的日志输出
  3. 校验被调用的API是否已经登陆和权限的鉴定
  4. Spring的额AOP功能模块就是采用动态代理的机制来实现切片编程

面试题五:BIO、NIO、AIO有什么区别?同步非阻塞和异步非阻塞有什么区别?

BIO、NIO、AIO时Java中的三种I/O模型,它们的区别主要体现在阻塞与非阻塞,同步与异步的两方面:

  1. BIO(同步阻塞模型):每个客户端连接都需要创建一个线程进行处理,如果这个链接不做任何十四请会造成不必要的线程开销
  2. NIO(同步非阻塞模型):服务器实现模式为一个请求一个线程,客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求就进行处理
  3. AIO(异步非阻塞模型):服务器实现模式为一个有效的请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理

同步非阻塞和异步非阻塞的主要区别在于是否需要等待I/O操作完成:

  • 同步非阻塞:在发起一个I/O操作后,不需要等待其完成,可以继续执行其他操作。但是如果I/O操作还没完成,就需要不断询问其状态
  • 异步非阻塞:在发起一个I/O操作后,也不需要等待其完成,可以继续执行其他操作。当I/O操作完成后,会得到一个通知

面试题六:Exception和Error有什么关联和区别?

关联:Exception和Error都是继承Throwable类,在Java中只有Throwable类型的实例,才可以throw异常或者catch异常,都是异常处理机制的基本组成类型

区别

  • Error:Error类一般是指与虚拟机相关的问题,如系统奔溃,虚拟机错误,内存空间不足,方法调用栈溢出。这类错误导致的应用程序中断,仅靠程序本身无法恢复和预防,建议程序终止
  • Exception:Exception类表示程序可以处理的异常可以捕获且可能恢复。遇到这类异常,应该Exception尽可能处理异常,使程序恢复运行,而不应该随意终止异常

面试题七:抽象类和接口有什么区别?

抽象类和接口有以下几种区别:

  1. 类型扩展不同:抽象类是单继承,接口是多继承
  2. 方法/属性访问控制符不同:抽象类方法和属性使用访问修饰符无限制,只是抽象类的抽象方法不能被private修饰;而接口有限制,接口默认的是public控制符,不能使用其他修饰符
  3. 方法实现不同:抽象类中的普通方法必须有实现,抽象方法必须没有实现;而接口中普通方法不能有实现
  4. 使用目的不同:接口是为了定义规范,而抽象类是为了复用代码
  1. // 接口定义规范
  2. public interface Flyable {
  3. void fly();
  4. }
  5. public class Bird implements Flyable {
  6. @Override
  7. public void fly() {
  8. System.out.println("Bird is flying.");
  9. }
  10. }
  11. // 抽象类复用代码
  12. public abstract class Animal {
  13. public void eat() {
  14. System.out.println("Animal is eating.");
  15. }
  16. }
  17. public class Dog extends Animal {
  18. public void bark() {
  19. System.out.println("Dog is barking.");
  20. }
  21. }

面试题八:Java中线程安全的容器有哪些?它们分别是怎么保证安全性的

Java中线程安全的包括Vector、Stack、BlockingQueue、Hashtable、ConcuurrentHashMap这几种,它们有很多方式来保证线程安全,如:

  • Vector和Stack是通过synchronized加锁写入方法来保证线程安全的
  • BlockingQueue是通过ReentrantLock来保证线程安全的
  • Hashtable是通过synchronized保证线程安全的
  • ConcurrentHashMap在JDK 1.7是通过分段锁保证线程安全的,之后通过synchronized和CAS保证线程安全 

 面试题九:ArrayList和LinkedList有什么区别?

ArrayList和LInkedList是Java中List的两种实现,它们的主要区别有以下几种:

  1. 数据结构:ArrayList是动态数组实现的,而LinkedList是双向链表实现的
  2. 随机访问:对于随机访问ArrayList是优于LinkedList,前者时间复杂度是O(1),后者是O(n)
  3. 插入删除:插入操作LinkedList是优于ArrayList,前者时间复杂度是O(1),后者是O(n)
  4. 内存占用:ArrayList是需要一块连续的地址存储数据,而LinkedList是不要求连续空间的,但是它需要额外的空间存储前后指针,所以LinkedList会更加占用空间

面试题十:HashMap底层是如何实现的?

不同的JDK 版本,HashMap 的底层实现是不一样的,总体来说: 在JDK 1.8 之前不含JDK 1.8)HashMap 使用的是数组 + 链表实现的,而JDK 1.8 之后(包含JDK 18)使用的是数组 + 链表或红黑树实现的,当插入到同一个桶的数据过多的时候就会使用红黑树。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/902477
推荐阅读
相关标签
  

闽ICP备14008679号