一、准备
1.1 总介绍
介绍面试环节中常见问题
讲解J2SE面试笔试常见问题
讲解J2EE与框架的面试笔试常见问题
2.1 本章介绍
......
3.1 自我介绍
我是谁
我做过什么
我的优势在哪里
时间2-3分钟
3.2 现场面对面
容貌要求
着装要求
面试礼仪(70/80后社会中坚力量,公司管理层主要构成)
一对多面试
4.1 面试必知必问-1
谈谈你的职业规划
与同事遇到正面冲突,你怎么办(不诋毁任何人,不传递负面情绪)
你生活中最重要的是什么(考你对工作生活家庭是什么态度)
4.2 面试必知必问-2
这份工作你能预见哪些问题(对公司业务不熟悉)
你希望与什么样的同事或上级共事
你将如何开展工作(考你条理性、适应性)
4.3 面试必知必问-3
有想过创业吗
你还应聘了哪些公司(考你是否有明确的目标和职业规划)
为什么你的学历是专科
4.4 面试必知必问-4
你对加班的看法(测试你是否愿意为公司奉献。当日事当日毕)
你对薪资的要求
谈谈你对跳槽的看法(面试陷阱。说得越少越好。可以说不想从金融IT转电信IT)
5.1 给职场新人的建议
1. 不要有为老板工作的心态。
2. 永远不要敷衍工作,不要抱怨环境、不要埋怨别人,不要混日子、不要讲是非。
3. 事情做完马上汇报。如果做很久,就分阶段汇报进度。不要让主管追着你问。
4. 管理好自己的情绪,做一个可爱的人。没有超完美的公司,也没有不委屈的工作。做弹簧,不要做橡皮泥。
5. 接受任务有确认机制,不清楚的地方及时沟通,不要想当然,不要我以为。
6. 注意工作汇报方式。老板不是法官,别整天怀里揣着公平公正公开,他们看的是利弊,不是对错。汇报工作说结果不说过程,说功劳不说苦劳。
7. 注重细节。不迟到,不写错别字。
8. 提建议时要有数据支撑。请示问题说方案,不要给主管问问题。有思考才能证明你的存在。
9. 要提升自己的价值(经营人脉的前提)。不要被成功学忽悠了,什么圈子人脉,到处社交什么用也没有。人脉的本质是资源对等的交换。
10. 认真对待工作汇报。日报周报年度总结,不是负担,是你表现的机会。会干活,会吆喝。对主管,兑现大于承诺,答应的事情比期限提早一点完成,承诺的内容外多花一点心思。工作的基本要求。超出预期才有升值的可能。
二、Java基础面试技巧
1.1 JDK、JRE、JVM有什么区别
JDK:Java Development Kit 针对Java程序员的产品
JRE:Java Runtime Environment 是运行Java的环境集合
JVM:Java虚拟机用于运行Java字节码文件,跨平台核心
1.2 常用数字类型的区别
1.3 Float在JVM的表达方式及使用陷阱
打印结果为:d1 == d2
float类型在内存中的存储形式为科学计数法,表达为:4.2343242E7(小数点后保留7位)
d2用科学计数法表示同样为4.2343242E7,因此d1 == d2
1.4 随机数的使用
编程题:随机生成30~100之间的整数
int min = 30;
int max = 100;
int result = new Random().nextInt(max-min) + min;
int result = (int)(Math.random()*(max-min)) + min;
1.5 找出1-1000内的质数
public class PrimeNumber {
public static void main(String[] args){
for(int i=2; i<=1000; i++){
boolean flag = true;
for(int j=2; j<I; j++){
if (i%j==0) {
flag = false
break
}
}
if (flag) {
System.out.println(i);
}
}
}
}
2.1 面向对象三大特性是什么
封装(接口是体现封装最常用的办法)
好处:
实现专业的分工
减少代码耦合
可以自由修改类的内部结构
继承(单继承)
多态 (封装继承都是为多态服务的。)
多态的实现机制:
多态是三大特性中最重要的操作
多态是同一个行为具有多个不同表现形式或形态的能力
多态是同一个接口,使用不同的实例而执行不同操作
接口与抽象类有哪些异同
2.2 静态与实例变量(方法)的区别
语法区别:静态变量前要加static关键字,实例则不用
隶属区别:实例变量属于某个对象的属性,而静态属于类
运行区别:静态变量在JVM加载类字节码时创建,运行过程中不会被GC回收。实例变量在实例化对象时创建,不使用时会被GC回收。
推荐使用实例变量,减少静态变量的使用。
2.3 类的执行顺序
会出面试题,考察子类父类代码的执行顺序
1. 静态优先
2. 父类优先
3. 非静态块优先于构造函数
2.4 Java的异常体系
请说明Java的异常体系
Error和Exception的区别和联系
3.1 String与字符串常量池
答案:
true:内存地址相同
true:内存地址相同
false:编译时无法确定s5,运行时才确定,并给一个新内存地址。
true
false:new String()创建的字符串不会保存在常量池中
考察字符串底层存储的理解,字符串一旦创建就是final修饰的,不可变。同时字符串会默认保存在“方法区域 特定开辟的区域 常量池”。字符串创建好后,常量池就会出现这个字符串常量,不同String对象引用相同的字符串时,其实就是指向同一字符串的内存地址。
3.2 String、StringBuilder与StringBuffer的区别
4.1 List与Set的区别
4.2 List排序的编码实现
编程题list排序:
public class ListSorter {
public static void main(String[] args) {
List<Employee> emps = new ArrayList<~>();
emps.add(new Employee("张三", 33, 1800f));
emps.add(new Employee("李四", 55, 3800f));
emps.add(new Employee("王五", 40, 2300f));
Collections.sort(emps, new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return (int)(o1.getAge() - o2.getAge());
}
})
System.out.println(emps);
}
}
提示:当差值在-1到1之间时,强转后会变为0,导致结果不准确。此时,可以加一个判断条件,当-1<差值<0时,返回-1,当0<差值<1时,则返回1。
4.3 TreeSet排序的编码实现
public class SetSorter {
public static void main(String[] args) {
TreeSet<Employee> emps = new TreeSet<Employee>(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return (int)(o1.getAge() - o2.getAge());
});
})
emps.add(new Employee("张三", 33, 1800f));
emps.add(new Employee("李四", 55, 3800f));
emps.add(new Employee("王五", 40, 2300f));
System.out.println(emps);
}
}
public class SetSorter {
public static void main(String[] args) {
TreeSet<Employee> emps = new TreeSet<Employee>()
emps.add(new Employee("张三", 33, 1800f));
emps.add(new Employee("李四", 55, 3800f));
emps.add(new Employee("王五", 40, 2300f));
System.out.println(emps);
}
}
public class Employee implements Comparable<Employee> {
......
@Override
public int compareTo(Employee o) {
return this.getAge().compareTo(o.getAge());
}
}
4.4 hashCode与equals的联系与区别
Object类hashCode与equals的区别:
equals()方法用来判断两个对象是否“相同”。可靠,考量了各种因素,自反性、对称性、传递性、一致性等。
hashCode()返回一个int,代表“该对象的内存地址”。不可靠
hashMap、hashSet、hashTable等先用hashCode初判再用equals复判。
5.1 Java IO中有几种类型的流
5.2 利用IO实现文件复制
编程题:复制文件到指定文件夹
public class FileCopy {
public static void main(String[] args) {
//第一种方式:利用Java IO
File source = new File("e:/tomcat8.zip");
File target = new File("e:/target/tomcat8.zip");
InputStream input = null;
OutputStream output = null;
try {
input = new FileInputStream(source);
output = new FileOutputStream(target);
byte[] buf = new byte[1024];
int byteRead;
while((byteRead = input.read(buf)) != -1) {
output.write(buf, 0, byteRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
input.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//第二种方式:FileChannel实现文件复制
//第三种方式:Commons IO组件实现文件复制
// FileUtils.copyFile(Source, Target);
}
}
手写完整说明编程功底非常过硬。
6.1 JVM的内存组成
堆:Java虚拟机管理的内存的最大一块,唯一的目的就是存放在程序运行时创建的对象实例。垃圾回收主要区域。被所有线程共享。
方法区:存储虚拟机加载的类的信息、静态常量、静态变量、方法的声明等。被所有线程共享。
私有区:线程独有的部分。
程序计数器PC:行号计数器,程序跳转时记录行号,方便程序还原。
虚拟机栈:方法执行时的状态。每个方法都会在这里形成一个栈帧,每个栈帧相当于方法的实时状态。
本地方法栈:存放操作系统API的栈帧。
6.2 GC垃圾回收及算法介绍
GC负责3项任务:分配内存、确保引用、回收内存。
GC回收的依据是某对象没有任何引用,则可以被回收。
垃圾回收GC算法:
引用计数算法
跟踪回收算法(利用JVM维护的对象引用图)
压缩回收算法(把办公桌移到墙角,打扫卫生,后再移回办公桌)
复制回收算法(内存分成两个区域,一个区域满了,把其中的活动的对象移到另一片内存中,并紧密地排列。那片满了再重复操作)
按代回收算法(主流回收算法。把堆分成多个子堆,每个子堆视为一代,算法运行过程中优先回收年幼的对象。对此回收后依然存活的对象 移到高一级的子堆中。高一级的子堆被扫描的频率更低。)
6.3 Java的内存泄漏场景
1. 静态集合list类
2. 各种链接(开启后未关闭)
3. 监听器(如果对监听器中使用的对象变量 没有有效控制的话,很容易产生内存泄漏)
4. 不合理的作用域(变量定义范围 大于 使用范围,很可能造成内存泄漏)
6.4 请实现对象浅复制与深复制
浅复制:只对对象及变量值进行复制,引用对象地址不变
深复制:不仅对象及变量值进行复制,引用对象也进行复制
public class Dancer implements Cloneable, Serializable {
...属性...
public Dancer deepClone() {
//序列化,将内存中的对象序列化为字节数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化,将字节数组转回到对象,同时完成深复制的任务
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Dancer)ois.readObject();
}
......
Dancer d1 = new Dancer();
d1.setName('刘明');
Dancer d2 = new Dancer();
d2.setName('李敏霞');
//浅复制
Dancer shallow = (Dancer)d1.clone();
//深复制
Dancer deep = (Dancer)d1.deepClone();
}
三、Web基础与数据处理
1.1 请说明Servlet执行流程
Apahce负责对Servlet进行实例化与初始化。那么Servlet是什么时候被实例化的呢?
Servlet默认情况下是第一次访问的时候实例化的,也可以通过web.xml配置load-on-startup,使其在服务器启动的时候实例化。
同时对于Servlet来说,它在Tomcat中全局有且仅有唯一的一个对象,Tomcat并不会创建Servlet的多个实例。对于Servlet来说,如果在并发环境下,它是怎么处理的?
Servlet是基于单例多线程,利用多线程技术来提供web服务。不得不注意线程安全问题,在使用Servlet的时候,不允许创建存在状态的变量或者对象,不然会在并发访问时产生无法预期的结果。
1.2 Servlet生命周期
Servlet生命周期是什么?
1. 装载 - web.xml(在Java应用程序启动的时候,Tomcat会扫描web.xml,得知当前的应用有哪些Servlet,注意装载时并不会实例化Servlet。)
2. 创建 - 构造函数(URL第一次访问Servlet地址的时候,来进行创建的。同时会执行构造函数。Java层面对象创建。)
3. 初始化 - init()(对于Servlet来说,在创建对象以后,马上执行 init() 这个初始化函数,对Servlet进行初始化。init() 是Servlet独有的,专门用于初始化Servlet执行资源的方法。)
4. 提供服务 - service()(对于发来的请求无论是 Get 还是 Post,一律使用 service() 方法接收处理。还可细分为doGet、doPost,service()是请求的总的入口。)
5. 销毁 - destroy()(web应用程序重启或者关闭的时候,会执行 destroy() 方法,来将Servlet资源彻底销毁。)
代码演示:
IDEA 配置Tomcat运行Servlet项目_你这家伙的博客-CSDN博客_idea运行servlet
1.3 请求与响应的结构
请阐述HTTP请求的结构:
HTTP请求包含三部分:请求行、请求头、请求体。
请阐述HTTP响应的结构:
HTTP响应包含三部分:响应行、响应头、响应体。
1.4 请求转发与响应重定向的区别
请求转发是服务器跳转,只会产生一次请求。
请求转发语句是:request.getRequestDispatcher().forward()
重定向则是浏览器端跳转,会产生两次请求
响应重定向语句是:response.sendRedirect()
1.5 请阐述session的原理
session是指与客户端浏览器窗口绑定的,且存储在服务器内部的用户数据。
1.6 JSP九大内置对象
2.1 Statement和PreparedStatement的区别
PreparedStatement是预编译的SQL语句,效率高于Statement(每执行一次就要解析一次SQL语句)。
PreparedStatement支持 ?操作符,相对于Statement更加灵活。
PreparedStatement可以防止SQL注入,安全性高于Statement。
JDBC代码演示:
2.2 请说明JDBC使用步骤
加载JDBC驱动
创建数据库连接(Connection)
创建命令(Statement)
处理结果(ResultSet)
关闭连接
2.3 SQL编程训练-1
2.4 SQL编程训练-2
HAVING对分组后的结果进行二次筛选,在GROUP BY之后执行的。WHERE在GROUP BY之前执行的。
2.5 SQL编程训练-3
四、主流框架
1.1 IOC与DI的理解
IOC控制反转
宏观设计理念,由第三方来管理与控制对象。
IDAO dao = new UserDAO();
编译时就决定了这个对象是UserDao,不可能有其他变化。把对象绑定时机滞后,在运行时动态的对它进行创建不就可以了吗。
IDAO dao = (IDAO)applicationContext.getBean("userDAO");
//先用这个
<bean id="userDAO" class="com.imooc.dao.UserDAO" />
//随时可以换成这个
<bean id="userDAO" class="com.imooc.dao.UserExtDAO" />
applicationContext对象对配置文件中的对象进行创建和控制,所以也被称为IOC容器。
DI依赖注入
具体技术实现,它是对宏观的IOC理念的一种技术上的诠释。由对象容器在运行时动态注入对象。
实现方式:反射,Java中反射作用在运行时进行动态的创建、设置、管理。
工厂模式,利用 工厂不必关注对象创建的细节,直接返回接口,在运行时由工厂动态的决定是由哪个对象进行实例化。
1.2 Spring实例化对象的三种形式
Spring中Bean实例化有几种方式:
1. 使用类构造器实例化(最常用 最根本)
2. 使用静态工厂方法实例化(间接用了方式1)
3. 使用实例工厂方法实例化(间接用了方式1)
public static void main(String[] args) {
//运行后 IOC容器被初始化
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService)ctx.getBean("userService");
userService.createUser();
}
factory-method="createPerson"
1.3 Spring四种注入方式
Bean注入属性有哪几种方式:
1. setter注入
2. 构造器注入
3. 注解注入
4. Java Config注入
通过构造函数注入:程序执行前,没有准备好userDao的话,意味着UserService无法被创建。因为这是创建对象的强制要求。在实际开发中,不推荐构造函数注入。
注解是JDK1.5后出现的新特性。可以帮助我们简化配置的过程。
@Repository("userDAO")
@Service("userService") //括号内为BeanId名字
@Resource(name = "userDao") //优先按照BeanId加载对象
上面注解:IOC容器初始化(Spring启动)的时候,它会自动加载当前的类并实例化。默认情况下,类的bean id就是类名首字母小写。注解在IOC容器初始化过程中,就完成了自动创建注入的工作。
Java Config注入 :Spring4以后推出的对象创建与注入的方式。摒弃了以往的xml配置的方式,采用注解+Java代码的方式,来管理对象的关系。可以让我们完全不用修改原有的Service Dao的代码就可以完成对象的关联工作。
@Configuration
public class AppConfig {
@Bean(name = "userDao")
public UserDao userDao() {
return new UserDAOImpl();
}
//对于上面的方法来说,IOC容器在初始化的时候会执行这个方法,并且将这个方法产生的对象命名为userDao放入IOC容器。
//@Bean注解不写name属性的话,就默认用方法名作为BeanId。
@Bean
public UserService userService() {
UserService userSerivce = new UserService();
userService.setUserDAO(this.userDAO());
return userService;
}
1.4 Spring常见面试问题
请说明Scope属性的作用与取值:
用于控制对象的数量,是单例,还是多例。
<bean id="" class="" scope="prototype / singleton / request / session" />
prototype情况下,每一次 “ctx.getBean()” 时才会创建对象。在IOC容器初始化时,并不会创建任何新的对象。
request情况下,同一请求内 “ctx.getBean()” 的对象是同一个。引入Spring MVC,才会生效。
session情况下,同一个session name “ctx.getBean()” 是同一个对象。引入Spring MVC,才会生效。
请说明lazy-init属性的作用:
懒加载。默认为false。true:只有需要这个Bean时,才会进行实例化的操作。可以起到减少服务器压力的作用。
当scope="prototype"时,lazy-init属性会失效。
<bean id="" class="" scope="" lazy-init="" />
@Autowired与@Resource有什么区别:
本质上有很大区别。@Autowired为第三方包,按照类型在IOC容器中匹配。@Resource为官方包,可以设置name属性按照名称进行匹配、或按照类名查找、或按照类型进行查找,更智能。
1.5 AOP五种通知类型
面向切片编程,通知的作用就是对原有的程序进行扩展。
1. 前置通知 [Before]
2. 返回通知 [After returning]
3. 异常通知 [After throwing]
4. 后置通知 [After]
5. 环绕通知 [Around] 可实现上面所有通知。
切面类是用于对原始程序进行扩展的。所谓面向切面编程,最根本的用意是 在不修改原始程序的前提下,使用通知来对我们的程序进行扩展。
补全代码:
execution(* com.imooc.spring.aop.*Service.create*(..))说明AOP切面作用在哪些类的哪些方法上。
pointcut-ref="samplePC" returning="ret" 指向doAfterReturn的名为ret的参数,使用ret参数获取方法的返回值。
pointcut-ref="samplePC" throwing="t"
//5. 环绕通知
1.6 声明式事务
请介绍Spring的声明式事务
执行方法时,自动开启或者关闭事务的技术。
声明式事务是指利用AOP自动提交、回滚数据库事务。
声明式事务规则进入方法打开事务,成功提交,运行时异常回滚。
@Transactional是声明式事务的注解。
编程式事务不受欢迎。用代码方式 打开提交关闭事务。
注解放在类上时
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
@Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
public class UserService { }
2.1 SpringMVC开发REST风格Web程序
REST(表述性状态传递) 以URL表示要访问的资源。
REST风格只响应数据,通常是以JSON形式体现。
代码演示:
引入依赖
web.WEB-INF.web.xml
对于springMVC来说,最重要的核心servlet:DispatcherServlet。
SpringMVC项目文件结构:
main.resources.applicationContext.xml文件:
@Controller注解:
在IOC容器初始化的时候会自动的扫描所标注的类,进行加载。并且通知IOC容器这是一个MVC中的控制器。
@GetMapping("/emp/list/{DEPT}") 配合 @PathVariable("DEPT") String department
@RestController @ResponseBody 将return返回的数据直接输入到客服端。不然springMVC默认返回页面名称给前端。
2.2 SpringMVC拦截器的作用
SpringMVC拦截器用于对控制器方法进行前置、后置处理。
拦截器的底层实现技术是AOP(面向切面编程)
拦截器必须实现HandlerInterceptor接口
用途广泛:权限控制、登录拦截、字符集的管理国际化
代码实现:
resources.applicationContext.xml文件中增加:
拦截器类:
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response) {
//运行controller方法前先进入这个方法。
//如果返回false,请求会中断,postHandle也不再执行,afterCompletion会执行。
return true
}
public void postHandle(HttpServletRequest request, HttpServletResponse response) {
//controller方法执行完,试图渲染之前执行。controller方法得到结果但是还未返回时。
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response){
//前面两个方法执行完再执行。
}
}
2.3 SpringMVC的执行流程
请解释SpringMVC的执行流程
上图执行流程:从右上到左下。
HandlerMapping找符合请求路径的controller,交给DispatcherServlet实例化。
HandlerAdapter转换请求和响应中的数据。
ViewResolver的选择:FreeMarker、JSP。
3.1 说明MyBatis的开发过程
引入依赖
编写配置文件:resources.mybatis.xml
编写实体类,对应数据库字段。
编写映射器:resources.mapper.cmp.xml
编写程序主类:
public class MyBatisRunner {
public static void main(String[] args) {
//mybatis的配置文件
String resource = "mybatis.xml";
InputStream is = MyBatisRunner.class.getClassLoader().getResourceAsStream(resource);
//构建sqlSession的工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
String statement = "com.imooc.interview.mybatis.mapper.EmpMapper.findById";
SqlSession session = sessionFactory.openSession();
Employee employee = session.selectOne(statement, 7566);
session.close();
}
}
3.2 MyBatis的缓存机制
请介绍Mybatis的缓存机制:
缓存 把一些不太常变更的数据保存在内存中,或者高速的存储器上。从而降低查询数据时的时间以及提高程序执行的效率。
MyBatis存在两级缓存。
一级缓存与SqlSession会话绑定,默认开启。保存在内存中,每个SqlSession有一个巨大的hashMap。
二级缓存是应用全局缓存,所有SqlSession共享。
<mapper namespace="com.imooc.interview.mybatis.mapper.EmpMapper">
<cache size="512" eviction="FIFO/LRU/" flushInterval="60000" readOnly="true"/>
//size容纳多少个对象 eviction缓存清除策略 flushInterval多久一清理 readOnly只读,防止多个SqlSession操作数据。
//entity类要implements Serializable。
//增 删 改操作不要缓存。
<select id="findAll" resultType="com.imooc.interview.mybatis.entity.Employee" useCache="false">
select * from emp
</select>
<select id="findById" parameterType="int" resultType="com.imooc.interview.mybatis.entity.Employee" useCache="true">
select * from emp where empno = #{value}
</select>
</mapper>
4.1 Spring、SpringMVC与SpringBoot的区别
1. Spring是所有应用的基础,提供了IOC与AOP特性。轻松的对对象进行管理。
2. SpringMVC是Spring的子项目,用于提供Web支持。替代J2EE中的Servlet。底层上看SpringMVC的Controller也要被Spring IOC容器管理的。SpringMVC拦截器也使用了AOP特性,来对Controller的行为进行扩展与控制。
3. SpringBoot是Spring体系的敏捷开发框架,提高了开发效率。在传统体系下,Spring无论是注解也好,还是配置文件也罢,使用起来不轻松。SpringBoot使用市场上最优的模版来对Spring进行自动化配置以及自动化的处理。SpringBoot又扩展了很多实用的功能,以及默认的配置模版。
4.2 SpringBoot面试题
1. Spring Initializr是创建Spring Boot Projects的唯一方法吗?
不是唯一方法。本质上就是一个maven工程。
2. Spring boot支持几种配置文件?
Spring使用XML作为配置文件,Spring boot觉得XML太过笨重。目前只支持两种配置文件:属性文件properties,单行来描述要配置的选项,配置项很多的情况下会比较混乱 阅读性差;yml文件,按层级进行区分,这种格式对程序维护非常有帮助。
3. 请列举至少五个SpringBoot中的配置选项?
4.3 Maven的构建生命周期
考察你的maven的理解和常用命令的使用:
maven的生命周期包含7个步骤。