JAVA笔试题和面试题-2017年

前车之鉴  后事之师

更多详细内容尽在  https://jack-zdl.github.io  

        我在2017年的三月至四月份间面试了N家公司。根据他们的笔试和面试问题,我总结下来,希望对大家有用。不同的阶段会有不同的笔试和面试问题。这是为一年多的工作经验的java开发人员准备。希望大家一起努力充实自己,查漏补缺。

* 说出mybatis对jdbc的封装,并且说出相互之间的映射关系。

    首先我们都知道jdbc是最原始对数据库操作,他一般分为7个步骤

(1)加载JDBC驱动

(2)建立并获取数据库连接

(3)创建JDBC Statements对象

(4)设置SQL语句的传入参数

(5)执行SQL语句并获得查询结果

(6)对查询结果进行转换处理并将处理结果返回

(7)释放相关资源(关闭Connection,关闭Statement,关闭ResultSet)

mybatis封装连接数据库和释放数据库:数据库连接的获取和关闭我们可以使用数据库连接池来解决资源浪费的问题。通过连接池就可以反复利用已 经建立的连接去访问数据库了。减少连接的开启和关闭的时间。可以使用有可能采用DBCP的连接池,也有可能采用容器本身的JNDI数据库连接池。

SQL统一存取:原来的sql语句在java代码中,非常不方便,可读性差。传入参数映射和动态SQL和提取重复sql语句。我们写SQL语句,是使用占位符的形式必须按照顺序一一匹配,使用mybatis可以使用动态sql语句。

结果映射和结果缓存:mybatis可以讲sql结果映射到实体类中.

*spring的事物管理。其中要说出 4种隔离界别 ,7种传播方式。

脏读:事物读到未提交的数据。

事务隔离级别定义的是事务在数据库读写方面的控制范围。

4种隔离级别。

seriallizable(TransactionDefinition.ISOLATION_SERIALIZABLE):表明事务被处理为顺序执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

read(TransactionDefinition.ISOLATION_REPEATABLE_READ):隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。

理解:当我在查询数据时,不允许别的人来修改数据。

committed(TransactionDefinition.ISOLATION_READ_COMMITTED):该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值

理解:当我在修改数据,不允许别人的读取。

uncommitted(TransactionDefinition.ISOLATION_READ_UNCOMMITTED):该隔离界别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。就是很少使用,

理解:我在查询别人可以修改数据,脏读,可重复读

你需要知道一些数据库的默认隔离级别(TransactionDefinition.ISOLATION_DEFAULT)

对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。

mysql默认隔离级别TransactionDefinition.ISOLATION_REPEATABLE_READ

InnoDB默认隔离级别TransactionDefinition.ISOLATION_REPEATABLE_READ

SQL Server的缺省隔离级别TransactionDefinition.ISOLATION_READ_COMMITTED。

Oracle缺省的设置是TransactionDefinition.ISOLATION_READ_COMMITTED。

spring的事物传播行为,当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。

传播级别定义的是事务的控制范围

(required)TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 这个是最常见的传播行为,所以这个级别通常能满足处理大多数的业务场景。

(requires_new)TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。,执行新事务完成以后,当前事务恢复再执行。这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回滚。怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的子事务不会直接影响到父事务的提交和回滚。

(supports)TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。应用场景较少。

(not_supported)TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。非事务执行后在执行当前事务。

(propagation_never)TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。不能存在上下文事物

(propagation_mandatory)TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(上下文必须有事物)

(propagation_nested)TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

* 双向链表的描述-单双链表的反序操作

链表和数组优缺点:数组查询比较简单,因为有下标值,根据下标值可以快速查询到相应的值,但是删除就比较麻烦,这一点连接比较方便,只需要将上一个指针不在指向要删除的数据,而是指向下一个数据。

数据块,first的指针,last的指针,一般数据时first的指针连接上一个数据的last指针,last的指针连接下一个数据的first指针。第一个数据没有first的指针,最后一个元素没有last指针。

* 线程的加锁机制,一共有几种加锁机制。

synchronized(互斥锁)代码加上这个关键字后以为者这段代码具有了原子性和可见性。原子性说明一个线程只能执行这段代码,可见性指它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 。

作用:如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。

synchronized缺点:1它无法中断一个正在等候获得锁的线程;2也无法通过投票得到锁,如果不想等下去,也就没法得到锁;3同步还要求锁的释放只能在与获得锁所在的堆栈帧相同的堆栈帧中进行,

lock(锁抽象):1NSLock 2ReentrantLock(锁对象):具有synchronized的相同功能,但是还有锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。3读写锁ReadWriteLock:读取线程不应该互斥!

* 线程的顺序问题

* spring的重定向和转发问题

转发:forward  转发到某个视图,就是页面跳转,实例springmvc可以使用viewResolver设置转发具体的view,本来我们发送到hello中,通过viewResolver设置前缀和后缀,我们可以转发到/springmvc/hello.jsp页面中。

重定向:重定向之后地址栏上的地址会发生变化,重定向是二次请求,转发是一次请求,转发快于重定向。redirect:/index.action";redirect 重定向到内部的某个controller中,定向内部某个资源

个人使用:页面跳转建议使用重定向,有内部Servlet跳转建议使用转发。转发只能在站内跳转,重定向可以跳转到任意想要的地址----只要这个地址存在,所以请求页面的时候转发相比重定向也有局限性。如果代码逻辑是ServletA->ServletB->*.jsp,使用转发,那么这三次操作都在一次请求中,而如果使用重定向,那么客户端将发起三次请求,这真的毫无必要。因此,如果代码逻辑中含有内部的Servlet跳转,使用转发会使一个好的选择。

* 内存区块问题

内存分配及其实现

    栈:线程单独享有,每个线程对应着一个虚拟机栈,因此虚拟机栈也是线程私有的

        1 虚拟机栈,在虚拟栈中存放  a 局部变量表 b 操作站 c 动态链接 d 方法出口

                    a 局部变量表 存储着方法的相关局部变量.包括各种基本数据类型,对象的引用,返回地址等

                      只有long和double类型会占用2个局部变量空间(Slot,对于32位机器,一个Slot就是32个bit),

                      其它都是1个Slot,局部变量表是在编译时就已经确定好的,方法运行所需要分配的空间在栈帧中是完全确定的,

                      在方法的生命周期内都不会改变。

                    d 方法出口(当方法被调用时,栈帧在JVM栈中入栈,当方法执行完成时,栈帧出栈)

        2 本地方法栈 :虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,

                      在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。

                      线程私有。

    堆:

    年轻代 对象创建时,停止-复制清理法,Minor GC

        (8)Eden: (Eden满的时候出发minor GC)绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。

            Eden区是连续的内存空间,因此在其上分配内存极快

            最初一次,当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,

            并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的)

            下次Eden区满了,再执行一次Minor GC,将消亡的对象清理掉,将存活的对象复制到Survivor1中,然后清空Eden区

        (1)Survivor0: 来记录对象的清理数次。在HotSpot切换15次,就可以进去老年代。

        (1)Survivor1:

    年老代 Major GC,也叫 Full GC。标记-整理算法。升到老年代的对象大于老年代剩余空间full gc,(年轻代升到年老代对象大于

        老年代剩余空间)

        或者小于时被HandlePromotionFailure参数强制full gc,(当空间小于指定的设置的空间)

        标记出仍然存活的对象(存在引用的),将所有存活的对象向一端移动,

        以保证内存的连续。在发生Minor GC时,虚拟机会检查每次晋升进入老年代的大小是否大于老年代的剩余空间大小,如果大于,

        则直接触发一次Full GC,

        如果对象比较大(比如长字符串或大数组),Young空间不足,则大对象会直接分配到老年代上

        (大对象可能触发提前GC,应少用,更应避免使用短命的大对象)。

        可能存在年老代对象引用新生代对象的情况,如果需要执行Young GC,则可能需要查询整个老年代以确定是否可以清理回收,

        这显然是低效的。解决的方法是,年老代中维护一个512 byte的块——”card table“,所有老年代对象引用新生代对象的记

        录都记录在这里。Young GC时,只要查这里即可,不用再去查全部老年代,因此性能大大提高。

    永久代(方法区)常量池中的常量,无用的类信息,

        类的所有实例都已经被回收

        加载类的ClassLoader已经被回收

        类对象的Class对象没有被引用(即没有通过反射引用该类的地方)

        则将类信息进行回收。

* 线程生产者消费者问题以及多线程和线程池问题

* 设计模式-工厂模式 观察者模式 适配器等常用模式

工厂模式是创建型的设计模式,通过这个可以了解如何创建对象,适配器模式是结构型模式,通过了解他来了解所有的结构型设计模式的方法,观察者模式是行为型模式,了解它知道行为型的模式的作用。

工厂模式:平时我们新建一个类都是在需要的代码中new一个,现在我们通过一个工程类来帮我们new一个我们需要的类返回给我们。

观察者模式:类似于邮件订阅和RSS订阅,当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。

适配器模式:跟代理模式一样,不是直接对得到这个类,而是同一个另一个类去得到这个类,并且加强了这个类的方法。跟代理模式一样,等其他的结构型设计模式差不多。

* linux 常用命令写出5到10个。

1ifconfig 2 systemctl start mariadb 3 ip addr 4reboot 0 5 mysql -uroot -ppassword 6 cd 7vi 8vim 9 cat 10 ls

* 链表的反向修改。

* String 为什么不可变,考察你的源码分析

string是不可变的,他的内部有value hash二个成员变量都没有set方法,所以外部都无法修改它。一般使用string池来销毁和生成string。

* int 等一些基本数据类型的长度及所占字节

    byte 8位 -128-127

    short 16位

    int  32

    long 64

    float 32位  0.0f

    double 0.0d

    boolean false

    char 16 位 Unicode 字符;最小值是 \u0000(即为0); 最大值是 \uffff(即为65,535);

* spring  ioc的实现原理

IoC理论:借助于“第三方”实现具有依赖关系的对象之间的解耦,

        1) 软件系统在没有引入IoC容器之前,对象A依赖对象B,那么A对象在实例化或者运行到某一点的时候,自己必须主动创建对象

          B或者使用已经创建好的对象B,其中不管是创建还是使用已创建的对象B,控制权都在我们自己手上。

        2)如果软件系统引入了Ioc容器之后,对象A和对象B之间失去了直接联系,所以,当对象A实例化和运行时,如果需要对象B的

          话,IoC容器会主动创建一个对象B注入到对象A所需要的地方。

        3)通过前面的对比,可以看到对象A获得依赖对象B的过程,由主动行为变成了被动行为,即把创建对象交给了IoC容器处理,控

          制权颠倒过来了,这就是控制反转的由来!

        IOC原理 这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,即所谓反转。

    Bean的生命周期:

        spring bean的完整生命周期从创建Spring容器开始,知道spring容器销毁bean.

        bean自身的方法,Bean本身调用的方法和通过配置文件中的init-method和destroy-method指定的方法

        Bean级生命周期接口方法  BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法

        容器级生命周期接口方法  InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,

        一般称它们的实现类为“后处理器”。

        工厂后处理器接口方法    AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等

        非常有用的工厂后处理器  接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用

            实例BeanFactoryPostProcessor实例化出

                容器级别生命周期接口 BeanPostProcessor ,InstantiationAwareBeanPostProcessor 。

                InstantiationAwareBeanPostProcessor 执行before方法对对象属性进行修改

                在执行Bean构造器

                InstantiationAwareBeanPostProcessor 执行Property方法

                为bean注入属性

                调用Bean级生命周期接口方法

                BeanNameAware  BeanFactoryAware

                调用容器级生命周期接口方法

                    BeanPostProcessor

                调用Bean级生命周期接口方法

                InitializingBean

                调用Bean自身的方法

                nit-method

                调用容器级生命周期接口方法

                BeanPostProcessor  after方法 修改对象属性

                InstantiationAwareBeanPostProcessor  after方法 修改对象属性

                ....初始化成功后正常使用......

                调用Bean级生命周期接口方法

                DiposableBean

                调用Bean自身的方法

                destroy-method

                销毁

* springmvc流程

1.用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;

    2.DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得

            该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain

            对象的形式返回;

    3.DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,

            此时将开始执行拦截器的preHandler(...)方法)

            4.提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,

            根据你的配置,

            Spring将帮你做一些额外的工作:

            HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

            数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

            数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

            数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

    5.Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;

    6.根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)

        返回给DispatcherServlet ;

    7.ViewResolver 结合Model和View,来渲染视图

    8.将渲染结果返回给客户端

* java 三大特性讲解一二。多态讲解

封装,继承,多态

封装:封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。

继承:继承是为了重用父类代码。

多态:Java实现多态有三个必要条件:继承、重写、向上转型。实现方式:继承和接口

多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

酒 a = 剑南春

酒 b = 五粮液

酒 c = 酒鬼酒

指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

* javaIO的使用,NIO的使用。

输入输出流:inputstream  outputstream 字节流字符流:“InputStraem,OutputStrem”,“Reader,Writer”,节点流和处理流:“直接连接io设备”,“将流包装一下,”

NIO是基于缓冲的io读写,非阻塞IO,

IO是基于流的读写,阻塞IO。

* servlet的生命周期

1,初始化阶段  调用init()方法

2,响应客户请求阶段  调用service()方法 调用doget方法或者dopost方法

3,终止阶段  调用destroy()方法

* 内部类 等几种内部类

简单理解:一个类中定义了另加一个类,

好处:最大的好处就是可以多重继承,加入你需要继承二个实体类怎么办?一个子类只能继承一个实现类或者抽象类,所以要使用内部类,因为内部类可以独立继承其他类。

内部类分类:

1成员内部类:它是外围类的一个成员。a 他可以随意访问所有外围类的变量方法,但是外围类只能实例化他来访问它。b 成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

2 局部内部类:他是方法内的内部类。对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

3 匿名内部类:匿名内部类是没有访问修饰符的

4 静态内部类:关键字static中内部类,a 它的创建是不需要依赖于外围类的。b 它不能使用任何外围类的非static成员变量和方法。

* java 反射

java反射:是指在编译期间不知道是哪个类别加载,只有在运行期间才被加载探知,自省,这种使用编译期不知道的类,这种编译特点就是反射。

在我们eclipse或者intellij打出某个类的点时会出现这个类方法和属性,这就是利用了反射。我们在代码中使用log4j时,使用这个反射机制,得到log的所有方法属性。

* spring的线程池

线程池的使用情况,

* redis的使用,使用什么api使用什么jar,假如redis的连接数不够怎么办

* 多线程问题

* equals() 与 hashcode()或 “==”

* final, finally, finalize的区别

* spring将传递的数据过来的数据封装为对象,并且做校验

* 除了设计模式做单例模式其他的方法中如何做单例模式


JAVA笔试题和面试题-2017年_第1张图片
红包等你拿

你可能感兴趣的:(JAVA笔试题和面试题-2017年)