JDK集合类Collection解析--HashMap

HashMap源码解析

HashMap实现散列这一数据结构,维护一个散列表用于快速查询

内部结构

HashMap内部以词条(key-value)数组维护散列表,采用拉链法应对hash碰撞。
所谓词条数组指:具有相同键值key的元素放在一起。当然我们不能key唯一,可能且允许出现重复。当出现重复时,就发生了hash碰撞。
拉链法指:对于key相同,但是不equals的元素(即不能合并),以链表的形式存储
在这里插入图片描述

重要参数

// HashMap中存储结构:词条数组
transient Node<K,V>[] table;
// 构造时不显示声明容量时的默认值
static final int DEFAULT_INITIAL_CAPACITY = 16;
// 链表树形化阈值:超过该值转为树
static final int TREEIFY_THRESHOLD = 8;
// 数组容量最小是64的时候才能树形化,否则一直扩容
static final int MIN_TREEIFY_CAPACITY = 64;
// 树转链表阈值:当树中结点小于该值,还原为链表
static final int UNTREEIFY_THRESHOLD = 6;
// 默认负载因子:当table中词条占容量的0.75时发生扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;

为什么扩容因子是0.75?
在容量为0.75的时候进行扩容,意味着还有0.25的空间可用,为何不充分利用这一空间呢?对于这个问题不能单单从空间上考虑,容量使用了0.75不仅意味着剩余0.25的空间,更意味着发生碰撞的概率是0.75。
那能否该为0.5呢? 能,怎么不能,你写的程序听你的 0.5虽然降低了hash碰撞的可能,但是降低了空间利用率。所以0.75这个系数,是空间利用率和避免hash碰撞的折中

为什么链表的长度为8转换为树
1.首先,处于空间利用率的考虑
Because TreeNodes are about twice the size of regular nodes, we use them only when bins contain enough nodes to warrant use
以上为JDK注释原文:由于树结点是普通结点(链表结点)的两倍,因此我们要确保有足够多的点才能转换
虽然树查询快,但是在点不太多的情况快不到哪去,但是空间占一堆,所以结点太少就转化为树反而浪费空间资源,也并没有提升时间效率

2.从概率的角度来说:词条插入数组某一位置的概率 近似服从 泊松分布。由该模型可知,hash碰撞发生在同一位置上8次的可能性极小

  • Ideally, under random hashCodes, the frequency of
    * nodes in bins follows a Poisson distribution
    * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
    * parameter of about 0.5 on average for the default resizing
    * threshold of 0.75, although with a large variance because of
    * resizing granularity. Ignoring variance, the expected
    * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
    * factorial(k)). The first values are:
    *
    * 0: 0.60653066
    * 1: 0.30326533
    * 2: 0.07581633
    * 3: 0.01263606
    * 4: 0.00157952
    * 5: 0.00015795
    * 6: 0.00001316
    * 7: 0.00000094
    * 8: 0.00000006
    * more: less than 1 in ten million

为什么树还要还原为链表?
And when they become too small (due to removal or resizing) they are converted back to plain bins.
以上为JDK注释原文:当树结点变少的时候,这些结点将重新变成链表
结合上一个问题,虽然树查询快,但是在点不太多的情况快不到哪去,但是空间占一堆,所以结点太少就转化为树反而浪费空间资源,也并没有提升时间效率

内部类

// 该类实现了词条(键值对)接口,是HashMap中的链表结点
 static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;		//链表后继
        ...
  }
// HashMap里的树结点,对对对,就那个红黑树(有生之年但愿能给看懂喽)
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    TreeNode<K,V> parent;  // red-black tree links
    TreeNode<K,V> left;
    TreeNode<K,V> right;
    TreeNode<K,V> prev;    // needed to unlink next upon deletion
    boolean red;
	...
}

构造方法

HashMap中table的构造不在构造器中实现,构造器仅负责设定参数,table的加载直到执行put方法时才执行

// 默认无参构造
public HashMap() {
	// 设定默认负载因子,然后。。。没了
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
// 虽然花里胡哨一大堆,就是多验了个数据合法,最后还是设定参数
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);
    // 不管上面哪些有的没有,底下两行才是干活的
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}

HashMap容量的特别说明
在设定threshold时,并不是直接赋值,而是经过tableSizeFor函数,这个函数是将输入的int值转换为 大于该值的最小的2的幂次。如10->16
为啥呢?在put元素确定位置的时候就能发现这样做的巧妙之处了

常用方法

put

向table中添加词条,如果已存在添加的词条,覆盖更新,返回被覆盖的值(键值对中的value)

// 看起来是put
public V put(K key, V value) {
	// 这里传入的hash值可不是hashCode
    return putVal(hash(key), key, value, false, true);
}
// 真正执行put的操作
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    // 这里查看是否有初始化,没有resize扩容
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    // 底下这行确定插入位置
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

流程图
在这里插入图片描述

如何确定插入位置?
在JDK中,p = tab[i = (n - 1) & hash])确定插入位置,其等效于hash % n。
在前文中我们提到过,n = tab.length是2的幂次,因此n-1的二进制码必然是一堆0+一堆1,就比如000000…0011111,再经过&之后仅保留了后5位,实际也就是取余了。
此外,这个hash值也并非直接调用hashCode(),早在传入putVal()之前,就先经过hash()对key的hash值做预处理,将前16位与后16位异或(h = key.hashCode()) ^ (h >>> 16)。这样做是为了利用其高位信息来避免hash碰撞。如果一组数据的hash值仅高16位不同,而低16位完全相同,直接采用hash确定位置,可能需要扩容到216才能发现他们不同;而加上高位信息则可能避免这种情况发生,使得hash尽可能离散

为什么重写hashCode也要重写equals
在put的过程中,首先获取对象的hashcode进而确定在hashmap中的位置,随后对该位置上的链表/tree查询是否重复。
现在考虑这样的问题:只重写equals而没有重写hashcode会发生什么?
先说结论,会重复。从逻辑上说,两对象相等<=>equals为true=>hashcode相同。显然两对象相等,那么hashcode一定相等;如果hashcode不同,则两对象一定不同。如果我们只重写了equals而没有重写hashcode,可能equals相同的对象,hashcode却不相同,进而在HashMap里存放了两个“不同”的对象
举例:数组{1,0,1,1},hashcode认为其是一个从左向右的十进制数:1011;而equals认为这是一个从右向左的十进制数:1101。对于数组{1,0,1,1,0},这两个函数发生了歧义,一个认为是10110,而另一个还是认定1101。HashMap中首先调用hashCode,导致明明是相同的对象却阴阳两隔,连调用equals判定的机会都没有

此外,HashMap与HashTable不同,HashMap允许key为null,对应的hash是0

resize

初始化或者将容量翻倍。如果为空,参照默认值初始化容量;不为空则容量扩一倍,原来的词条要么保持不动,要么移动一个常数距离。


final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    
	// 底下这一片,看着挺多的,但就干了一件事,确定新的容量
    if (oldCap > 0) {
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    else {               // zero initial threshold signifies using defaults
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    if (newThr == 0) {
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    // 一直到这

	// 建新的table
    @SuppressWarnings({"rawtypes","unchecked"})
    Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;

	// 遍历原有的table,重新确定位置
    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
                oldTab[j] = null;
                if (e.next == null)
                    newTab[e.hash & (newCap - 1)] = e;
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                else { 
                	// 这一坨,看着也很多,但是说起来,就是把链表里位置变动的结点单独拿出来
                	// 又重写接了个链表给按到新位置上了
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do {
                        next = e.next;
                        if ((e.hash & oldCap) == 0) {
                            if (loTail == null)
                                loHead = e;
                            else
                                loTail.next = e;
                            loTail = e;
                        }
                        else {
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    if (loTail != null) {
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    if (hiTail != null) {
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}

关于扩容时,重新确定位置的小技巧
在插入时,hash和一堆1 & ;现在长度变了,hash和另一堆1 &。这两堆1差不多,就是一个比另一个长了一位,所以得出的pos就只有两种情况,新加的那一位是0,不动;是1,那就加个数,而且所有元素加的数都一样哦

get

返回指定key所映射的value,如果不存在key返回null。

返回null不代表一定没有,可能是某个key值map到了null。containsKey()可以用来区分二者。

这个源码真没啥好说的,遇树查树,遇表查表;有就返回,没有算完

线程安全版本:ConcurrentHashMap

属性


transient volatile Node<K,V>[] table;
//仅在扩容时非空
private transient volatile Node<K,V>[] nextTable;
/**
 * 控制数组的初始化和扩容
 * -1 : 初始化
 * -(1 + the number of active resizing threads) 扩容
 * 0 数组长度为默认长度
 * table==null 表示需要新建数组的长度
 * 已经初始化 数组的有效容量(n*loadFactor)
 */
private transient volatile int sizeCtl;

其余参数与HashMap相同

构造器

构造器怎么写的不重要,重要的是ConcurrentHashMap和HashMap一样,都不在构造器中构建数组,只是设定参数

// 看着花里胡哨的,基本都在检验参数的合法性
// 可见人的输入能有多不靠谱
public ConcurrentHashMap(int initialCapacity,
                         float loadFactor, int concurrencyLevel) {
    if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
        throw new IllegalArgumentException();
    if (initialCapacity < concurrencyLevel)   // Use at least as many bins
        initialCapacity = concurrencyLevel;   // as estimated threads
    long size = (long)(1.0 + (long)initialCapacity / loadFactor);
    int cap = (size >= (long)MAXIMUM_CAPACITY) ?
        MAXIMUM_CAPACITY : tableSizeFor((int)size);
    this.sizeCtl = cap;
}

常见方法

put

在这里插入图片描述

get

get方法是不加锁的,和HashMap差不多 懒得写了

transfer

第一部分是构建一个 nextTable,它的容量是原来的两倍,这个操作是单线程完成的。新建 table 数组的代码为:Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1],在原容量大小的基础上右移一位。
第二个部分就是将原来 table 中的元素复制到 nextTable 中,主要是遍历复制的过程。
根据运算得到当前遍历的数组的位置 i,然后利用 tabAt 方法获得 i 位置的元素再进行判断:

  1. 如果这个位置为空,就在原 table 中的 i 位置放入 forwardNode 节点,这个也是触发并发扩容的关键点
  2. 如果这个位置是 Node 节点(fh>=0),如果它是一个链表的头节点,就构造一个反序链表,把他们分别放在 nextTable 的 i 和 i+n 的位置上
  3. 如果这个位置是 TreeBin 节点(fh<0),也做一个反序处理,并且判断是否需要 untreefi,把处理的结果分别放在 nextTable 的 i 和 i+n 的位置上
  4. 遍历过所有的节点以后就完成了复制工作,这时让 nextTable 作为新的 table,并且更新 sizeCtl 为新容量的 0.75 倍 ,完成扩容。设置为新容量的 0.75 倍代码为 sizeCtl = (n << 1) - (n >>> 1),仔细体会下是不是很巧妙,n<<1 相当于 n 左移一位表示 n 的两倍即 2n,n>>>1,n 右移相当于 n 除以 2 即 0.5n,然后两者相减为 2n-0.5n=1.5n,是不是刚好等于新容量的 0.75 倍即 2n*0.75=1.5n。

作者:你听___ 链接:https://juejin.im/post/6844903602423595015 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

JDK1.7:Segment

将数组分段,对每一段segment独立上锁,这样最多可以有 numberOf(segment)线程同时对ConcurrentHashMap进行操作,提高吞吐量
图片链接
在这里插入图片描述


参考链接:

  1. 第六章 Java数据结构和算法 之 容器类(一)
  2. 并发容器之ConcurrentHashMap(JDK 1.8版本)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一. Java基础部分 7 1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 9 6、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错? 9 7、char型变量中能不能存贮一个中文汉字?为什么? 9 8、用最有效率的方法算2乘以8等於几? 9 9、请设计一个一百亿的计算器 9 10、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、静态变量和实例变量的区别? 12 13、是否可以从一个static方法内部发对非static方法的调用? 12 14、Integer与int的区别 13 15、Math.round(11.5)等於多少? Math.round(-11.5)等於多少? 13 16、下面的代码有什么不妥之处? 13 17、请说作用域public,private,protected,以及不写时的区别 13 18、Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型? 14 19、构造器Constructor是否可被override? 15 20、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法? 15 21、写clone()方法时,通常都有一行代码,是什么? 15 22、面向对象的特征有哪些方面 15 23、java中实现多态的机制是什么? 17 24、abstract class和interface有什么区别? 17 25、abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized? 18 26、什么是内部类?Static Nested Class 和 Inner Class的不同。 19 27、内部类可以引用它的包含类的成员吗?有没有什么限制? 20 28、Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)? 21 29、super.getClass()方法调用 21 30、String是最基本的数据类型吗? 22 31、String s = "Hello";s = s + " world!";这两行代码执行后,原始的String对象中的内容到底变了没有? 22 32、是否可以继承String类? 23 33、String s = new String("xyz");创建了几个String Object? 二者之间有什么区别? 23 34、String 和StringBuffer的区别 23 35、如何把一段逗号分割的字符串转换成一个数组? 24 36、数组有没有length()这个方法? String有没有length()这个方法? 24 37、下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d"; 24 38、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 25 39、下面的程序代码输的结果是多少? 25 40、final, finally, finalize的区别。 27 41、运行时异常与一般异常有何异同? 27 42、error和exception有什么区别? 28 43、Java中的异常处理机制的简单原理和应用。 28 44、请写你最常见到的5个runtime exception。 28 45、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛异常吗? 29 46、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 29 47、sleep() 和 wait() 有什么区别? 30 48、同步和异步有何异同,在什么情况下分别使用他们?举例说明。 32 49. 下面两个方法同步吗?(自己发明) 33 50、多线程有几种实现方法?同步有几种实现方法? 33 51、启动一个线程是用run()还是start()? . 33 52、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 33 53、线程的基本概念、线程的基本状态以及状态之间的关系 34 54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写程序。 38 57、介绍Collection框架的结构 43 58、Collection框架中实现比较要实现什么接口 43 59、ArrayList和Vector的区别 44 60、HashMap和Hashtable的区别 44 61、List 和 Map 区别? 45 62、List, Set, Map是否继承自Collection接口? 45 63、List、Map、Set三个接口,存取元素时,各有什么特点? 45 64、说ArrayList,Vector, LinkedList的存储性能和特性 46 65、去掉一个Vector集合中重复的元素 46 66、CollectionCollections的区别。 47 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别? 47 68、你所知道的集合类都有哪些?主要方法? 47 69、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对? 48 70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说一些常用的类,包,接口,请各举5个 49 72、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说他们分别是哪些类? 49 73、字节流与字符流的区别 50 74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收? 52 80、什么时候用assert。 53 81、java中会存在内存泄漏吗,请简单描述。 53 82、能不能自己写个类,也叫java.lang.String? 57 83. Java代码查错 57 二. 算法与编程 61 1、编写一个程序,将a.txt文件中的单词与b.txt文件中的单词交替合并到c.txt文件中,a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格进行分隔。 61 2、编写一个程序,将d:\java目录下的所有.java文件复制到d:\jad目录下,并将原来文件的扩展名从.java改为.jad。 62 3、编写一个截取字符串的函数,输入为一个字符串和字节数,输为按字节截取的字符串,但要保证汉字不被截取半个,如“我ABC”,4,应该截取“我AB”,输入“我ABC汉DEF”,6,应该输“我ABC”,而不是“我ABC+汉的半个”。 65 4、有一个字符串,其中包含中文字符、英文字符和数字字符,请统计和打印各个字符的个数。 65 5、说明生活中遇到的二叉树,用java实现二叉树 66 6、从类似如下的文本文件中读取所有的姓名,并打印重复的姓名和重复的次数,并按重复次数排序: 71 7、写一个Singleton来。 75 8、递归算法题1 77 9、递归算法题2 78 10、排序都有哪几种方法?请列举。用JAVA实现一个快速排序。 79 11、有数组a[n],用java代码将数组元素顺序颠倒 80 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一个日期大 82 2. 用table显示n条记录,每3行换一次颜色,即1,2,3用红色字体,4,5,6用绿色字体,7,8,9用红颜色字体。 83 3、HTML 的 form 提交之前如何验证数值文本框的内容全部为数字? 否则的话提示用户并终止提交? 84 4、请写用于校验HTML文本框中输入的内容全部为数字的javascript代码 84 5、说说你用过那些ajax技术和框架,说说它们的区别 85 四. Java web部分 85 1、Tomcat的优化经验 85 2、HTTP请求的GET与POST方式的区别 85 3、解释一下什么是servlet; 85 4、说一说Servlet的生命周期? 86 5、Servlet的基本架构 86 6、SERVLET API中forward() 与redirect()的区别? 86 7、什么情况下调用doGet()和doPost()? 86 8、Request对象的主要方法: 87 9、forward 和redirect的区别 87 10、request.getAttribute() 和 request.getParameter() 有何区别? 88 11. jsp有哪些内置对象?作用分别是什么? 分别有什么方法? 88 12. jsp有哪些动作?作用分别是什么? 88 13、JSP的常用指令 89 14. JSP中动态INCLUDE与静态INCLUDE的区别? 89 15、两种跳转方式分别是什么?有什么区别? 89 16、页面间对象传递的方法 89 17、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么? 90 18、MVC的各个部分都有那些技术来实现?如何实现? 90 19、我们在web应用开发过程中经常遇到输某种编码的字符,如iso8859-1等,如何输一个某种编码的字符串? 90 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset 91 五. 数据库部分 91 1、用两种方式根据部门号从高到低,工资从低到高列每个员工的信息。 91 2、列各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 91 3、存储过程与触发器必须讲,经常被面试到? 92 4、数据库三范式是什么? 94 5、说一些数据库优化方面的经验? 95 6、union和union all有什么不同? 96 7.分页语句 97 8.用一条SQL语句 查询每门课都大于80分的学生姓名 100 9.所有部门之间的比赛组合 100 10.每个月份的发生额都比101科目多的科目 101 11.统计每年每月的信息 102 12.显示文章标题,发帖人、最后回复时间 103 13.删除除了id号不同,其他都相同的学生冗余信息 104 14.航空网的几个航班查询题: 104 15.查比经理薪水还高的员工信息: 105 16、求小于45岁的各个老师所带的大于12岁的学生人数 106 17.求发帖最多的人: 107 18、一个用户表中有一个积分字段,假如数据库中有100多万个用户,若要在每年第一天凌晨将积分清零,你将考虑什么,你将想什么办法解决? 107 19、一个用户具有多个角色,请查询该表中具有该用户的所有角色的其他用户。 108 20. xxx公司的sql面试 108 21、注册Jdbc驱动程序的三种方式 109 22、用JDBC如何调用存储过程 109 23、JDBC中的PreparedStatement相比Statement的好处 110 24. 写一个用jdbc连接并访问oracle数据的程序代码 111 25、Class.forName的作用?为什么要用? 111 26、大数据量下的分页解决方法。 111 27、用 JDBC 查询学生成绩单, 把主要代码写来(考试概率极大). 112 28、这段代码有什么不足之处? 112 29、说数据连接池的工作机制是什么? 113 30、为什么要用 ORM?  和 JDBC 有何不一样? 113 六. XML部分 113 1、xml有哪些解析技术?区别是什么? 113 2、你在项目中用到了xml技术的哪些方面?如何实现的? 114 3、用jdom解析xml文件时如何解决中文问题?如何解析? 114 4、编程用JAVA解析XML的方式. 115 5、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 117 七. 流行的框架与新技术 117 1、谈谈你对Struts的理解。 117 2、谈谈你对Hibernate的理解。 118 3、AOP的作用。 118 4、你对Spring的理解。 118 5、谈谈Struts中的Action servlet。 120 6、Struts优缺点 优点: 1. 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现. 120 7、STRUTS的应用(如STRUTS架构) 121 8、说说struts1与struts2的区别。 121 9、hibernate中的update()和saveOrUpdate()的区别,session的load()和get()的区别。 122 10、简述 Hibernate 和 JDBC 的优缺点? 如何书写一个 one to many 配置文件. 122 11、iBatis与Hibernate有什么不同? 122 12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托方案怎么配置? 123 16. hibernate进行多表查询每个表中各取几个字段,也就是说查询来的结果集没有一个实体类与之对应如何解决; 123 17.介绍一下Hibernate的二级缓存 123 18、Spring 的依赖注入是什么意思? 给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 八. 软件工程与设计模式 126 1、UML方面 126 2、j2ee常用的设计模式?说明工厂模式。 126 3、开发中都用到了那些设计模式?用在什么场合? 127 九. j2ee部分 127 1、BS与CS的联系与区别。 127 2、应用服务器与WEB SERVER的区别? 128 3、应用服务器有那些? 128 4、J2EE是什么? 128 5、J2EE是技术还是平台还是框架? 什么是J2EE 128 6、请对以下在J2EE中常用的名词进行解释(或简单描述) 129 7、如何给weblogic指定大小的内存? 129 8、如何设定的weblogic的热启动模式(开发模式)与产品发布模式? 129 9、如何启动时不需输入用户名与密码? 130 10、在weblogic管理制台中对一个应用域(或者说是一个网站,Domain)进行jms及ejb或连接池等相关信息进行配置后,实际保存在什么文件中? 130 11、说说weblogic中一个Domain的缺省目录结构?比如要将一个简单的helloWorld.jsp放入何目录下,然的在浏览器上就可打入http://主机:端口号//helloword.jsp就可以看到运行结果了? 又比如这其中用到了一个自己写的javaBean该如何办? 130 12、在weblogic中发布ejb需涉及到哪些配置文件 130 13、如何在weblogic中进行ssl配置与客户端的认证配置或说说j2ee(标准)进行ssl的配置? 130 14、如何查看在weblogic中已经发布的EJB? 131 十. EBJ部分 131 1、EJB是基于哪些技术实现的?并说SessionBean和EntityBean的区别,StatefulBean和StatelessBean的区别。 131 2、简要讲一下 EJB 的 7 个 Transaction Level? 131 3、EJB与JAVA BEAN的区别? 131 4、EJB包括(SessionBean,EntityBean)说他们的生命周期,及如何管理事务的? 132 5、EJB容器提供的服务 132 6、EJB的激活机制 132 7、EJB的几种类型 132 8、客服端调用EJB对象的几个基本步骤 133 十一. webservice部分 133 1、WEB SERVICE名词解释。JSWDL开发包的介绍。JAXP、JAXM的解释。SOAP、UDDI,WSDL解释。 133 2、CORBA是什么?用途是什么? 133 3. Linux 134 4、LINUX下线程,GDI类的解释。 134 5. 问得稀里糊涂的题 134 6、四种会话跟踪技术 134 7、简述逻辑操作(&,|,^)与条件操作(&&,||)的区别。 134 十二. 其他 134 1、请用英文简单介绍一下自己. 134 2、请把 http://tomcat.apache.org/ 首页的这一段话用中文翻译一下? 135 3、美资软件公司JAVA工程师电话面试题目 135

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值