1.hashmap的内部实现
答:hashmap 是对数据结构hash table 的内部实现,哈希表也叫散列表,有着不错的查询和添加速度。它通过关键吗key来访问其对应的值value。就是关键码key(key.hashcode())的映射函数来找到表中相对应的位置的value。它结合了链表和数组的优势,其中链表是用来解决hash冲突的。其链接节点数据结构是entry<k,v>,每个entry对象内部又含有指向下一个对象entry的引用。(hashmap 扩容后的长度总是为2的次幂)
2.如果hashMap的key是一个自定义的类,how?
答:需要重写hashcode()和equals()方法。因为不重写的话,entry里面的其他内部属性会影响hashcode的值,明明相等的两个对象可能会判断不相等。
3.为什么重写equals还要重写hashcode?
答:因为hashmap在判断两个对象相等的时候,会先使用key.hashcode来找到相对应的位置,因此如果不重写hashcode的话,hashcode 会受到entry内部其他属性的影响,导致发生错误。
4.ArrayList和LinkedList的区别,如果一直在list的尾部添加元素,用哪个效率高?
答:ArrayList的底层数据结构是数组,linkedList的底层数据结构为链表。通常Arraylist的查询速度快于LinkedList,LinkedList的插入删除速度快于ArrayList。 但是一直在尾部添加元素的话,ArrayList快于LinkedList.
5.介绍一下Syncronized锁。如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
答:Syncronized锁是同步锁,如果关键字修饰静态方法的话是一个类锁(当前类的所有线程都必须等待同步线程执行), 如果关键字修饰成员方法的话是一个对象锁(当前对象的所有进程必须等待同步进程执行完,释放锁)。
6.介绍一下volatile
答:volatile关键字可以修饰共享变量。保证其他线程访问这个变量的时候始终是最新值。 也就是volatile会更新最新值到内java主内存中去,其他线程使用这个变量的时候会从java主内存中去取得这个变量。(解决可见性和有序性)
7.多线程中的i++线程安全吗?为什么
答:是不安全的,因为每个线程都会分配到自己的工作内存,i也会在执行的时候被暂时保存到工作内存中,所以如果当其他线程调用i的时候无法调用到i最新的值。所以这里要使用volatile关键字。
8.如何线程安全的实现一个计数器?
答:使用Syncronized关键字修饰计数器方法。
package com.yolanda.fun.thread;
import java.util.concurrent.atomic.AtomicInteger;
public class MySafeCalcThread1 implements Runnable {
private static AtomicInteger count = new AtomicInteger(0);
public synchronizedstatic void calc() {
if ((count.get()) < 1000) {
int c = count.incrementAndGet();// 自增1,返回更新值
System.out.println("正在运行是线程" + Thread.currentThread().getName() + ":" + c);
}
}
public void run() {
while(true)
{
MySafeCalcThread1.calc();
try {
Thread.sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 6; i++) {
MySafeCalcThread1 thread = new MySafeCalcThread1();
Thread t = new Thread(thread);
t.start();
}
}
}
9.讲一下TCP的连接和释放连接。
答:TCP的链接:3次握手:a.客户端首先发送SYN请求报文
b.服务端收到报文并返回客户端一个ACK确认报文,并分配资源
c.客户端收到报文并返回服务端一个ACK确认报文,并分配资源建立连接
TCP释放连接:4次挥手:a.假设客户端向服务端发送FIN请求结束报文。
b.服务端返回ACK报文,并且确认数据是否传送完毕。
c.客户端收到ACK报文后,进入等待关闭状态,等待服务端发送FIN请求结束报文 (等待时间超过一定时间还没有收到ACK报文可以重传FIN请求报文)
d.服务端数据传送完毕后发送FIN请求结束报文,客户端接受到后返回ACK,服务端客户端关闭TCP连接
10.浏览器从接收到一个URL到最后展示出页面,经历了哪些过程。
答: 在有了客户端和服务端以后,大概进行以下3个步骤展示页面:
1.通过三次握手建立TCP的链接。
2.成功建立连接后,服务器会根据url请求中的信息进行处理,作出响应。一般是找到一个HTML文件返还给客户端。(一般的web技术都会把请求进行封装然后交给我们的服务器进行处理,比如servlet会把请求封装成httpservletrequest对象,把响应封装成httpsevletresponse对象)
3.客户端得到HTML文件,进行渲染。
11.长连接怎么实现的
使用长连接的HTTP协议,会在响应头有加入这行代码:
Connection:keep-alive
12.GC工具用过哪些?
-Xmx Java Heap最大值,默认值为物理内存的1/4;
-Xms Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;
-Xmn Java Heap Young区大小,不熟悉最好保留默认值;
-Xss 每个线程的Stack大小,不熟悉最好保留默认值;
-XX:PermSize:设定内存的永久保存区域;
-XX:MaxPermSize:设定最大内存的永久保存区域;
-XX:PermSize:设定内存的永久保存区域;
-XX:NewSize:设置JVM堆的‘新生代’的默认大小;
-XX:MaxNewSize:设置JVM堆的‘新生代’的最大大小;
1.Server端JVM最好将-Xms和-Xmx设为相同值。为了优化GC,最好让-Xmn值约等于-Xmx的1/3。
2.一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒之内完成。
调优的重要性:新生代的大小设置非常重要,如果新生代过小,会导致新生对象很快就晋升到老年代中,在老年代中对象很难被回收。如果新生代过大,会发生过多的复制过程。因而我们需要找到一个合适的大小,不幸的是,要想获得一个合适的大小,只能通过不断的测试调优,这就需要JVM参数了。
13.IO
a.inputstream 用于字节流读文件, inputstream read = new fileinputstream().
b.outputstream用于字节流写文件
c.reader用于字符流读文件
d.writer用于字符流写文件
e.bufferinputstream,bufferoutputstream用于字节流,速度更快,对流进行写入时提供一个buffer来提高IO效率。在进行磁盘或网络IO时,原始的InputStream对数据读取的过程都是一个字节一个字节操作的,而BufferedInputStream在其内部提供了一个buffer,在读数据时,会一次读取一大块数据到buffer中,这样比单字节的操作效率要高的多,特别是进程磁盘IO和对大量数据进行读写的时候。
14.NIO:NIO和IO最大的区别是数据打包和传输方式。IO是以流的方式处理数据,而NIO是以块的方式处理数据。
a.buffer:Buffer是一个对象,它包含一些要写入或读出的数据。在NIO中,数据是放入buffer对象的,而在IO中,数据是直接写入或者读到Stream对象的。应用程序不能直接对Channel 进行读写操作,而必须通过Buffer 来进行,即Channel 是通过Buffer 来读写数据的。
在NIO中,所有的数据都是用Buffer处理的,它是NIO读写数据的中转池。Buffer实质上是一个数组,通常是一个字节数据,但也可以是其他类型的数组。但一个缓冲区不仅仅是一个数组,重要的是它提供了对数据的结构化访问,而且还可以跟踪系统的读写进程。
使用Buffer 读写数据一般遵循以下四个步骤:
1. 写入数据到Buffer;
2. 调用flip() 方法;
3. 从Buffer 中读取数据;
4. 调用clear() 方法或者compact() 方法。
b.channel:Channel是一个对象,可以通过它读取和写入数据。可以把它看做IO中的流。但是它和流相比还有一些不同:
1. Channel是双向的,既可以读又可以写,而流是单向的
2. Channel可以进行异步的读写
3. 对Channel的读写必须通过buffer对象
如果从文件读取数据的话,需要如下三步:
1. 从FileInputStream获取Channel
2. 创建Buffer
3. 从Channel读取数据到Buffer
15. get 和post的区别
16.session 和 cookie 的区别
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中
17.类加载机制
a.加载:这个阶段会在内存中生成一个代表这个类的java.lang.class 对象,作为方法区这个类的的各种数据入口。
b.验证:这一阶段的主要目的是为了确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
c. 准备:准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。
d.解析:解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。
可以认为是一些静态绑定的会被解析,动态绑定则只会在运行是进行解析;静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类),构造器(不会被重写)
e.初始化
初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其它操作都由JVM主导。到了初始阶段,才开始真正执行类中定义的Java程序代码。
数据库:
一、什么是索引?
索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置。如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍。
假设我们创建了一个名为people的表:
CREATE TABLE people ( peopleid SMALLINT NOT NULL,
name CHAR(50) NOT NULL );
然后,我们完全随机把1000个不同name值插入到people表。在数据文件中name列没有任何明确的次序。如果我们创建了name列的索引,MySQL将在索引中排序name列,对于索引中的每一项,MySQL在内部为它保存一个数据文件中实际记录所在位置的“指针”。因此,如果我们要查找name等于“Mike”记录的peopleid(SQL命令为“SELECT peopleid FROM people WHERE name='Mike';”),MySQL能够在name的索引中查找“Mike”值,然后直接转到数据文件中相应的行,准确地返回该行的peopleid(999)。在这个过程中,MySQL只需处理一个行就可以返回结果。如果没有“name”列的索引,MySQL要扫描数据文件中的所有记录,即1000个记录!显然,需要MySQL处理的记录数量越少,则它完成任务的速度就越快。
二、索引的类型
MySQL提供多种索引类型供选择:
普通索引:
这是最基本的索引类型,而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建:
创建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表);
创建表的时候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) );
唯一性索引:
这种索引和前面的“普通索引”基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一。唯一性索引可以用以下几种方式创建:
创建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);
创建表的时候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) );
主键:
主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”。如果你曾经用过AUTO_INCREMENT类型的列,你可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我们也可以通过修改表的方式加入主键,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每个表只能有一个主键。
全文索引:
MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者TEXT类型的列上创建。它可以通过CREATE TABLE命令创建,也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引,要了解更多信息,请参见MySQL documentation。
IOC(控制反转):Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
AOP (面向切面编程)
在OOP中,正是这种分散在各处且与对象核心功能无关的代码(横切代码)的存在,使得模块复用难度增加。AOP则将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。