Java 面试题 MD
我的GitHub | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|
baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
Java 面试题
谈谈对Java多态的理解?
多态是指父类的某个方法被子类重写时,可以产生自己的功能行为,
同一个操作作用于不同对象,可以有不同的解释,产生不同的执行结果
。
多态的三个必要条件:
- 继承父类。
- 重写父类的方法。
父类的引用指向子类对象
。
静态方法与静态成员变量可以被继承吗,为什么?
静态方法与静态成员变量可以被继承
,但是不能被重写
。它对子类隐藏
,因此静态方法也不能实现多态
。
为什么Java里的匿名内部类只能访问final修饰的外部变量?
匿名内部类用法
public class TryUsingAnonymousClass {
public void useMyInterface() {
final Integer number = 123;
System.out.println(number);
MyInterface myInterface = new MyInterface() {
@Override
public void doSomething() {
System.out.println(number);
}
};
myInterface.doSomething();
System.out.println(number);
}
}
编译后的结果
class TryUsingAnonymousClass$1
implements MyInterface {
private final TryUsingAnonymousClass this$0;
private final Integer paramInteger;
TryUsingAnonymousClass$1(TryUsingAnonymousClass this$0, Integer paramInteger) {
this.this$0 = this$0;
this.paramInteger = paramInteger;
}
public void doSomething() {
System.out.println(this.paramInteger);
}
}
因为匿名内部类最终用会编译成一个单独的类
,而被该类使用的变量会以构造函数参数的形式传递给该类
,例如:Integer paramInteger,如果变量不定义成final的,paramInteger在匿名内部类被可以被修改,进而造成和外部的paramInteger不一致的问题
,为了避免这种不一致的情况,Java规定匿名内部类只能访问final修饰的外部变量。
讲一下Java的编码方式?
为什么需要编码
计算机存储信息的最小单元是
一个字节即8bit
,所以能表示的范围是0~255
,这个范围无法保存所有的字符,所以需要一个新的数据结构char
来表示这些字符,从char到byte需要编码。
常见的编码方式有以下几种:
ASCII
:总共有 128 个,用一个字节的低 7 位表示,0~31 是控制字符如换行回车删除等;32~126 是打印字符,可以通过键盘输入并且能够显示出来。GBK
:码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和GB2312
兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。
-UTF-16
:UTF-16 具体定义了Unicode
字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长
的表示方法,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。UTF-8
:统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长
技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 1~6 个字节组成
。
Java中需要编码的地方一般都在字符到字节
的转换上,这个一般包括磁盘IO和网络IO。
静态代理与动态代理区别是什么,分别用在什么样的场景里?
静态代理与动态代理的区别在于代理类生成的时间不同
,如果需要对多个类进行代理,并且代理的功能都是一样的,用静态代理重复编写代理类就非常的麻烦,可以用动态代理动态的生成代理类。
// 为目标对象生成代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");
// 执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务");
return null;
}
});
}
描述一下Java的异常体系?
- Error是程序
无法处理的错误
,比如OutOfMemoryError
、ThreadDeath
等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。 - Exception是程序本身
可以处理的异常
,这种异常分两大类,运行时异常和非运行时异常,程序中应当尽可能去处理这些异常。运行时异常都是RuntimeException
类及其子类异常,如NullPointerException
、IndexOutOfBoundsException
等,这些异常是不检查异常
,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生。
描述一个类的加载过程?
Person person = new Person()
- 查找
Person.class
,并加载到内存中。 - 执行类里的
静态代码块
。 - 在堆内存里开辟内存空间,并分配内存地址。
- 在堆内存里建立对象的属性,并进行
默认的初始化
。 - 对属性进行
显示初始化
。 - 对对象进行
构造代码块初始化
。 - 调用对象的
构造函数
进行初始化。 - 将对象的地址赋值给person变量。
Java对象的生命周期是什么?
加载
:将类的信息加载到JVM的方法区
,然后在堆区
中实例化一个java.lang.Class
对象,作为方法区中这个类的信息入口。连接
- 验证:验证类是否合法。
- 准备:为静态变量分配内存并设置JVM默认值,非静态变量不会分配内存。
- 解析:将常量池里的符号引用转换为直接引用。
初始化
:初始化类的静态赋值语句和静态代码块,主动引用会被触发类的初始化,被动引用不会触发类的初始化
。使用
:执行类的初始化,主动引用会被触发类的初始化,被动引用不会触发类的初始化。卸载
:卸载过程就是清除堆里类的信息,以下情况会被卸载:- 类的所有实例都已经被回收。
- 类的ClassLoader被回收。
- 类的CLass对象没有被任何地方引用,无法在任何地方通过反射访问该类。
描述一下类的加载机制?
类的加载就是虚拟机通过一个类的
全限定名
来获取描述此类的二进制字节流
,而完成这个加载动作。
类和类加载器息息相关,判定两个类是否相等,只有在这两个类被同一个类加载器加载的情况下才有意义
,否则即便是两个类来自同一个Class文件,被不同类加载器加载,它们也是不相等的。
注:这里的相等性包含Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果以及Instance关键字对对象所属关系的判定结果等。
类加载器可以分为三类:
- 启动类加载器(Bootstrap ClassLoader):负责加载
<JAVA_HOME>\lib
目录下或者被-Xbootclasspath
参数所指定的路径的,并且是被虚拟机所识别的库到内存中。 - 扩展类加载器(Extension ClassLoader):负责加载
<JAVA_HOME>\lib\ext
目录下或者被java.ext.dirs
系统变量所指定的路径的所有类库到内存中。 - 应用类加载器(Application ClassLoader):负责加载
用户类路径上的指定类库
,如果应用程序中没有实现自己的类加载器,一般就是这个类加载器去加载应用程序中的类库。
这么多类加载器,那么当类在加载的时候会使用哪个加载器呢?
这个时候就要提到类加载器的双亲委派模型
,流程图如下所示:
双亲委派模型的整个工作流程非常的简单:
如果一个类加载器收到了加载类的请求,
它不会自己立即去加载类,它会先去请求父类加载器
,每个层次的类加载器都是如此。层层传递,直到传递到最高层的类加载器,只有当父类加载器反馈自己无法加载这个类,才会由当前子类加载器去加载该类。
关于双亲委派机制,在ClassLoader源码里也可以看出,如下所示:
public abstract class ClassLoader {
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
//首先,检查该类是否已经被加载
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//先调用父类加载器去加载
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//ClassNotFoundException thrown if class not found from the non-null parent class loader
}
if (c == null) {
//如果父类加载器没有加载到该类,则自己去执行加载
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
}
}
return c;
}
}
为什么要这么做呢?
这是为了要让越基础的类由越高层的类加载器加载
,例如Object
类,无论哪个类加载器去尝试加载这个类,最终都会传递给最高层的类加载器去加载。前面我们也说过,类的相等性是由类与其类加载器共同判定的,这样Object类无论在何种类加载器环境下都是同一个类
。
相反如果没有双亲委派模型,那么每个类加载器都会去加载Object,那么系统中就会出现多个不同的Object类了,如此一来系统的最基础的行为也就无法保证了。
描述一下GC的原理和回收策略?
提到垃圾回收,我们可以先思考一下,如果我们去做垃圾回收需要解决哪些问题?
一般说来,我们要解决以下三个问题:
- 哪些内存回收?
- 什么时候回收?
- 如何回收?
这些问题分别对应着引用管理
和回收策略
等方案。
提到引用,我们都知道Java中有四种引用类型:
- 强引用:代码中普遍存在的,只要强引用还存在,垃圾收集器就不会回收掉被引用的对象。
- 软引用:SoftReference,用来描述还有用但是非必须的对象,
当内存不足的时候会回收这类对象
。 - 弱引用:WeakReference,用来描述非必须对象,弱引用的对象只能生存到下一次GC发生时,
当GC发生时,无论内存是否足够,都会回收该对象
。 - 虚引用:PhantomReference,一个对象是否有虚引用的存在,完全不会对其生存时间产生影响,
也无法通过虚引用取得一个对象的引用
,它存在的唯一目的是在这个对象被回收时可以收到一个系统通知
。
不同的引用类型,在做GC时会区别对待,我们平时生成的Java对象,默认都是强引用,也就是说只要强引用还在,GC就不会回收,那么如何判断强引用是否存在呢?
一个简单的思路就是:引用计数法
,有对这个对象的引用就+1,不再引用就-1。但是这种方式看起来简单美好,但它却不能解决循环引用计数
的问题。
因此可达性分析算法
登上历史舞台
Java 面试题 MD的更多相关文章
- 经典Java面试题收集(二)
经典的Java面试题(第二部分),这部分主要是与Java Web和Web Service相关的面试题. 96.阐述Servlet和CGI的区别? 答:Servlet与CGI的区别在于Servlet处于 ...
- 百度搜索 “Java面试题” 前200页(面试必看)
前言 本文中的题目来源于网上的一篇文章<百度搜索 "Java面试题" 前200页>,但该文章里面只有题目,没有答案.因此,我整理了一些答案发布于本文.本文整理答案的原则 ...
- java面试题,转载自http://www.cnblogs.com/nnngu/p/8471043.html#3914167
Java面试题库及答案解析 1.面向对象编程(OOP)有哪些优点? 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可靠性和灵活性. 增加代码的可理解性. 2.面向对象编程有哪些特性? 封 ...
- java面试题及答案(转载)
JAVA相关基础知识1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时 ...
- 115个Java面试题和答案——终极列表(下)
第一篇讨论了面向对象编程和它的特点,关于Java和它的功能的常见问题,Java的集合类,垃圾收集器,本章主要讨论异常处理,Java小应用程序,Swing,JDBC,远程方法调用(RMI),Servle ...
- Java面试题(全)
JAVA部分 什么是反射机制?反射机制应用(Struts中反射机制的应用) 答:运行状态中,对于任意一个类,都可以知道它的所有属性和方法,对于任意一个对象都可以调用它的任意一个方法,这种动态获取信息以 ...
- Java面试题大全(四)
JAVA代码查错 1. abstract class Name { private String name; public abstract boolean isStupidName(String n ...
- 大公司的Java面试题集
找工作要面试,有面试就有对付面试的办法.以下一些题目来自我和我朋友痛苦的面试经历,提这些问题的公司包括IBM, E*Trade, Siebel, Motorola, SUN, 以及其它大小公司. 面试 ...
- 收集了50道基础的java面试题
下面的内容是对网上原有的Java面试题集及答案进行了全面修订之后给出的负责任的题目和答案,原来的题目中有很多重复题目和无价值的题目,还有不少的参考答案也是错误的,修改后的Java面试题集参照了JDK最 ...
随机推荐
- jsonp原理和实例详解
1.一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面.动态网页.web服务.WCF,只要是跨域请求,一律不准:2.不过我们又发现,Web页面上调用js文件时则不受 ...
- LeetCode(38): 报数
Easy! 题目描述: 报数序列是指一个整数序列,按照其中的整数的顺序进行报数,得到下一个数.其前五项如下: 1. 1 2. 11 3. 21 4. 1211 5. 111221 1 被读作 &qu ...
- js获取当前有效样式
js获取有效样式 节点.currentStyle["属性名"] 兼容ie方法(只有ie有效) getcomputedStyle(节点)["属性名&q ...
- python 全栈开发,Day115(urlencode,批量操作,快速搜索,保留原搜索条件,自定义分页,拆分代码)
今日内容前戏 静态字段和字段 先来看下面一段代码 class Foo: x = 1 # 类变量.静态字段.静态属性 def __init__(self): y = 6 # 实例变量.字段.对象属性 # ...
- 购物车的实现(jsp的session+Java的Map的结合)
1:电商如此发达的现在,作为一个web开发程序猿,如果不会写购物车,真是有点不好意思找工作.所以抓紧练习啊,从上篇博客中抽离出如何实现购物车的功能. 2:首先需要理解购物车实现的一些基本步骤. 2.1 ...
- Oracle回收站的清理方法
http://blog.itpub.net/18841027/viewspace-1057765/
- day8--socket回顾
后面学习了线程.协成和异步,它们的框架都是基于socket的协议,基本原理都是一样的,现在把这几个模块重温一下,尽量掌握这些知识更全面一些. 动态导入模块,知道知道模块名,可以像反射一样,使用字符串来 ...
- 安装oracle11g时遇到INS-13001环境不满足最低要求
在安装oracle11g,点击setup.exe之后,弹出了如下提示框: 解决方法: 首先,打开你解压后的database文件夹,找到stage,然后cvu,找到cvu_prereq.xml文件,用记 ...
- 【Java】 剑指offer(51)数组中的逆序对
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成 ...
- 动态产生DataSource------待整理
1. https://www.cnblogs.com/wsss/p/5475057.html https://www.cnblogs.com/jiligalaer/p/5418874.html htt ...