从零开始-JAVA
JAVA是安卓的应用和框架层的核心,面试也常常提及,是安卓的基础,地基建好后等待OFFER大楼的只差施工了
- 基础语法
- 集合框架
- 线程相关
- IO相关
- 设计模式
- JAVA虚拟机
基础语法
-
1.switch能否用String类型做参数?
答:可以,在java7中添加了对String支持,之前不行.tips:不支持double,float,boolean -
2.重载和重写的区别?
答:重载体现了JAVA中的多态性,允许存在同名函数,只要满足参数类型不同
重写是子类对父类方法的一种覆盖,保留父类的方法,子类定义自己的方法实现
-
-
3.java四个基本特性的面试题
-
( 封装 多态 抽象 继承)
-
抽象类和接口的区别?(抽象)
答:语法上:
抽象类可以有具体实现的方法而接口的方法全部抽象
一个类只能继承一个抽象类,但是可以实现多个接口
接口不能有静态的代码块和方法,抽象类可以有
设计上:
抽象类更像一种模板的设计,接口是一种行为的规范 -
JAVA多态实现原理
多态:同一消息根据发送目的的变换而采取多种不同的行为方式
原理:动态绑定,在运行期动态识别找到合适的方法
-
-
-
4.equals与==的区别?
答:基本数据类型,都是比较值是否相等
引用数据类型,equals比较两个对象指向的内存空间的值是否相等,==比较指向的内存空间地址是否相同
tips:equals被String类重写所以判断的是字符串是否相等 -
5.Hashcode方法的作用和equals的区别?
答:hashcode()返回的是对象内存地址通过哈希算法得到的整数值,
多出现于集合中判断其中是否有相同的元素,当往HashMap中添加元素时,会先用hashcode判断是否同一个元素,若不相同再用equals判断内容
-
6.String、StringBuffer与StringBuilder的区别?
答:
String 不可变 适用场景:少数据量
StringBuffer可变 线程安全 适用场景:多线程大数据量
StringBuilder可变 线程不安全 适用场景:单线程大数据量
底层是Char[]数组实现的 -
7.final, finally, finalize的区别?
答:final是修饰符 被修饰的成员无法被继承无法被覆盖无法被修改成员
finally语句块 多用于异常处理最后的收尾操作
finalize对象被垃圾回收期回收的时候会调用这个方法 -
8.JAVA的四种引用类型,用到的场景
答:
1.强引用:不会被垃圾回收期回收,即使JVM内存不足会出现崩溃报错也不会被回收,我们经常new一个对象这个就是强引用,若要中断这种引用,可以显式的将对象赋值为null
2.软引用:当JVM内存不足时会回收,足够不回收
3.弱引用:被垃圾回收器发现就会被回收 通常可以用在图片的缓存上
4.虚引用:随时都有可能被回收 -
9.说说java的反射机制原理以及应用场合?
答:反射机制即在运行过程中,
对于任意一个类,可以得到这个类的所有属性和方法
对于任意一个对象,可以调用它任意的方法和属性
-
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
出现场景:GSON的序列化和反序列化等,使用源码中一些被hide注解的方法 (重要的基础: 类对象: 封装了类的描述信息的对象,类加载的产物,由jvm创建java.lang.Class 获取类对象的方式: 1.类名.class 2. 类的对象.getClass() 3. Class.forName("包名.类名"))
集合框架
-
1.Collection 和 Collections的区别?
答:Collection是集合的接口,实现它的主要有set和list
Collections是集合的一个帮助类,能帮助排序,搜索,线程安全化等操作 -
2.ArrayList、LinkedList、Vector的区别?
答:ArrayList和Vector底层是由数组实现的,而LinkedList底层是由双向链表实现
Vector在线程安全性上高于ArrayList和LinkedList但代价是效率上变慢
-
ArrayList因为在连续的空间中用序号标记位置,索引快,增删需要涉及元素移动,
LinkedList存在于独立的空间,对象间保存下一个的索引,增删只用记录本项的前后项即可,增删快,查询需要遍历,查询慢 -
3.HashMap,HashTable的区别?(附加:ConcurrentHashMap)
答:HashMap实现的是Map接口而HashTable实现Map接口的同时继承Directory类
HashMap效率高但线程不安全,HashTable效率低但线程安全
HashMap的key和value都可以为null而HashTable不可以
ConcurrentHashMap是线程安全的hashmap并不是像HashTable一样每个方法加同步锁
他将map分成了几个类似于HashTable的有锁segment分段,put和get时根据hashcode值判断在哪个分段进行,安全性上高,性能也高 -
4.HashMap,HashSet的区别?
答:HashMap实现是Map接口,HashSet实现Set接口
HashMap存储方式-键值对,HashSet存储对象
HashMap由键的HashCode来判断地址是否重复
HashSet存储对象也是通过HashMap的add键值对,但是键为对象,值为HashSet自身,
因为HashMap是允许重复值的所以我们需要重写HashCode和equals判断是否唯一,若相同返回false -
5.HashMap的底层源码实现
答:我们增加一组元素时,会根据输入的key值的hashcode计算hash值,根据哈希值得到元素所在数组下标
,如果这个位置再数组上有其他元素,以链表形式加入到头部,最先进入的在尾部,如果下标位置没有其他元素就将元素放在这个位置上
从上面的源代码中可以看出:当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
- 6.Fail-Fast机制概述答:在使用Iterator迭代器的时候,有其他线程修改了map,将会抛出ConcurrentModificationException(并发修改异常).
源码中:Iterator初始化时会将map的modCount修改次数赋值给expectedModCount,
在迭代中判断modCount和expectedModCount是否相等,若不相等就表名修改了map报错7.LinkedHashSet和HashTable的原理?
LinkedHashSet底层是用LinkedHashMap实现但又有HashSet(不重复)的特点
LinkedHashMap底层原理 是Entry[]数组,而Entry又是一个双向链表HashTable原理 是安全的HashMap HashMap底层原理 是Entry数组 而Entry是个单链表
线程相关
-
1.线程和进程的区别?
答:
进程是系统资源分配的基本单位
线程是CPU资源调度的基本单位
线程是进程内的一个执行单元,也是一个可调度的实体
进程内的多个线程共享这个进程内的所有资源
线程之间协同工作需要借助消息通信 -
2.什么是线程池,线程池的作用是什么?
答:
线程池是对线程的一种封装,开辟一块内存区域,批量放入线程,由池管理器统一调度,当有线程任务,从池子取出,执行完再放回线程池中
作用:能提高线程的复用性,减少线程对象的创建,节约开销
能有效的控制并发线程,提高资源使用率,避免堵塞
提供了定期执行,定时执行,控制线程并发数等功能
-
3.JAVA如何创建线程?
答:
1.继承Thread类 再new
2.实现Runnable接口再将其作为参数传入Thread类的构造方法中 再new
3.实现Callable接口 -
4.用户线程和守护线程有什么区别?
答:用户线程是我们开发者创建的线程,守护线程是服务于用户线程的且与JVM一同关闭退出的的线程 例如:GC线程 -
5.wait()和sleep()的区别?
答:wait方法属于Object类 而Sleep方法属于Thread类
JAVA中每个对象都有对象锁,当调用wait方法时会将这个锁释放其他线程有机会争抢这个锁,系统会将这个对象的资源空间让出,等待调用notify或notifyall方法后再得到这个锁执行任务
而sleep方法并没有释放掉对象锁,其他线程无法获得,一直保持这个对象的监控,当时间到时再执行任务 -
6.JAVA多线程同步的方法?
答:1.同步代码块
2.同步方法
3.使用volatile修饰
4.使用重入锁(ReenreantLock)是对synchronized的扩展
5.使用ThreadLocal类管理共享变量,这样每个访问得线程都有这个变量副本可以随意修改 -
7.什么是线程调度器和时间分片?
答:线程调度器是为Runnable状态的线程分配CPU时间,线程的启动依赖于线程调度器
时间分片是指将cpu时间分配给线程的过程,可以基于线程优先级和等待时间分配 -
8.Synchronzied和Lock的区别?
答:Synchronized是隐式锁 Lock是显式锁
-
Synchronized是托管给JVM,Lock是代码控制需要自己开启和关闭
JAVA6之后Synchronized被又优化了导致与lock性能上相差不大
Synchronized采用悲观锁机制,独占锁而Lock是乐观锁的机制,假设没有冲突出现错误重试,直到成功
IO相关
-
-
- 1.JAVA序列化,如何实现序列化和反序列化?
答:序列化:实现Seralizable接口
反序列化:实现Externalizable接口
Java虚拟机
- 1.JVM内存模型以及分区,需要详细到每个区放什么
答:JVM首先分为两个部分线程私有内存区,线程共享内存区
线程共享内存区:方法区(里面有常量池),堆
线程私有内存区:PC程序寄存器,本地方法栈,虚拟机栈
方法区:涉及到类加载的时候,加载进来的类的信息,常量,字段,方法代码等的信息
常量池:方法区的一部分,其中存储的是,字面常量,符号引用等
堆:为对象分配内存
PC程序寄存器:记录正在运行虚拟机字节码的地址
本地方法栈:虚拟机原生方法执行的内存区域
虚拟机栈:方法执行的区域,每个方法执行时会创建栈帧,其中记录着局部变量表,方法返回地址等信息- 2.JAVA中堆和栈的区别?
答:都是数据结构
堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全树。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。堆用来存储对象,栈用来存储局部变量,执行方法
堆是线程共享的,栈是线程私有的
-
3.介绍下Java GC机制
答:GC即垃圾收集,负责回收所有不可达的对象的内存空间
原理:采用有向图的方式记录和管理堆中的所有对象,判断是否可达 -
4.GC怎么确定某个对象是垃圾?
(1)引用计数法:将一个对象的引用关联计数保存,当引用次数为0则释放
缺陷:无法解决循环引用问题 A-B相互引用永远不为0,无法回收(2)对象引用遍历(现在大多数 jvm 使用的方法):
从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集- 5.java GC是在什么时候,对什么东西,做了什么事情(精华)?
什么时候:
堆内存分为新生代,老年代
新生代分为Eden,Survival from,Survival to 当Eden内存满了发生Minor GC
当升到老年代的对象大于老年代的剩余内存会发生FullGC将清理整个堆空间对什么东西:对象引用遍历中,通过遍历对象图从根对象开始,不可达的对象
什么事情:垃圾回收器根据不同的算法进行对象的回收
在年轻代中Survival from,Survival to 使用了复制清理算法
具体实现:将Eden和Survival from中的存活的对象赋值到Survival to
然后将前面两个区域对象全部清除,不会产生碎片在老年代中GC使用标记清理算法
具体实现:先进行一次遍历将可达的标记,第二次遍历不可达的清理
会产生碎片-内存空间不连续
碎片整理:- 6.GC的种类?
1.基于引用计数算法的GC 有对象引用+1,引用完毕-1
2.基于跟踪收集的GC 从根对象开始遍历对象图,记录可达和不可达的
3.基于对象跟踪分代收集的GC 将JVM堆中根据对象存活时间分段-年轻代,老年代,永久代
在不同的分段采取不同的垃圾回收算法
Java有四种类型的垃圾回收器:
串行垃圾回收器(Serial Garbage Collector)
并行垃圾回收器(Parallel Garbage Collector)
并发标记扫描垃圾回收器(CMS Garbage Collector)
G1垃圾回收器(G1 Garbage Collector)
设计模式
设计模式即代码的写法,如何才能写出高质量的代码的总结
- 1.单例模式:一个类只有一个实例,并将其向全局提供
懒汉式:将实例放入静态方法中
饿汉式 将实例放在成员中private static MyClass myClass=null; private MyClass() {} public static MyClass getInstance(){ if(myClass==null){ myClass=new MyClass(); } return myClass; }
- 1.JAVA序列化,如何实现序列化和反序列化?
-
private static final MyClass myClass=new MyClass(); private MyClass() {} public static MyClass getInstance(){ return myClass; }
登记式:通过map实现(仅了解)
优化安全问题的单例-双重检查锁定
-
private static volatile MyClass myClass=null;//第一重锁定 private MyClass() {} public static MyClass getInstance(){ if(myClass==null){//第一重检查 synchronized (MyClass.class){//第二重锁定 if(myClass==null){//第二重检查 myClass=new MyClass(); } } } return myClass; }
- 2.工厂模式:实例化对象的模式,用自己的工厂方法代替new,批量生产对象的模式
简单工厂模式(Simple Factory) 缺点:增加产品需要修改工厂代码,违背开闭原则
工厂方法模式(Factory Method) 改进:只需生成无需修改public class Factory { public BMW createBMW(int type) { switch (type) { case 320: return new BMW320(); case 523: return new BMW523(); default: break; } return null; } }
-
interface BMWFactory {//创建工厂接口 BMW createBMW(); } class BMW320Factory implements BMWFactory{//创建不同的工厂 @Override public BMW createBMW() { return new BMW320(); } } class BMW523Factory implements BMWFactory{ @Override public BMW createBMW() { return new BMW523(); } }
抽象工厂模式(Abstract Factory) 更加抽象
产品抽象
工厂抽象public interface Engine {//创建发动机 } class EngineA implements Engine { public EngineA(){ System.out.println("制造-->EngineA"); } } class EngineB implements Engine { public EngineB(){ System.out.println("制造-->EngineB"); } } //空调以及型号 interface Aircondition { } class AirconditionA implements Aircondition{ public AirconditionA(){ System.out.println("制造-->AirconditionA"); } } class AirconditionB implements Aircondition{ public AirconditionB(){ System.out.println("制造-->AirconditionB"); } }
-
//创建工厂的接口 public interface AbstractFactory { //制造发动机 public Engine createEngine(); //制造空调 public Aircondition createAircondition(); } //为宝马320系列生产配件 public class FactoryBMW320 implements AbstractFactory{ @Override public Engine createEngine() { return new EngineA(); } @Override public Aircondition createAircondition() { return new AirconditionA(); } } //宝马523系列 public class FactoryBMW523 implements AbstractFactory { @Override public Engine createEngine() { return new EngineB(); } @Override public Aircondition createAircondition() { return new AirconditionB(); } }
- 3.适配器模式
类适配器:创建adapter类继承需要实现特殊功能的类并实现规范接口,即可转型调用
对象适配器 在适配器中关联类public interface Target { public void request();//标准接口 } // 具体目标类,只提供普通功能 class ConcreteTarget implements Target { public void request() { System.out.println("putong"); } } // 用户需要的类具有特殊功能 class Adaptee { public void specificRequest() { System.out.println("teshu"); } } class Adapter extends Adaptee implements Target{ @Override public void request() { specificRequest(); } } class Client { public static void main(String[] args) { // 使用普通功能类 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 使用特殊功能类,即适配类 Target adapter = new Adapter(); adapter.request(); } }
- 3.适配器模式
-
// 适配器类,直接关联被适配类,同时实现标准接口 class Adapter implements Target{ // 直接关联被适配类 private Adaptee adaptee; // 可以通过构造函数传入具体需要适配的被适配类对象 public Adapter (Adaptee adaptee) { this.adaptee = adaptee; } public void request() { // 这里是使用委托的方式完成特殊功能 this.adaptee.specificRequest(); } } // 测试类 public class Client { public static void main(String[] args) { // 使用普通功能类 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 使用特殊功能类,即适配类, // 需要先创建一个被适配类的对象作为参数 Target adapter = new Adapter(new Adaptee()); adapter.request(); } }
-