面试day5

##HashMap的Key为Object怎么办

HashMap中,如果要比较key是否相等,要同时使用hashcode(),equals(),因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地 址,这样即便有相同含义的两个对象,比较也是不相等的,例如,生成了两个“羊”对象,正常理解这两个对象应该是相等的,但如果你不重写 hashcode()方法的话,比较是不相等的!
HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等 的。若equals()不相等则认为他们不相等。如果只重写hashcode()不重写equals()方法,当比较equals()时只是看他们是否为 同一对象(即进行内存地址的比较),所以必定要两个方法一起重写。HashMap用来判断key是否相等的方法,其实是调用了HashSet判断加入元素 是否相等。

##浏览器从接收到一个URL到最后展示出页面,经历了哪些过程。

####整体通信

有了客户端和服务器,就可以开始通信了,整体上分为3个步骤:

  • 因为http是构建在TCP之上,那么自然是要经过3次握手创建连接。
  • 创建连接后,服务器会根据url请求中的信息进行处理,作出响应,一般来说是找到一个html文件返回给客户端。
  • 客户端即浏览器得到html,进行渲染。
  1. 缓存解析

    浏览器缓存-系统缓存-路由器缓存 当中查看,如果有从缓存当中显示页面

  2. DNS解析

    域名到IP地址的转换过程,递归查询,非递归查询

  3. 创建连接

    http三次握手

    为什么要三次握手

    计算机A和B之间的通信,假定B给A发送一个连接请求分组,A收到了这个分组,并发送了确认应答分组。按照两次握手的协定,A认为连接已经成功地建立了,可以开始发送数据分组。可是,B在A的应答分组在传输中被丢失的情况下,将不知道A是否已准备好,不知道A建议什么样的序列号,B甚至怀疑A是否收到自己的连接请求分组。在这种情况下,B认为连接还未建立成功,将忽略A发来的任何数据分组,只等待连接确认应答分组。而A在发出的分组超时后,重复发送同样的分组。这样就形成了死锁

  4. 服务器处理

    建立好连接后,客户端就会发送http请求,请求信息包含一个头部和一个请求体,

    一般的web技术都会把请求进行封装然后交给我们的服务器进行处理,比如servlet会把请求封装成httpservletrequest对象,把响应封装成httpsevletresponse对象。nodejs的http模块,当你创建服务器的时候会写一个回调函数,回调的参数用来接受http请求对象和响应对象,然后在回调函数中对请求进行处理。

  5. 客户端渲染

    客户端接收到服务器传来的响应对象,从中得到html字符串和MIME,根据MIME知道了要用页面渲染引擎来处理内容即html字符串。
    渲染引擎得到html字符串作为输入,然后对html进行转换,转化成能够被DOM处理的形式,接着转换成一个dom树,在解析html的过程,解析到

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    	

    ##最安全的单例模式--java使用内部类实现单例模式

    使用内部类可以避免这个问题,因为在多线程环境下,jvm对一个类的初始化会做限制,同一时间只会允许一个线程去初始化一个类,这样就从虚拟机层面避免了大部分单例实现的问题

    ```Java
    public class Singleton {

    private static class LazyHolder {
    private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton (){}
    public static final Singleton getInstance() {
    return LazyHolder.INSTANCE;
    }
    }

##网络协议 7层 应-表-会-传-网-数-物

  • 应用层

    与其它计算机进行通讯的一个应用,它是对应应用程序的通信服务的。例如,一个没有通信功能的字处理程序就不能执行通信的代码,从事字处理工作的程序员也不关心OSI的第7层。但是,如果添加了一个传输文件的选项,那么字处理器的程序员就需要实现OSI的第7层。示例:TELNET,HTTP,FTP,NFS,SMTP等。

  • 表示层

    这一层的主要功能是定义数据格式及加密。例如,FTP允许你选择以二进制或ASCII格式传输。如果选择二进制,那么发送方和接收方不改变文件的内容。如果选择ASCII格式,发送方将把文本从发送方的字符集转换成标准的ASCII后发送数据。在接收方将标准的ASCII转换成接收方计算机的字符集。示例:加密,ASCII等。

  • 会话层

    它定义了如何开始、控制和结束一个会话,包括对多个双向消息的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的,在某些情况下,如果表示层收到了所有的数据,则用数据代表表示层。示例:RPC,SQL等。

  • 传输层

    这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。示例:TCP,UDP,SPX。

  • 网络层

    这层对端到端的包传输进行定义,它定义了能够标识所有结点的逻辑地址,还定义了路由实现的方式和学习的方式。为了适应最大传输单元长度小于包长度的传输介质,网络层还定义了如何将一个包分解成更小的包的分段方法。示例:IP,IPX等。

  • 数据链路层

    它定义了在单个链路上如何传输数据。这些协议与被讨论的各种介质有关。示例:ATM,FDDI等。

  • 物理层

    OSI的物理层规范是有关传输介质的特这些规范通常也参考了其他组织制定的标准。连接头、帧、帧的使用、电流、编码及光调制等都属于各种物理层规范中的内容。物理层常用多个规范完成对所有细节的定义。示例:Rj45,802.3等。

###Spring循环依赖

Spring将对象依赖分成属性依赖和构造依赖,构造依赖问题无法解决,只能抛出BeanCurrentlyInCreationException异常,在解决属性依赖问题,Spring采用的是提前暴露对象的方法。

首先Spring创建office对象,采用其默认构造函数,创建成功后,Spring会通过以下代码将对象提前暴露出来,尽管此时的对象还未完成属性注入,属于早期对象。这个时候对象放在singletonFactories的Map表中,value是函数对象ObjectFactory.

Spring会通过函数populateBean来完成office对象的属性注入,再注入boss属性时,发现是一个引用对象,这个时候同样会通过getBean(“boss”)来获得boss对象,boss对象由于从未创建,则创建boss对象。在创建boss对象时,发现它构造依赖于office对象,这个时候Spring也会通过getBean(“office”)获取office对象。由于存在office提前暴露出来,这个时候直接从singletonFactories的Map表中得到office对象并返回,并不需要重新再创建office对象,这样就避免了循环依赖问题,接下来boss对象可以成功被创建,则返回到到office的属性注入中。

###消息队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class LinkedBlockingQueue<E> {
private final int capacity;

private Lock lock = new ReentrantLock();
private LinkedList<E> queue;//缓冲区
private int count; //缓冲区商品个数
private Condition unfull = lock.newCondition();
private Condition unEmpty = lock.newCondition();

public LinkedBlockingQueue() throws InterruptedException {
this(Integer.MAX_VALUE);
}


public LinkedBlockingQueue(int capacity) throws InterruptedException {
this.capacity = capacity;
queue = new LinkedList<E>();
}


public void put(E e) throws InterruptedException {

try {
while (count == capacity) {
unfull.await();//阻塞队列已满,一直等待,直到有unfull
}
lock.lock(); //内层互斥夹紧
queue.add(e);
count++;
lock.unlock();
unfull.signal();
} finally {

}
}

public E take() throws InterruptedException {

try {
while (count == 0) {//队列为空,阻塞.一直等待指导有商品(unEmpty)
unEmpty.await();
}
lock.lock();
E e = queue.pop();
count--;
lock.unlock();
unEmpty.signal();
return e;
} finally {

}
}

}