总结我看到的面经或者我面试中遇到的问题(包含答案)
拿到美团的意向,我的秋招也结束了,虽然比不上各位大佬的offer,但我也满足了。在很多地方看了很多面经,为了反馈广大牛友,现在将我所有复习的知识点总结如下(包含答案,这都是我自己理解的答案,有不对的,欢迎大家指出)。
东西太多了,短期内肯定写不完,我会持续更新。
分割线------------------------------------------------
1.JVM有哪些分区
程序计数器,Java虚拟机栈,本地方法栈,堆,方法区(Java栈中存放的是一个一个的栈帧,每一个栈帧对应一个被调用的方法。栈帧包括局部变量表,操作数栈,方法的返回地址,指向当前方法所属的类的运行时常量池的引用,附加信息)。JVM中只有一个堆。方法区中最重要的是运行时常量池。
2.GetVSPost
get提交的信息显示在地址栏 不安全 对大数据不行(因为地址栏存储体积有限) 获取/查询资源
Post 提交的信息不显示在地址栏 安全 对大数据可以 更改信息
3.URL中可以存在中文吗?
A:可以,先将中文进行编码,tomcat默认解码为iso8859-1,这样就会出现乱码,我们可以再用iso8859-1进行编码,再用指定码表解码(post和get都可以)。对于post,可以使用requset的setCharacterEncodeing方法设置指定的解码表。
4.mysql使用的引擎?
A:1)MyIsam 不支持事务,适用于选择密集型,插入密集型,mysql默认的引擎
2)innodb 使用于更新密集型,支持事务,自动灾难恢复,行级锁,外键约束
3)memory 出发点是速度 采用的逻辑存储介质是内存
4)merge 一组myisam表的组合
5.线程池ThreadPoolExecutor
corepoolsize:核心池的大小,默认情况下,在创建了线程池之后,线程池中线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中线程数达到corepoolsize后,就把任务放在任务缓存队列中。
Maximumpoolsize:线程池中最多创建多少个线程。
Keeplivetime:线程没有任务执行时,最多保存多久的时间会终止,默认情况下,当线程池中线程数>corepoolsize时,Keeplivetime才起作用,直到线程数不大于corepoolsize。
workQueue:阻塞队列,用来存放等待被执行的任务
threadFactory:线程工厂,用来创建线程。
继承关系
Executor 接口
ExecutoServicer 接口
AbstractExecutoServicer 抽象类
ThreadPoolExecutor
线程池的状态
1.当线程池创建后,初始为running状态
2.调用shutdown方法后,处shutdown状态,此时不再接受新的任务,等待已有的任务执行完毕
3.调用shutdownnow方法后,进入stop状态,不再接受新的任务,并且会尝试终止正在执行的任务。
4.当处于shotdown或stop状态,并且所有工作线程已经销毁,任务缓存队列已清空,线程池被设为terminated状态。
当有任务提交到线程池之后的一些操作:
1.若当前线程池中线程数<corepoolsize,则每来一个任务就创建一个线程去执行。
- 若当前线程池中线程数>=corepoolsize,会尝试将任务添加到任务缓存队列中去,若添加成功,则任务会等待空闲线程将其取出执行,若添加失败,则尝试创建线程去执行这个任务。
- 若当前线程池中线程数>= Maximumpoolsize,则采取拒绝策略(有4种,1)abortpolicy 丢弃任务,抛出RejectedExecutionException 2)discardpolicy 拒绝执行,不抛异常3)discardoldestpolicy 丢弃任务缓存队列中最老的任务,并且尝试重新提交新的任务 4)callerrunspolicy 有反馈机制,使任务提交的速度变慢)。
6.现在需要测试系统的高并发性能,如何模拟高并发?
使用cyclicbarrier,cyclicbarrier初始化时规定一个数目,then计算调用了cyclicbarrier.await()进入等待的线程数,当线程数达到这个数目时,所有进入等待状态的线程将被唤醒并继续。Cyclic就像他的名字一样,可看成是一个屏障,所有线程必须到达后才可以一起通过这个屏障。
7、linux查看文件内容的命令
Cat:从第一行开始显示内容,并将所有内容输出
Tac:从最后一行开始显示内容,并将所有内容输出
Head:只显示前几行
Tail:只显示后几行
nl:和cat一样,只是nl要显示行号
8.jdk1.8bin目录下的东西
Java.exe javac.exe Javadoc.exe jar.exe jstack.exe (打印所有java线程堆栈跟踪信息)
9.生产者-消费者代码-用blockingqueue实现
查日志
当类被加载如内存后,jvm就知道。JVM可以通过普通java对象的元数据信息确定java对象的大小。
对象是否存活
1)引用计数法缺点:很难解决对象之间循环引用的问题。
2)可达性分析法基本思想:通过一系列的称为“GC roots”的对象作为起始点,从这些节点,开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC root没有任何引用链相连(用图论的话来说,就是从GC roots到这个对象不可达),则证明此对象是不可用的。
可作为GC roots 的对象
1)java虚拟机栈(栈帧中的本地变量表)中引用的对象
2)方法区中类的静态属性引用的对象
3)方法区中常量引用的对象
4)本地方法栈中JNI引用的对象
引用强度强引用>软引用>弱引用>虚引用
任何一个对象的finalize()方法都只会被系统调用一次
若对象在进行可达性分析后发现没有与GC roots相连接的引用链,那么他将会被第一次标记并进行一次筛选,筛选的条件是该对象是否有必要执行finalize()方法,当对象没有重写finalize()方法或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为没必要执行。
若该对象被判定为有必要执行finalize方法,则这个对象会被放在一个F-Queue 队列,finalize方法是对象逃脱死亡命运的最后一次机会,稍后GC 将对F-queue中的对象进行第二次小规模的标记,若对象要在finalize中成功拯救自己—只要重新与引用链上的任何一个对象建立关联即可,那么在第二次标记时他们将会被移出“即将回收”集合。
Finalize方法不是c或c++的析构函数。
类需要同时满足下面3个条件才是“无用的类”:
1.该类的all实例都已经被回收
2.加载改类的classloader已经被回收
3.该对象的java.lang.class对象没有在任何地方被引用,无法再任何地方通过反射访问该类的方法。
永久的的垃圾回收主要回收废弃常量和无用的类。
停止-复制算法:它将可用内存按照容量划分为大小相等的两块,每次只使用其中一块。当这一块的内存用完了,则就将还存活的对象复制到另一块上面,然后再把已经使用过的内存空间一次清理掉。商业虚拟机:将内存分为一块较大的eden空间和两块较小的survivor空间,默认比例是8:1:1,即每次新生代中可用内存空间为整个新生代容量的90%,每次使用eden和其中一个survivour。当回收时,将eden和survivor中还存活的对象一次性复制到另外一块survivor上,最后清理掉eden和刚才用过的survivor,若另外一块survivor空间没有足够内存空间存放上次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代。
标记-清除算法:缺点1)产生大量不连续的内存碎片2)标记和清除效率都不高
标记-清理算法:标记过程和“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清除,而是让all存活对象都向一端移动,然后直接清理掉端边界以外的内存。
分代收集:新生代停止-复制算法 老年代标记-清理或标记-清除
垃圾收集器,前3个是新生代,后3个是老年代
1)serial收集器:单线程(单线程的意义不仅仅说明它会使用一个cpu or 一条垃圾收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集的时候,必须暂停其他all工作线程,直到他收集结束)。对于运行在client模式下的虚拟机来说是个很好的选择。停止-复制
2)parNew搜集器:serial收集器的单线程版本,是许多运行在server模式下的虚拟机首选的新生代收集器。停止-复制
3)parallel scaverge:目标达到一个可控制的吞吐量,适合在后台运算,没有太多的交互。停止-复制。
4)serial old:serial 的老年代版本,单线程,标记-清理
5)parallel old:parallel scaverge老年代的版本,多线程标记-清理
6)cms收集器:一种以获取最短回收停顿时间为目标的收集器“标记-清除”,有4个过程初始标记(查找直接与gc roots链接的对象)并发标记(tracing过程)重新标记(因为并发标记时有用户线程在执行,标记结果可能有变化)并发清除 其中初始标记和重新标记阶段,要“stop the world”(停止工作线程)。优点:并发收集,低停顿缺点:1)不能处理浮动垃圾 2)对cpu资源敏感 3)产生大量内存碎片{每一天具体的详解请看《深入理解Java虚拟机:JVM高级特性与最佳实践》}
对象的分配:1)大多数情况下,对象在新生代eden区中分配,当Eden区中没有足够的内存空间进行分配时,虚拟机将发起一次minor GC {minor gc:发生在新生代的垃圾收集动作,非常频繁,一般回收速度也比较快 full gc:发生在老年代的gc} 2)大对象直接进入老年代 3)长期存活的对象将进入老年代 4)若在survivor空间中相同年龄all对象大小的总和>survivor空间的一半,则年龄>=改年龄的对象直接进入老年代,无须等到MaxTeuringThreshold(默认为15)中的要求。
空间分配担保
1)双重检测
3)静态内部类的
14.Out of Memory
1.程序计数器是唯一一个在Java虚拟机规范中没有规定任何oom情况的区域。
2.在java虚拟机规范中,对于java虚拟机栈,规定了2中异常,1)若线程请求的栈深度>虚拟机所允许的深度,则抛出Stack Overflowerror异常2)若虚拟机可以动态扩展,若扩展时无法申请到足够的内存空间,则抛出oom异常。
3.java虚拟机栈为执行java方法,本地方法栈为虚拟机使用native方法服务,本地方法栈也会抛出Stack Overflowerror和oom。
4.Java堆可以处于物理上连续的内存空间,只要逻辑上是连续的即可。可固定,可扩展。若堆中没有内存完成实例分配,并且堆也无法再扩展,则会抛出oom。
17.对象的访问方式
1)句柄访问,堆中有一个句柄池,reference中存放的是对象的句柄地址,句柄中包含了对象实例数据与类型数据各自的具体地址信息。
18.Java内存模型和线程
每个线程都有一个工作内存,线程只可以修改自己工作内存中的数据,然后再同步回主内存,主内存由多个内存共享。
下面8个操作都是原子的,不可再分的:
1)lock:作用于主内存的变量,它把一个变量标识为一个线程独占的状态。
2)unlock:作用于主内存的变量,他把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
3)read:作用于主内存变量,他把一个变量的值从主内存传输到线程的工作内存,以便随后的load操作使用。
4)load:作用于工作内存的变量,他把read操作从主内存中得到的变量值放入工作内存的变量副本中。
5)use:作用于工作内存的变量,他把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值得字节码指令时将会执行这个操作。
6)assign:作用于工作内存的变量,他把一个从执行引擎接收到的值付给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
7)store:作用于工作内存的变量,他把工作内存中一个变量的值传送到主内存中,以便随后write使用。
8)write:作用于主内存的变量,他把store操作从工作内存中得到的变量的值放入主内存的变量中。
关键字volatile是轻量级的同步机制。
Volatile变量对于all线程的可见性,指当一条线程修改了这个变量的值,新值对于其他线程来说是可见的、立即得知的。
19.线程的状态
在任意一个时间点,一个线程只能有且只有其中的一种状态
1)新建:创建后尚未启动的线程处于这种状态。
2)运行:包括了OS中Running和Ready状态,也就是处于次状态的线程可能正在运行,也可能正在等待cpu为他分配执行时间。
3)无限期等待:处于这种状态的线程不会被分配cpu执行时间,要等待其他线程显示唤醒。以下方***让线程进入无限期等待:1.没有设置timeout的object.wait()方法 2.没有设置timeout参数的Thread.join()方法3.LockSupport.park();
4)有限期的等待:处于这种状态的线程也不会被分配cpu执行时间,不过无需等待被其他线程显示唤醒,而是在一定时间后,他们会由os自动唤醒 1.设置了timeout的object.wait()方法 2.设置了timeout参数的Thread.join() 3.LockSupport.parkNanos() 4.LockSupport.parkUnit()
5)阻塞:线程被阻塞了与“等待状态”的区别是:阻塞状态在等待获取一个排它锁,这个事件将在另外一个线程放弃这个锁的时候发生。等待状态在等待一段时间或者唤醒动作。
6)结束:已终止线程的线程状态,线程已经结束执行。
20.synchronized(S) VS lock(L)
1) L是接口,S是关键字
2)S在发生异常时,会自动释放线程占有的锁,不会发生死锁。L在发生异常时,若没有主动通过unlock()释放锁,则很有可能造成死锁。所以用lock时要在finally中释放锁。
3)L可以当等待锁的线程响应中断,而S不行,使用S时,等待的线程将会一直等下去,不能响应中断。
4)通过L可以知道是否成功获得锁,S不可以。
21.mysq索引使用的是B+的数据结构
索引:用于提高数据访问速度的数据库对象。
优点:1)索引可以避免全表扫描;2)对于非聚集索引,有些查询甚至可以不访问数据项;3)聚集索引可以避免数据插入操作集中于表的最后一个数据页;4)一些情况下,索引还可以避免排序。
虽然索引可以提高查询速度,但是他们也会导致数据库更新数据的性能下降,因为大部分数据更新时需要同时更新索引。
聚集索引:数据按索引顺序存储,叶子节点存储真实的数据行,不再有另外单独的数据页。在一张表上只能创建一个聚集索引,因为真实数据的物理顺序只能有1种,若一张表没有聚集索引,则他被称为堆集,这样表的数据行无特定的顺序,所有新行将被添加到表的末尾。
非聚集索引与聚集索引的区别:
1)叶子节点并非数据节点
2)叶子节点为每一个真正的数据行存储一个“键-指针”对
3)叶子节点中还存储了一个指针偏移量,根据页指针及指针偏移可以定位到具体的数据行。
4)在除叶节点外的其他索引节点,存储的是类似内容,只不过是指向下一级索引页。
22.假如堆内存最大为2G,现在发现电脑内存占用了3G,原因可能是直接内存。
24.类加载
类从加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:
加载-验证-准备-解析-初始化-使用-卸载,其中验证-准备-解析称为链接。
在遇到下列情况时,若没有初始化,则需要先触发其初始化(加载-验证-准备自然需要在此之前):
1)1.使用new关键字实例化对象2.读取或设置一个类的静态字段3.调用一个类的静态方法。
2)使用java.lang.reflect包的方法对类进行反射调用时,若类没有进行初始化,则需要触发其初始化
3)当初始化一个类时,若发现其父类还没有进行初始化,则要先触发其父类的初始化。
4)当虚拟机启动时,用户需要制定一个要执行的主类(有main方法的那个类),虚拟机会先初始化这个类。
被动引用:1)通过子类引用父类的静态字段,不会导致子类的初始化,即父类静态代码块执行,子类静态代码块不执行。2)通过数组定义来引用类,不会触发此类的初始化,eg,SuperClass [] ss=new SuperClass[10]。3)常量在编译阶段会存入调用的类的常量池,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
在加载阶段,虚拟机需要完成下面3件事:
1)通过一个类的全限定名获取定义此类的二进制字节流;
2)将这个字节流所表示的静态存储结构转化为方法区运行时数据结构
3)在内存中生成一个代表这个类的class对象,作为方法区的各种数据的访问入口。
验证的目的是为了确保clsss文件的字节流中包含的信息符合当前虚拟机的要求,且不会危害虚拟机自身的安全。验证阶段大致会完成下面4个阶段的检验动作:1)文件格式验证2)元数据验证3)字节码验证4)符号引用验证{字节码验证将对类的方法进行校验分析,保证被校验的方法在运行时不会做出危害虚拟机的事,一个类方法体的字节码没有通过字节码验证,那一定有问题,但若一个方法通过了验证,也不能说明它一定安全}。
准备阶段是正式为类变量分配内存并设置变量的初始化值得阶段,这些变量所使用的内存都将在方法区中进行分配。(不是实例变量,且是初始值,若public static int a=123;准备阶段后a的值为0,而不是123,要在初始化之后才变为123,但若被final修饰,public static final int a=123;在准备阶段后就变为了123)
解析阶段是虚拟机将常量池中的符号引用变为直接引用的过程。
静态代码块只能访问在静态代码块之前的变量,在它之后的变量,在前面的静态代码块中可以复制,但是不可以使用。
通过一个类的全限定名来获取定义此类的二进制字节流,实现这个动作的代码就是“类加载器”。
比较两个类是否相同,只有这两个类是由同一个类加载器加载的前提下才有意义,否则即使这两个类来源于同一个class文件,被同一个虚拟机加载,只要加载他们的加载器不同,他们就是不同的类。
从Java虚拟机的角度来说,只存在两种不同的类加载器:一种是启动类加载器,这个类加载器使用c++实现,是虚拟机自身的一部分。另一种就是所有其他的类加载器,这些类加载器都由Java实现,且全部继承自java.lang.ClassLoader。
从JAVA开发人员角度,类加载器分为:
1)启动类加载器,这个加载器负责把<HAVA_HOME>\lib目录中或者–Xbootclasspath下的类库加载到虚拟机内存中,启动类加载器无法被Java程序直接引用。
2)扩展类加载器:负责加载<HAVA_HOME>\lib\ext下或者java.ext.dirs系统变量指定路径下all类库,开发者可以直接使用扩展类加载器。
3)应用程序类加载器,负责加载用户路径classpath上指定的类库,开发者可以直接使用这个类加载器,若应用程序中没有定义过自己的类加载器,一般情况下,这个就是程序中默认的类加载器。
双亲委派模型:若一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把所这个请求委派给父类加载器去完成,每一层的加载器都是如此,因此all加载请求最终都应该传送到顶级的启动类加载器。只有当父类加载器反馈自己无法加载时(他的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
双亲委派模型好处:eg,object类。它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都是委派给处于模型顶端的启动类加载器加载,因此object类在程序的各种加载环境中都是同一个类。25.线程安全与锁优化东西太多了,直接见《深入理解Java虚拟机:JVM高级特性与最佳实践》最后一章。
26.同步:多个线程并发访问共享数据时,保证共享数据在同一个时刻,只被一个(or一些,使用信号量)线程使用,而互斥是实现同步的一种手段,临界区,互斥量,信号量都是主要的互斥实现方式。互斥是因,同步是果;互斥是方法,同步是目的。
27.synchronized是重量级的同步机制。
28.公平锁:(先申请先得到)多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获取,而非公平锁则不保证这一点。Synchronized不是公平锁,reetrantlock默认下也是非公平的,但是在构造函数中,可以设置为公平的。
29.all的可重入代码都是线程安全的,但是并非all线程安全的代码都是可重入的。
30.互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的需要转入内核态中完成。若物理机器上有一个以上的处理器,能让2个or2个以上的线程同时并行执行,我们就可以让后面请求锁的那个线程“稍等一下”,但不放弃处理器的执行时间,看看持有锁的线程是否很快就释放锁,为了让线程等待,我们只需要让他执行一个忙循环(自旋),这项技术就是所谓的自旋锁。
自适应自旋锁的自旋时间不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态决定。
31.锁消除是指虚拟机的编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。
32.tcp如何保证传输的可靠性?tcp是面向连接,可靠的字节流服务。
面向连接意味着两个使用tcp的应用(通常是一个客户端和一个服务器)在彼此交换数据之前必须先建立一个tcp连接。在一个tcp连接中,仅有两方进行彼此通信,广播和多播不能用于tcp。
Tcp通过下列方式提供可靠性:
1)将应用数据分割为tcp认为最合适发送的数据块;
2)超时重传:当tcp发出一个段后,他启动一个定时器,等待目的端确认收到这个报文段。若不能及时收到一个确认,将重发这个报文段。
3)当tcp收到发自tcp链接另一端的数据时,它将发送一个确认(对于收到的请求,给出确认响应)。这个确认不是立即发送,通常将推迟几分之一秒(之所以推迟,可能是要对包做完校验);
4)若tcp收到包,校验出包有错,丢弃报文段,不给出响应,tcp发送端会超时重传;
5)对于失序数据进行重新排序,然后交给应用层(tcp报文段作为ip数据报进行传输,而ip数据报的到达会失序,因此tcp报文段的到达也可能失序。若必要,tcp将对收到的数据进行重新排列,以正确的顺序交给应用层)。
6)对于重复数据,直接丢弃。
7)tcp可以进行流量控制,防止较快主机致使较慢主机的缓冲区溢出。
字节流服务:两个应用程序通过tcp连接,tcp不在字节中插入记录标识符,我们将这种为字节流服务。
Tcp对字节流的内容不做任何解释,tcp不知道传输的字节流数据是二进制数据还是ascii字符或其他类型数据,对字节流的解释由tcp连接双方的应用层。
33.json是数据格式。
34.https其实是由两部分组成:http+ssl/tls,也就是在http上又加了一层处理加密信息的模块,服务端和客户端的信息传输都会通过tls加密,传输的数据都是加密后的数据。加解密过程:
1)客户端发起https请求(就是用户在浏览器里输入一个https网址,然后连接到server的443端口)
2)服务端的配置(采用https协议的服务器必须要有一塔数字证书,可以自己制作,也可以向组织申请,这套证书就是一对公钥和私钥)。
3)传输证书(这个证书就是公钥,只是包含了很多信息)
4)客户端解析证书(由客户端tls完成,首先验证公钥是否有效,若发现异常,则弹出一个警示框,提示证书存在问题,若无问题,则生成一个随机值,然后用证书对随机值进行加密)
5)传输加密信息(这里传输的是加密后的随机值,目的是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密了)
6)服务端解密信息(服务端用私钥解密后得到了客户端传来的随机值,then把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全)
7)传输加密的信息
8)客户端解密信息,用随机数来解。
问:在客户端抓包抓到的是加密的还是没加密的?不知道是哪个面试官问的,我就乱说是加密的,然后面试官说错了,是没有加密的
35.jdk和jre区别?jdk的bin下有javac,jre的bin下没有javac。
36.面向对象和面向过程的区别?
(过程)优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗源;比如嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。缺点:没有面向对象易维护、易复用、易扩展。
(对象)优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统。缺点:性能比面向过程低。
37.java集合类太多了,自己网上查
38.ArrayList VS Vector (都实现了list接口,都是数组实现)
不安全 安全
扩容50% 扩容100%
39. ArrayList VS LinkedList
数组 链表
适合检索和在末尾插入or删除 适合在中间插入or删除
LinkedList还实现了queue接口,他还提供peek(),pool(),offer()等方法。
40.hashmap和hashtable底层原理(必问,每一个点都要清楚)
给几个网址:http://zhangshixi.iteye.com/blog/672697
http://www.admin10000.com/document/3322.html
http://www.cnblogs.com/skywang12345/p/3310887.html
http://blog.csdn.net/chdjj/article/details/38581035
41.一个数的集合,里面只有一个数不同,其他都成对出现,怎么找出这个不同的数?
见《剑指offer》P211。
42.两个栈实现队列? 见《剑指offer》P59,插入的元素都放在stack1中,pop时,若stack2不为空,则直接弹出stack2的栈顶,若stack2为空,则把stack1的元素弹入stack2,再pop出stack2的栈顶。
43.现在有很多xml布局文件里面要使用相同的布局,要怎么实现复用?用include(这道题不知道在哪里看到的,从来没被问到过)。
44.使用线程池。我们只需要运行Executors类给我们提供的静态方法,就可以创建相应的线程池。
Public static ExecutorService newSingleThreadExecutor()
Public static ExecutorService newFixedThreadPool()
Public static ExecutorService newCahedThreadPool()
newSingleThreadExecutor返回包含一个单线程的Executor,将多个任务交给这个Executor时,这个线程处理完一个任务之后接着处理下一个任务,若该线程出现异常,将会有一个新线程来代替。
newFixedThreadPool返回一个包含指定数目线程的线程池,若任务数多于线程数目,则没有执行的任务必须等待,直到有任务完成为止。
newCahedThreadPool根据用户的任务数创建相应的线程数来处理,该线程池不会对线程数加以限制,完全依赖于JVM能创建线程的数量,可能引起内存不足。
我们只需要将待执行的方法放入run方法中,将Runnable接口的实现类交给线程池的execute方法,作为他的一个参数,比如:
Executor e=Executors.newSingleThreadExecutor();
e.execute(new Runnable(){ //匿名内部类
public void run(){
//需要执行的任务
}
});
-
排序,感觉这个写的很好(http://blog.csdn.net/hguisu/article/details/7776068/),每一个点都要懂,直接插入,选择,冒泡,归并,快排要会写,面试问的最多的是快排(时间复杂度,最好和平均都是O(nlgn),最差是O(n*n),当数据几乎有序时是最差的,这是退为冒泡,空间复杂度O(nlgn))。
46.当运行一个程序时,JVM启动,运行bootstrap classloader ,该classloader加载核心API(Ext classloader 和app classloader 也在此时被加载),then 调用ext classloader 加载扩展API,最后app classloader 加载classpath目录下定义的class,这就是一个程序最基本的加载流程。
通过classloader加载类实际上就是加载的时候并不对该类进行解析,因此也不会初始化,而class类的forName方法则相反,使用forName方法加载的时候会将class进行解析与初始化。
47.在JAVA中,字符只以一种形式存在,那就是Unicode(不选择任何特定的编码,直接使用他们在字符集中的编号,这是统一的唯一的方法)。在java中指:在JVM中,在内存中,在你的代码里声明的每一个char,string类型的变量中。
Reader和Writer类使用的是GBK编码。
48.int i=0;
S.o.p(i+’o’); 打印结果为48;因为’o’是char类型,要转为int ‘o’对应48
49.int j=0; j=j++; //此时j还是0
j=++j; //此时j是1
50.类型由低到高为(byte,short,char)--int--long--float--double
byte,short,char相同级别,不能相互转换,但可以使用强制类型转换
六个包装类:Float,Double,Byte,Short,Int,Long,Character,Boolean
51.断言是软件开发中一种常用的调试方式,在实现中,assertion就是在程序中的一条语句,他对一个布尔表达式进行检查,一个正确的程序必须保证这个boolean表达式的值为true,若该值为false,则说明程序已经处于不正确的状态下,系统将给出警告并退出。
什么时候使用断言?可以在预计正常情况下不会到达的任何位置上放置断言,断言可以用于验证传递给私有方法的参数。不过,断言不应应用于验证传递给公有方法的参数。因为不管是否启用了断言,公有方法都必须检查参数,不过既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。