Java面试3,java基础面试笔试题


写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。扫码加微信好友进【程序员面试学习交流群】,免费领取。也欢迎各位一起在群里探讨技术。




 

反射的定义: 反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取它所有的成员变量和方法并且显示出来。 反射机制的优点与缺点 首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。 静态编译:在编译时确定类型,绑定对象,即通过。 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。 反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。 比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。 IOC:即“控制反转”,不是什么技术,而是一种思想。使用IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。 在spring的配置文件中,经常看到如下配置: <bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl"></bean> 那么通过这样配置,Spring是怎么帮我们实例化对象,并且放到容器中去了了?对,就是通过反射!!! 下面是Spring通过配置进行实例化对象,并放到容器中的伪代码: [html] view plain copy //解析<bean .../>元素的id属性得到该字符串值为“courseDao” String idStr = "courseDao"; //解析<bean .../>元素的class属性得到该字符串值为“com.qcjy.learning.Dao.impl.CourseDaoImpl” String classStr = "com.qcjy.learning.Dao.impl.CourseDaoImpl"; //利用反射知识,通过classStr获取Class类对象 Class<?> cls = Class.forName(classStr); //实例化对象 Object obj = cls.newInstance(); //container表示Spring容器 container.put(idStr, obj); 通过解析xml文件,获取到id属性和class属性里面的内容,利用反射原理获取到配置里面类的实例对象,存入到Spring的bean容器中。 当一个类里面需要应用另一类的对象时,Spring的配置如下所示: <bean id="courseService" class="com.qcjy.learning.service.impl.CourseServiceImpl"> <!-- 控制调用setCourseDao()方法,将容器中的courseDao bean作为传入参数 --> <property name="courseDao" ref="courseDao"></property> </bean> 我们继续用伪代码的形式来模拟实现一下Spring底层处理原理: //解析<property .../>元素的name属性得到该字符串值为“courseDao” String nameStr = "courseDao"; //解析<property .../>元素的ref属性得到该字符串值为“courseDao” String refStr = "courseDao"; //生成将要调用setter方法名 String setterName = "set" + nameStr.substring(0, 1).toUpperCase() + nameStr.substring(1); //获取spring容器中名为refStr的Bean,该Bean将会作为传入参数 Object paramBean = container.get(refStr); //获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象 Method setter = cls.getMethod(setterName, paramBean.getClass()); //调用invoke()方法,此处的obj是刚才反射代码得到的Object对象 setter.invoke(obj, paramBean); 通过上面对Spring底层原理的分析,可以发现,其实并不难,用到的都是反射机制,通过反射实例化对象,存入到Spring的bean容器中。 只要在代码或配置文件中看到类的完整路径(包.类),其底层原理基本上使用的就是Java的反射机制。



 

我们再系统的梳理一下fail-fast是怎么产生的。步骤如下:

(01) 新建了一个ArrayList,名称为arrayList。

(02) 向arrayList中添加内容。

(03) 新建一个“线程a”,并在“线程a”中通过Iterator反复的读取arrayList的值。

(04) 新建一个“线程b”,在“线程b”中删除arrayList中的一个“节点A”。

(05) 这时,就会产生有趣的事件了。

       在某一时刻,“线程a”创建了arrayList的Iterator。此时“节点A”仍然存在于arrayList中,创建arrayList时,expectedModCount = modCount(假设它们此时的值为N)。

       在“线程a”在遍历arrayList过程中的某一时刻,“线程b”执行了,并且“线程b”删除了arrayList中的“节点A”。“线程b”执行remove()进行删除操作时,在remove()中执行了“modCount++”,此时modCount变成了N+1!

“线程a”接着遍历,当它执行到next()函数时,调用checkForComodification()比较“expectedModCount”和“modCount”的大小;而“expectedModCount=N”,“modCount=N+1”,这样,便抛出ConcurrentModificationException异常,产生fail-fast事件。

至此,我们就完全了解了fail-fast是如何产生的!

即,当多个线程对同一个集合进行操作的时候,某线程访问集合的过程中,该集合的内容被其他线程所改变(即其它线程通过add、remove、clear等方法,改变了modCount的值);这时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
####可以简述为以下九步

实例化bean对象(通过构造方法或者工厂方法)

设置对象属性(setter等)(依赖注入)

如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口)

如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身

将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object bean, String beanname)方法

调用Bean的初始化方法

将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object bean, String beanname)方法

使用Bean

容器关闭之前,调用Bean的销毁方法

--------------------- 

作者:浅然_ 

来源:CSDN 

原文:https://blog.csdn.net/w_linux/article/details/80086950 

版权声明:本文为博主原创文章,转载请附上博文链接!
找工作的时候有些人会被问道Spring中Bean的生命周期,其实也就是考察一下对Spring是否熟悉,工作中很少用到其中的内容,那我们简单看一下。

    在说明前可以思考一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

    Spring上下文中的Bean也类似,如下

    1、实例化一个Bean--也就是我们常说的new;

    2、按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;

    3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值

    4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);

    5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);

    6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;

    7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。

    8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;

    注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。

    9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;

    10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

 

以上10步骤可以作为面试或者笔试的模板,另外我们这里描述的是应用Spring上下文Bean的生命周期,如果应用Spring的工厂也就是BeanFactory的话去掉第5步就Ok了。
流程 

1、用户发送请求至前端控制器DispatcherServlet 

2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。 

3、处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。 

4、DispatcherServlet调用HandlerAdapter处理器适配器 

5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。 

6、Controller执行完成返回ModelAndView 

7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet 

8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器 

9、ViewReslover解析后返回具体View 

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。 

11、DispatcherServlet响应用户


转载:https://www.cnblogs.com/zhwcs/p/10473052.html

推荐内容:
Java并发(9)- 从同步容器到并发容器
ERP不规范,同事两行泪
2018年如何快速学Java
Java 面试知识点解析(三)——JVM篇
java面试题
京东面试题 Java相关
2年Java开发工作经验面试总结
Java连接Oracle
Java 最常见的 200+ 面试题汇总
Java面试通关要点汇总集

猜你喜欢

转载自blog.csdn.net/bi_zhiyi/article/details/89452071