Java面试常见问答

1.hashmap的内部实现

 

答:hashmap 是对数据结构hash table 的内部实现,哈希表也叫散列表,有着不错的查询和添加速度。它通过关键吗key来访问其对应的值value。就是关键码key(key.hashcode())的映射函数来找到表中相对应的位置的value。它结合了链表和数组的优势,其中链表是用来解决hash冲突的。其链接节点数据结构是entry<k,v>,每个entry对象内部又含有指向下一个对象entry的引用。(hashmap 扩容后的长度总是为2的次幂)

 

2.如果hashMapkey是一个自定义的类,how

 

答:需要重写hashcode()equals()方法。因为不重写的话,entry里面的其他内部属性会影响hashcode的值,明明相等的两个对象可能会判断不相等。

 

3.为什么重写equals还要重写hashcode

 

答:因为hashmap在判断两个对象相等的时候,会先使用key.hashcode来找到相对应的位置,因此如果不重写hashcode的话,hashcode 会受到entry内部其他属性的影响,导致发生错误。

 

4.ArrayListLinkedList的区别,如果一直在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初始值,ServerJVM最好将-Xms-Xmx设为相同值,开发测试JVM可以保留默认值;

-Xmn    Java Heap Young区大小,不熟悉最好保留默认值;

-Xss     每个线程的Stack大小,不熟悉最好保留默认值;

-XX:PermSize:设定内存的永久保存区域; 

-XX:MaxPermSize:设定最大内存的永久保存区域;

-XX:PermSize:设定内存的永久保存区域;

-XX:NewSize:设置JVM堆的新生代的默认大小;

-XX:MaxNewSize:设置JVM堆的新生代的最大大小; 

1ServerJVM最好将-Xms-Xmx设为相同值。为了优化GC,最好让-Xmn值约等于-Xmx1/3 
2
.一个GUI程序最好是每1020秒间运行一次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:NIOIO最大的区别是数据打包和传输方式。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”记录的peopleidSQL命令为“SELECT peopleid FROM people WHERE name='Mike';”),MySQL能够在name的索引中查找“Mike”值,然后直接转到数据文件中相应的行,准确地返回该行的peopleid999)。在这个过程中,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 TABLECREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引,要了解更多信息,请参见MySQL documentation

 

 

IOC(控制反转):Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了,那我们来深入分析一下:

谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)

为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

 

 

在OOP中,正是这种分散在各处且与对象核心功能无关的代码(横切代码)的存在,使得模块复用难度增加。AOP则将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

猜你喜欢

转载自blog.csdn.net/puzimengya/article/details/81064455