Java 问题参考手册

Java中一个字符占多少个字节,扩展再问int, long, double占多少字节

String,StringBuilder,StringBuffer的区别?**

答: String * 字符串常量 * 创建后不可改变 * 对字符串的修改都需要回收再创建 * 通过:private final char value[] 实现,线程安全 * StringBuilder * 是变量,可改变 * 对变量的操作是直接操作创建的对象 * 父类:AbstractStringBuilder

StringBuffer

接口与抽象类的区别

答:

接口

抽象类

什么是java序列化,如何实现java序列化?(写一个实例)

String s = new String("abc");创建了几个 String Object

java中有哪些异常类,分别怎么使用

答:

例如:OutOfMemoryError、OutOfMemoryError等等, 这些异常发生时, java虚拟机一般会终止线程。

  1、当前方法知道如何处理该异常,则用try...catch块来处理。
  2、当前方法不知道如何处理,则在定义该方法时声明抛出该异常。

比较熟悉的checked类有:

  java.lang.ClassNotFoundException
  java.lang.NoSuchMetodException
  java.io.IOException

Runtime如除数是0和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们 比较常用的异常类

  Java.lang.ArithmeticException
  Java.lang.ArrayStoreExcetpion
  Java.lang.ClassCastException
  Java.lang.IndexOutOfBoundsException
  Java.lang.NullPointerException

*异常处理

Collection和Collections的区别是什么

常用的集合类有哪些?比如List如何排序?**

答: 集合的根有两个:Map Collection Vector

TreeSet

ArrayList

LinkedList

ConcurrentLinkedQueue

ConcurrentHashMap

HashMap

Hashtable

TreeMap

List一般使用:Collections进行排序 排序时需要实现接口Comparator的compare方法,此方法中定义排序规则。 实现此方法内容有两种方式: 1. 在sort方法中直接实现,new一个Comparator 的对象,作为sort的参数,直接定义compare 2. 定义一个类,实现Comparator接口,通过compare方法定义排序规则。

HashMap实现原理,如何保证HashMap的线程安全

答:

Hashmap 什么时候进行扩容

List,Set,Map三个接口,存取元素时,各有什么特点

Heap 和Stack 的区别

HashSet和HashTree的区别

HashSet的底层实现是什么

LinkedHashMap的底层实现是什么

为什么集合类没有实现Cloneable和Serializable接口

HashMap,Hashtable,ConcurrentHashMap的共同点与区别

*HashTable

底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
初始size为11,扩容:newsize = olesize*2+1
计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

除此之外,hash表里还有一个“负载极限”,“负载极限”是一个0~1的数值,“负载极限”决定了hash表的最大填满程度。当hash表中的负载因子达到指定的“负载极限”时,hash表会自动成倍地增加容量(桶的数量),并将原有的对象重新分配,放入新的桶内,这称为rehashing。

HashMap和Hashtable的构造器允许指定一个负载极限,HashMap和Hashtable默认的“负载极限”为0.75,这表明当该hash表的3/4已经被填满时,hash表会发生rehashing。

“负载极限”的默认值(0.75)是时间和空间成本上的一种折中:

较高的“负载极限”可以降低hash表所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的操作(HashMap的get()与put()方法都要用到查询)
较低的“负载极限”会提高查询数据的性能,但会增加hash表所占用的内存开销

程序员可以根据实际情况来调整“负载极限”值。 ConcurrentHashMap

底层采用分段的数组+链表实现,线程安全
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容

Hashtable和HashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽象类的。Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

HashMap基于哈希思想,实现对数据的读写。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来存储值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞时,对象将会储存在链表的下一个节点中。HashMap在每个链表节点中储存键值对对象。当两个不同的键对象的hashcode相同时,它们会储存在同一个bucket位置的链表中,可通过键对象的equals()方法来找到键值对。如果链表大小超过阈值(TREEIFY_THRESHOLD,8),链表就会被改造为树形结构。

在HashMap中,null可以作为键,这样的键只有一个,但可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示HashMap中没有该key,也可以表示该key所对应的value为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个key,应该用containsKey()方法来判断。而在Hashtable中,无论是key还是value都不能为null。

Hashtable是线程安全的,它的方法是同步的,可以直接用在多线程环境中。而HashMap则不是线程安全的,在多线程环境中,需要手动实现同步机制。

Hashtable与HashMap另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。

先看一下简单的类图:

从类图中可以看出来在存储结构中ConcurrentHashMap比HashMap多出了一个类Segment,而Segment是一个可重入锁。

ConcurrentHashMap是使用了锁分段技术来保证线程安全的。

锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

ConcurrentHashMap提供了与Hashtable和SynchronizedMap不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。

ConcurrentHashMap默认将hash表分为16个桶,诸如get、put、remove等常用操作只锁住当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。

ArrayList和LinkedList内部的实现大致是怎样的?他们之间的区别和优缺点? **

答:

Java集合类框架的最佳实践有哪些

什么是迭代器Iterator

Iterator和ListIterator的区别是什么

final/finally/finalize的区别

12. synchronized 关键字的实现原理?**

答: //TODO: 每个对象天生都是一个监视器, monitorenter monitorexit

什么是IO?**

答:

什么是NIO?**

答:

channel叫做通道。是IO源与目标节点打开的链接,和传统的IO很相似,但是channel是双向的,主要有如下几种通道: * FileChannel:从文件读或者向文件写数据 * SocketChannel:以TCP来向网络两段读写数据 * ServerSocketChannel:监听客户端发起的连接,并为每个连接创建一个新的SocketChannel来进行数据读写 * DatagramChannel:以UDP协议来向网络连接的两端读写数据

  使用channel的例子
    RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");

    FileChannel inChannel = aFile.getChannel();

    ByteBuffer buf = ByteBuffer.allocate(48);

    int bytesRead = inChannel.read(buf);

    while (bytesRead != -1) {

    System.out.println("Read " + bytesRead);

    buf.flip();

    while(buf.hasRemaining()){
        System.out.print((char) buf.get());
    }
    buf.clear();

    bytesRead = inChannel.read(buf);
        }
    aFile.close();

buffer 缓冲区,是一个容器,是一个连接数组。channel提供从文件、网络读取数据的渠道,但是读取或者写入的数据都必须经过buffer。

常用Buffer的子类有: * ByteBuffer * IntBuffer * CharBuffer * LongBuffer * DoubleBuffer * FloatBuffer * ShortBuffer

这些buffer覆盖了能通过IO发送的基本数据类型:byte,char,int,float,double,long,short。 使用buffer读写数据的几个步骤: * 写入数据到buffer * 调用flip()方法 * 从 Buffer中读取数据 * 调用clear()方法或者compact()方法 * flip方法是进行模式切换(写模式切换到读模式) * clear方法,清空整个缓冲区,compact清除已经读过的数据

buffer的三个属性

buffer的容量,只能存放:byte,long,char等类型,满了,需要清空

写入数据时,表示当前的位置,初始值为:0,最大值为:capacity-1 读入数据时,表示某个特定位置 写模式切换为读模式,position重置为:0

写模式下,buffer的limit表示最多能往buffer里写多少数据。 写模式下:limit等于buffer的capacity 读模式下,limit表示最多能多多少数据 写模式切换为读模式时,limit设置为写模式下的position值

  使用buffer的例子
    RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");

    FileChannel inChannel = aFile.getChannel();

    //申请一个48字节的buffer,也就是:capacity为48
    ByteBuffer buf = ByteBuffer.allocate(48);

    /** 向buffer中写数据 */
    int bytesRead = inChannel.read(buf);

    while (bytesRead != -1) {

        /** 从写模式切换到读模式,position会被设置为:0,limit设置为position设置为0之前的值 */
        buf.flip();

        while(buf.hasRemaining()){

            System.out.print((char) buf.get()); // read 1 byte at a time

        }

        /** buffer 数据读完,清空buffer */
        buf.clear();

        bytesRead = inChannel.read(buf);

    }

    aFile.close();

selector

选择器 用来轮询每个注册的channel,一旦发现channel有注册的事件发生,便获取事件然后进行处理。用一个单线程就可以管理多个通道,也就是管理多个连接,连接在真正有读写事件发生时,才会调用函数来进行读写,大大减少了系统开销,并且为每个连接都创建一个线程,不用去维护多个线程,避免了多线程之间的上下文切换导致的开销。

与Selector有关的一个关键类是:SelectionKey,一个SelectionKey表示一个到达的事件,这2个类构成了服务端处理业务的关键逻辑。

什么是BIO?**

答:

什么是AIO?**

select/epoll的区别?**

答:

多路复用的原理?**

答: I/O多路复用技术通过把多个I/O的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降底了系统的维护工作量,节省了系统资源.

C10K问题?

答: 最初的服务器都是基于进程/线程模型的,新到来一个TCP连接,就需要分配1个进程(或者线程)。而进程又是操作系统最昂贵的资源,一台机器无法创建很多进程。如果是C10K就要创建1万个进程,那么操作系统是无法承受的。如果是采用分布式系统,维持1亿用户在线需要10万台服务器,成本巨大,也只有Facebook,Google,雅虎才有财力购买如此多的服务器。这就是C10K问题的本质。

解决这一问题,主要思路有两个:一个是对于每个连接处理分配一个独立的进程/线程;另一个思路是用同一进程/线程来同时处理若干连接

1. 简单描述tls?**

3. 攻击网站主要有哪些手法? **

答:

sql注入,旁注,XSS跨站,COOKIE欺骗,DDOS,0day漏洞,社会工程学。

3. PreparedStatement与Statement的区别?

答:

** 12. 线程同步的方法?

答:

  1. synchronized关键字修饰 同步方法,同步代码块

如果aba和aab相等,给定两个字符串判断是否相等?

答: 先排序,在比较两个字符串是否相等; 遍历两个字符串,碰到相等的字符,则删除,最后判断两个字符串的长度