天天看点

常见面试题1 | 学习笔记

开发者学堂课程【Java 面试疑难点串讲1:面试技巧及语言基础:常见面试题1】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:

https://developer.aliyun.com/learning/course/24/detail/47 3

常见面试题1

内容介绍

一、说一下 java 类集

二、字符串哈西相等,equals 相等吗?反过来呢?

三、Spring 的工作原理,控制反转是怎么实现的,自己写过滤器过滤编码怎么实现。

四、框架的源码有没有看过

五、动态代理是怎么实现的

六、action 是单实例还是多实例

七、怎么配置 beana

八、修改单实例多实例

九、 java 的设计模式

十、事务的控制

十一、赃读

十二、事务的传播属性

十三、购物车是怎么实现的

十四、统计一天的订单量

十五、IN HAVING exsit.

十六、有没有用过定时任务

十七、JVM 的内存管理

十八、堆内存、栈内存溢出

十九、说一下缓存

二十、统计所有重名用户

类集是 java 实现的数据结构应用,如果只是一个使用,那么类集的操作非常简单,因为类集的核心接口:List 、Set、Map、Iterator、Enumeration;

List 子接口:是可以根据索引号取得内容,而在 List 集合里面最容易问到的问题: ArrayList(包装了数组的集合比较常用,数组是可变的)、LinkedList(链表的实现,搜索数据的时间复杂度为:n)区别。

Set 子接口:排序子类、HashSet 与 hashCode() 和 equals 的关系;

HashSet :重复的判断依靠的是 hashCode() 和 equals(),但是它是无序的;

TreeSet :是有序的,依靠的是Comparable 排序;

LinkedHashSet :继承了 HashSet 的特点,但是属于有序(增加顺序为保存顺序) • Map 接口:Map.Entry、Iterator 输出、HashMap、WakeHashMap (弱引用)。

例如:可能要求你现场编写一个链表,或者编写一个二叉树。

比如来写一个简单的程序做一个测试

范例:首先观察直接赋值

package cn.mldn.demo;

 public class TestIODemo {

public static void main(string[] args) throws Exception {

String strA="hello";

 String strB ="hello";

 system.out.println("strA HashCode -"+ strA.hashcode());

 system.out.println("strB Hashcode ="+ strB.hashcode());

 Sstem.out.println("

相等判断:”+(strA.equals(strB)));

strA HashCode = 99162322

 strB HashCode = 99162322

相等判断:true

范例:采用构造方法

package cn.mldn.demo;

 public class TestIODemo {

 public static void main(string[] args) throws Exception {

 string strA = new String("hello");

 String strB = new String("hello");

 System.out.println("strA HashCode ="+ strA.hashCode());

 System.out.println("strB HashCode ="+ strB.hashcode(

));

 System.out.println("

相等判断:”+(strA.equals(strB)));

strA HashCode = 99162322

 strB HashCode = 99162322

相等判断:true

范例:字符串

package cn.mldn.demo;

 public class TestIODemo {

 public static void main(string[] args) throws Exception {

 StringBuffer buf = new StringBuffer("hello");

String strA = buf.toString();

 String strB = new 'String("hello")";

 System.out.println("strA HashCode ="+ strA.hashCode());

 System.out.println("strB HashCode ="+ strB.hashcode(

));

 System.out.println("

相等判断:”+(strA.equals(strB)));

strA HashCode = 99162322

 strB HashCode = 99162322

相等判断:true

从正常道理来讲,如果 HashCode()相同,那么 equals()一定是相同的。

但是反过来 equals()相同。HashCode()也应该是相同的。

三、Spring 的工作原理,控制控制反转是怎么实现的,自己写过滤器过滤编码怎么实现。

Spring 的工作原理,控制反转是怎么实现的,自己写过滤器过滤编码怎么实现:

Spring 的核心组成:IOC&DI(工厂设计)、AOP(代理设计、动态代理设计);

Spring 之中针对于 XMIL 的解析处理采用的是 DOM4J 的实现;。

Anntation 的时候必须要求有一个容器;

 对于编码过滤需要考虑两种情况:

Struts L.X、Spring MVC、JSP+ Servet:都可以直接通过过滤器完成;

Struts 2.X:必须通过拦截器完成;

实现:考虑到可扩展性的配置,所以在配置文件里面设置编码,在程序运行的时候,动态取得设置的编码进行操作,但是需要设置两个操作:请求编码、回应编码。

Spring 的工作原理,控制反转是怎么实现的,自己写过滤器过滤编码怎么实现。

对于编码过滤需要考虑两种情况:

直接使用 InvocationHandler 接口进行实现,同时利用 Proxy 类设置动态请求对象;

使用 CGLIB 来避免对于“代理设计模式需要使用接口实现”的限制。

Struts 2.x 和 Spring MVC 中的 Action 都是多实例:

Struts 1.x 的 Action 是单实例;

Struts 2.x 和 Spring MVC 的是否单实例可以控制,只要交由 Spring 管理的Action 类,都可以通过“@scope="prototye"”来进行控制。

七、怎么配置 beana

这样的配置主要是在 Spring 里面,重点由 xml 和 annotation 的扫描负责:

xml 中直接使用“”,这样在 Spring 容器启动的时候就可以通过容器进行初始化

Annotation 必须设置 context 命名空间,而后进行扫描包的配置;

“@scope="prototye"”来进行控制

工厂设计模式、代理设计模式、单例设计模式、合成设计模式、门面设计模式(JDBC)、装饰设计模式(PrintStream、PrintWriter)、模板设计模式(Servlet)。

My SQL 数据库如果想要使用事务,必须使用“type=innodb”这个数据引擎;

事物的核心控制 commit rollback;

在 Spring 里面,利用 AspectJ,可以设置 AOP 的切面,而后进行声明式事务控制。

脏读:就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

不可重复读:是指在一个事务类多次读同一数据,在这个事务还没有结束时,另外一个事务也访问该统一数据。

那么在第一个事务的两次读数据之间,由于第二个事务的修改,那么第一个失误两次读到的数据可能是不一样的,这样就发生了在一个事务类两次读到的数据是不一样的,因此称为是不可重复读。

例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档,当编辑人员第二次读取文档时,文档已更改,原始读取不可重复,如果只有在该作者完全编写后,编辑人员才可以读取文档,则可以避免该问题。

幻读:是指当事物不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行的修改,这个修改涉及到表中的全部数据行,同时第二个事务也修改这个表中的数据,这种修改事项表中插入一行新数据。

那么以后就会发生操作第一个事务的用户发现表中还没有修改的数据行,就好像发生了幻觉一样。

例如一个编辑人员更改作者提交的文档,当生产部门将其中更改的内容,并和到该文档的主副本时,发现作者已将未编制的新材料添加到该文档中,如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。

Spring 事务传播行为

在 TransactionDefinition 接口中定义了七个事务传播行为:

Ø RR9RAGAT9N_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

Ø PROPAGATION SUPPORTS:如果存在一个事务,支持当前事务。 则非主务的执行。但是对于事务向步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。

Ø PROPAGATION_MANPATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常

Ø PROPAGALON RE9LRE_NEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

Ø  PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务。

Ø PROPAGATION_NEVER:总是非事务地执行,如果存在一个活动事务,则抛出异常;

Ø PROPAGATIQN_ NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中 如果没有活动事务,则按 TransactionDefinition.PROPAGATION_REQUIRED 属性执行

购物车的实现可以基于:

Session:浏览器关闭后消失; Cookie:数据保存在本地,如果切换到手机上无效;

数据库:可以在不同的终端上持续操作。

你的实现:Ajax 处理操作,处理购物车的应用,考虑到用户如果多的情况,并且访问量频繁要单独设计一个购物车的子系统模块。

如果一天的订单预估才 1W 条,随便你折腾;

绝对不可能使用 COUNT()和 WHERE;

分时统计,如果系统设计到位,可以单独配置一个文件进行计数(需要考虑同步,一同步就慢),不应该出现在抢购环节中。

IN 是判断具体的几项数据;

HAVING 是针对于分组后的数据的筛选,依然要使用统计函数处理;

EXTSTS:只是需要判断子查询里面是否有数据。

Java 本身提供有定时任务: TimerTask、Timer,但是此类操作对于定时很难完成,它只能够做频率,但是这个频率不准。

所以在定时开发之中会使用 quartz 组件,而且 spring 里面也提供有自己的定时实现这个实现的好处是可以在准确的时间上进行触发。

十七、JVM的内存管理

内存分为:栈(java虚拟机栈)、堆、程序计数器(类似于寄存器)、方法区、本地方法栈。

所谓的垃圾处理操作指的是堆内存:年轻代、老年代、永生代(JDK1.8移除)。会直接牵扯的 JVM 的内存调优问题。

栈溢出:栈帧,所有的方法调用都是通过栈帧的形式控制的。栈如果保存的数据过多,那么就会产生内存溢出,如果在堆内存中产生数据量过大,那么就有可能出现“OutOfMemoryError”错误。

缓存的主要目的是提高查询的效率,常见的两种缓存组件 :EhCache(数据库)、 OSCache(页面)除了这样的操作之外,还有缓存的数据库 redis、memcached,其中 redis 可以将数据保存到磁盘上,并且支持的数据类型要多于 memcached。这种 redis 的数据库每秒并发的访问量可以达到15W次。

还是需要考虑数据量问题,如果数据量大,考虑使用位图索引。如果数据量小,就直接分组统计即可。