J2SE基础:
- 九种基本数据类型的大小,以及他们的封装类。
byte,short,int,long,float,double,boolen,char,void
基本类型所占的存储空间是不变的:这种不变性也是java具有可移植性的原因之一。
基本类型是放在栈中,直接存储值。
所有数值类型都有正负号,没有无符号的数值类型。
- Switch能否用string做参数?
在 Java 7之前,switch 只能支持 byte、short、char、int或者其对应的封装类以及 Enum 类型。在 Java 7中,String支持被加上了。
- equals与==的区别。
equals比较两个对象的内容是否相同
== 比较两个对象是否是同一对象。
- Object有哪些公用方法?
protected Object clone()创建并返回此对象的一个副本。
boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
Class<?> getClass()返回此 Object 的运行时类。
int hashCode()返回该对象的哈希码值。
void notify()唤醒在此对象监视器上等待的单个线程。
void notifyAll()唤醒在此对象监视器上等待的所有线程。
String toString()返回该对象的字符串表示。
void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
void wait(long timeout, int nanos)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
- Java的四种引用,强弱软虚,用到的场景.
null - Hashcode的作用。
1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;
2、如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;
3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;
4、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。
- ArrayList、LinkedList、Vector的区别。
ArrayList Vector都使用数组式存储数据数组元素数于实际存储数据便增加插入元素都允许直接按序号索引元素插入元素要涉及数组元素移等内存操作所索引数据快插入数据慢Vector由于使用synchronized(线程安全)通性能较ArrayList差LinkedList使用双向链表实现存储按序号索引数据需要进行前向或向遍历插入数据需要记录本项前项即所插入速度较快
- String、StringBuffer与StringBuilder的区别。
1、String,StingBuffer,StringBuilder是字符串变量还是常量?
String ----> 字符串常量
StringBuffer ----> 字符串变量(线程安全的)
StringBuilder ----> 字符串变量(非线程安全的)
2、String,StingBuffer,StringBuilder效率如何呢?
从高到底的顺序依次是:StringBuilder > StingBuffer > String
有上知道了String是字符串常量,所以他的效率自然而然是最低的。对于StringBuffer和StringBuilder它们属于变量,是可以改变的对象,每次对字符串的操作,实际上实在一个对象上操作,所以效率更高一些。StringBuffer是线程安全的,考虑到安全问题,相对他的性能会更低一点。由此知道了从效率的角度看,StringBuilder最高,其次是StringBuffer,最后是String字符串常量。
总结:
当多个线程使用字符串缓冲区时,使用StringBuffer保证正确的操作,如果是单线程的,建议使用StringBuiler效率更高一些。
- Map、Set、List、Queue、Stack的特点与用法。
[Collection和Map常用类的比较
](https://zhuanlan.zhihu.com/p/30086934)
list 和set 有共同的父类 它们的用法也是一样的 唯一的不太就是set中不能有相同的元素 list中可以
list和set的用途非常广泛 list可以完全代替数组来使用
map 是独立的合集 它使用键值对的方式来储存数据 键不能有重复的 值可以用
map不像上边两种集合那个用的广泛 不过在servlet 和jsp中 map可是绝对的重中之重 页面之间传值全靠map
List是集合类的接口,子类有ArraryList 和LinkList,通常在Android开发中我们常用的是arrayList,来将数据进行插入和移除。
其次map也是一个集合映射,不过是键值对的映射,也就是key , value形式,比如当我们需要查询其中的某个对象时,只需要查询其key便能直接获取到他的value(值),就像一个小型的数据库,也有类似于hashmap , Linkedhashmap ,treemap等方法来进一步实现和拓展,并且提高他的性能。
Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 Set接口主要实现了两个实现类:
HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快
TreeSet :TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。
Set的功能方法
Set具有与Collection完全一样的接口,因此没有任何额外的功能,不像前面有两个不同的List。实际上Set就是Collection,只 是行为不同。(这是继承与多态思想的典型应用:表现不同的行为。)Set不保存重复的元素(至于如何判断元素相同则较为负责)
Set : 存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。
HashSet:为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。
TreeSet: 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。
LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
Queue用于模拟"队列"这种数据结构(先进先出 FIFO)。队列的头部保存着队列中存放时间最长的元素,队列的尾部保存着队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,
访问元素(poll)操作会返回队列头部的元素,队列不允许随机访问队列中的元素。结合生活中常见的排队就会很好理解这个概念
3.1) PriorityQueue
PriorityQueue并不是一个比较标准的队列实现,PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序,这点从它的类名也可以
看出来
3.2) Deque
Deque接口代表一个"双端队列",双端队列可以同时从两端来添加、删除元素,因此Deque的实现类既可以当成队列使用、也可以当成栈使用
3.2.1) ArrayDeque
是一个基于数组的双端队列,和ArrayList类似,它们的底层都采用一个动态的、可重分配的Object[]数组来存储集合元素,当集合元素超出该数组的容量时,系统会在底层重新分配一个Object[]数组来存储集合元素
3.2.2) LinkedList
- HashMap和HashTable的区别。
HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
区别1:
HashMap可以存放 null
Hashtable不能存放null
区别2:
HashMap不是线程安全的类
Hashtable是线程安全的类
HashTable已经被淘汰了
如果需要线程安全使用ConcurrentHashMap
- HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
null
- TreeMap、HashMap、LindedHashMap的区别。
LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。
- Collection包结构,与Collections的区别。
Collection是集合类的上级接口,子接口主要有Set 和List、Map。
Collections是针对集合类的一个帮助类,提供了操作集合的工具方法:一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
- try catch finally,try里有return,finally还执行么?
肯定会执行。finally{}块的代码只有在try{}块中包含遇到System.exit(0);之类的导致Java虚拟机直接退出的语句才会不执行。
1.影响返回结果的前提是在 非 finally 语句块中有 return 且非基本类型
2.不影响返回结果 的前提是 非 finally 块中有return 且为基本类型
究其本质 基本类型在栈中存储,返回的是真实的值,而引用类型返回的是其浅拷贝堆地址.所以才会改变。
- Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
oom:
1、全称为OutOfMemoryError异常,如果虚拟机在扩展栈时无法申请足够的内存空间,抛出它;
2、Java heap异常:java.lang.OutOfMemoryError:Java heap Space;
3、虚拟机栈和本地方法溢出;
4、运行时常量池溢出异常信息:java.lang.OutOfMemoryError:PermGen Space;
如果要向运行时常量池添加内容,简单的做法就是使用String.intern()这个Native方法;
5、方法区溢出,方法区用于存放class的相关信息,如类名,常量池,字段描述,方法描述等。
异常信息为:java.lang.OutofMemoryError:PermGen Space;
6、引起OOM主要有2个原因:内存泄露和内存溢出(即堆、栈溢出);
SOF:
1、全称为StackOverFlowError异常;
2、如果线程请求的栈深度大于虚拟机所允许的深度,抛出该异常;
3、主要发生在递归调用中;
- Java面向对象的三个特征与含义。
(封装,继承,多态)[http://www.cnblogs.com/chenssy/p/3351835.html] - Override和Overload的含义去区别。
重载 (Overload) 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数、类型或顺序不同)。
重写 (Override) 表示子类中的方法可以与父类中的某个方法的名称 和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那 个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。(备注:子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常 的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法 是 private 类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。)
- Interface与abstract类的区别。
抽象类
抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。以JDK中的GenericServlet为例:
接口
接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能做任何事情。以Externalizable接口为例:
什么时候使用抽象类和接口
如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
- Static class 与non static class的区别。
内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。
- java多态的实现原理。
继承,重写,向上转型 - 实现多线程的两种方法:Thread与Runable。
- 线程同步的方法:sychronized、lock、reentrantLock等。
git - 锁的等级:方法锁、对象锁、类锁。
锁 - 写出生产者消费者模式。
(1)wait() / notify()方法
(2)await() / signal()方法
(3)BlockingQueue阻塞队列方法
- ThreadLocal的设计理念与作用。
线程的局部变量
static put
- ThreadPool用法与优势。
线程池 - Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
1:本例介绍一个特殊的队列:BlockingQueue,如果BlockingQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒,同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间时才会被唤醒继续操作。
2:BlockingQueue有四个具体的实现类,
ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小。其所含的对象是以FIFO(先入先出)顺序排序的。
LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定。其所含的对象是以FIFO顺序排序的。
PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。
SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的。
CountDownLatch是减计数方式,计数==0时释放所有等待的线程;CyclicBarrier是加计数方式,计数达到构造方法中参数指定的值时释放所有等待的线程。
- wait()和sleep()的区别。
1:wait是Object类中,与notify和notifyAll搭配使用,sleep属于Thread类中的;1.CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
2.CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。
2:wait的时候放弃锁,而sleep的时候不放弃锁,但是在sleep的时候,可以调用interrupt函数来中断该线程;
3:suspend将当前线程挂起,要等到线程调用resume方法,该线程才能重新执行。
- foreach与正常for循环效率对比。
1:foreach在使用的过程中,会创建额外的iterator方法,而每次调用哪个hasNext,和next方法,增加了更多的操作,对于访问数组的话for的效率要高于foreach;而且在foreach中,还要检查mod_count,避免导致快速失败,所以效率上会降低,但是由此可以看出foreach是线程安全的,而for不是线程安全的
2:什么时候使用:在多线程中,则使用foreach,如果是在方法中读局部变量的操作,则使用for。
- Java IO与NIO。
nio 重点 - 反射的作用于原理。
- 泛型常用特点,List能否转为List
泛型只是在编译时起作用,最后都是会被擦除的。如果你是做的一个工具类的话,都用Object和不用泛型其实是一回事,建议工具类或者方法使用泛型来定义,再调用时再决定使用什么类型。
- Java与C++对比。
java 去除了 c++ 一些复杂难以理解的特性,去除了指针 - Java1.7与1.8新特性。
- 设计模式:单例、工厂、适配器、责任链、观察者等等。
[设计模式]() - JNI的使用。
重点:
- hashcode算法,默认初始16,因为0X1111,可以让数据均匀分配
- 可以为null,数组+链表(头插法)
- 1.8链表优化成红黑树
重点:
1.Hashmap在插入元素过多的时候需要进行Resize,Resize的条件是
HashMap.Size >= Capacity * LoadFactor(0.75f)
2.Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环。
- resize的时候多个线程同时操作
e = entry
next = e2
e2.next = e3
e3.next = e2
环状链表
此时再去get,程序呢陷入死循环
重点:
- hashset的查找时间复杂度是O(1)
- 最好的方法是用两个指针,一开始都在起点,但是第二个指针每次循环是两个数据节点,如果是环状的,必定两个指针会指向同一个点
时间复杂度O(n),空间复制度O(1)
JVM:
- 内存模型以及分区,需要详细到每个区放什么。
- 堆里面的分区:Eden,survival from to,老年代,各自的特点。
- 对象创建方法,对象的内存分配,对象的访问定位。
- GC的两种判定方法:引用计数与引用链。
- GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?
- GC收集器有哪些?CMS收集器与G1收集器的特点。
- Minor GC与Full GC分别在什么时候发生?
内存满时 - 几种常用的内存调试工具:jmap、jstack、jconsole。
- 类加载的五个过程:加载、验证、准备、解析、初始化。
- 双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。
- 分派:静态分派与动态分派。
总体来说java考察内容包括以下这些:
- 面向对象的一些基本概念:继承,多态之类的
- 抽象类和接口
- 静态类,内部类
- Java集合类,同步和非同步
- Java类加载机制
- Java内存模型和垃圾回收算法
- 线程同步机制(voliate,synchronized,重入锁,threadlocal),线程间通信(wait,notify)
- 异常处理
- 多线程同步问题,生产者消费者,读者写者,哲学家就餐,用java实现
- 了解java中设计模式的思想,用了哪些设计模式,有什么好处
百度一面
1、给一个函数,返回 0 和 1,概率为 p 和 1-p,请你实现一个函数,使得返回 01 概率一样。
2、10 亿个 url,每个 url 大小小于 56B,要求去重,内存 4G。
3、把一个 bst 转化成一个双向链表。
4、http 和 https 区别,https 在请求时额外的过程,https 是如何保证数据安全的。
5、IP 地址子网划分。
6、POST 和 GET 区别。
7、硬链接和软连接区别。
8、DNS 解析过程。
9、kill 用法,某个进程杀不掉的原因(进入内核态,忽略 kill 信号)。
10、linux 用过的命令。
11、系统管理命令(如查看内存使用、网络情况)。
12、管道的使用。
13、grep 的使用,一定要掌握,每次都会问在文件中查找。
14、shell 脚本。
15、find 命令。
16、awk 使用。
百度二面
1、Linux 下的一些指令,$(进程 id),$?(上一条命令退出时状态),怎么查看进程,按照内存大小,CPU 占用排序等等。(大写 M 和大写 P)。
2、http 的 get 和 post 方法。
3、介绍下你所了解的 epoll。
4、数据库 sql 的了解程度。
5、项目中遇到的问题,自己咋解决的等等。
6、手写一个全排列。
7、B树和B+树。
8、介绍一下 Hash,怎么解决冲突。
9、进程间的通信,共享内存方式的优缺点。
百度三面
1、说下你平时看的一些技术博客,书籍。
2、linux 下的一些指令。
3、工作中你觉得最不爽的事情是什么。
4、说下你的优缺点。
5、有没有想过去创业公司。
6、写个 strcpy 函数。
7、说说你自己的性格。
8、给你一个系统(面试官好像是无人车部门的),后台的逻辑已经实现了,但是前端加载很慢,怎么检测。
9、以后可能要学习很多新技术,你怎么看。
10、项目中遇到的困难(提前想好,并且把实现或者优化方法说清楚)。
11、系统的量级、pv、uv 等。
12、应对高并发的解决办法(分布式)。
13、在项目中主要负责了哪些工作。
14、nginx 的负载均衡。
15、分布式缓存的一致性,服务器如何扩容(哈希环)。
redis sharding 增加节点时,为什么会有key丢失?