1 . 请描述JVM加载class文件的原理机制?
在面试java工程师的时候,这道题经常被问到,故需特别注意。
Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。
Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。
Java的类加载器有三个,对应Java的三种类:
Bootstrap Loader // 负责加载系统类
|
- - ExtClassLoader // 负责加载扩展类(就是继承类和实现类)
|
- - AppClassLoader // 负责加载应用类(程序员自定义的类)
三个加载器各自完成自己的工作,但它们是如何协调工作呢?哪一个类该由哪个类加载器完成呢?为了解决这个问题,Java采用了委托模型机制。
委托模型机制的工作原理很简单:当类加载器需要加载类的时候,先请示其Parent(即上一层加载器)在其搜索路径载入,如果找不到,才在自己的搜索路径搜索该类。这样的顺序其实就是加载器层次上自顶而下的搜索,因为加载器必须保证基础类的加载。之所以是这种机制,还有一个安全上的考虑:如果某人将一个恶意的基础类加载到jvm,委托模型机制会搜索其父类加载器,显然是不可能找到的,自然就不会将该类加载进来。
我们可以通过这样的代码来获取类加载器:
ClassLoader loader = ClassName.class.getClassLoader();
ClassLoader ParentLoader = loader.getParent();复制代码
注意一个很重要的问题,就是Java在逻辑上并不存在BootstrapKLoader的实体!因为它是用C++编写的,所以打印其内容将会得到null。
前面是对类加载器的简单介绍,它的原理机制非常简单,就是下面几个步骤:
1.装载:查找和导入class文件;
2.连接:
(1)检查:检查载入的class文件数据的正确性;
(2)准备:为类的静态变量分配存储空间;
(3)解析:将符号引用转换成直接引用(这一步是可选的)
3.初始化:初始化静态变量,静态代码块。
这样的过程在程序调用类的静态成员的时候开始执行,所以静态方法main()才会成为一般程序的入口方法。类的构造器也会引发该动作。
2 . Java中存在内存泄漏吗,请描述你所了解的内存泄漏场景和解决方案?
存在,比如写一段程序使用递归的方法打印1到1百万之间的正整数,由于递归调用,这时候内存就会爆掉,发生内存泄漏,原因是递归调用1百万次需要分配1百万的内存空间,这时候计算机是没有这么大的空间的,解决方式就是采用其他的算法,避免算法的空间复杂度S(n)过大。
其他比如全局集合,缓存,类装载器都会发生内存泄漏。
关于内存泄漏的详细内容请看我的博客:
3 . synchronized关键字的用法,类锁和对象所的区别?
答案见公众号基础知识专题-多线程
4 . 在进行数据库操作时,连接池所起到的作用,如果你要实现一个连接池,你会考虑哪些方面?
由于创建连接和释放连接都有很大的开销(尤其是数据库服务器不在本地时,每次建立连接都需要进行TCP的三次握手,释放连接需要进行TCP四次握手,造成的开销是不可忽视的),为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接,从而避免频繁创建和释放连接所造成的开销,这是典型的用空间换取时间的策略(浪费了空间存储连接,但节省了创建和释放连接的时间)。
5 . 在javaweb工程中,web.xml可配置哪些内容?
在java工程中,web.xml用来初始化工程配置信息,比如说welcome页面,filter,listener,servlet,servlet-mapping,启动加载级别等等。
6 . 什么是ORM,简单描述你所了解的ORM持久层框架以及它们的区别?
Object Relational Mapping,对象-关系映射。
7 . 简单描述下你所了解的AOP切面,以及spring aop的常见用法?
答案见公众号基础专题-框架
8 . 什么是NOSQL,请简单描述下你所了解的NOSQL数据库?
9 . 简单介绍下什么是SQL注入攻击,XSS攻击,CSRF工具,如何避免这些问题?
所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。
比如在登录界面,如果用户名填入 'xxx'OR1=1--
就能构造下面的SQL语句,因为OR 1=1,password被注释掉,因此无论name和password填入什么都能登录成功。
select * from user name = 'xxx' or 1=1 -- and password = 'xxx'复制代码
使用PrepareStatement,可以防止sql注入攻击,sql的执行需要编译,注入问题之所以出现,是因为用户填写 sql语句参与了编译。使用PrepareStatement对象在执行sql语句时,会分为两步,第一步将sql语句 "运送" 到mysql上预编译,再回到java端拿到参数运送到mysql端。预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该sql语句的语法结构了。用户填写的 sql语句,就不会参与编译,只会当做参数来看。从而避免了sql注入问题。
所谓XSS攻击,是向网页中注入恶意脚本在用户浏览网页时在用户浏览器中执行恶意脚本的攻击方式。
所谓CSRF攻击是攻击者通过跨站请求,以合法的用户身份进行非法操作(如转账或发帖等)。CSRF的原理是利用浏览器的Cookie或服务器的Session,盗取用户身份。
10 . 简单描述你所使用的js框架,以及各自的优缺点?
jquery,node.js
11 . 你所了解的设计模式,在开发中如何看到设计模式的使用?
12 . 能不能简单描述一下你在java web开发中需要用到多线程编程的场景?
最典型的应用比如tomcat,tomcat内部采用的就是多线程,上百个客户端访问同一个web应用,tomcat接入后都是把后续的处理扔给一个新的线程来处理,这个新的线程最后调用到我们的servlet程序,比如doGet或者doPost方法。
一个业务逻辑有很多次的循环,每次循环之间没有影响,比如验证1万条url路径是否存在,正常情况要循环1万次,逐个去验证每一条URL,这样效率会很低,假设验证一条需要1分钟,总共就需要1万分钟,有点恐怖。这时可以用多线程,将1万条URL分成50等份,开50个线程,没个线程只需验证200条,这样所有的线程执行完是远小于1万分钟的
作者:junxia
如果您认为阅读这篇博客让您有些收获,欢迎扫描下方二维码关注我们,与我们交流互动。
本公众号专注Java面试题目的收集和解析以及【Web小项目】源码的分享,