31出现OOM异常怎么解决
OOM是什么:OUT OF MEMORY
OOM为什么出现:内存空间不足,至于哪的内存可能是堆的,可能是
OOM怎么解决:一般就是设大点。
类似的还有StackOverFlowError
当线程请求的栈深度大于虚拟机所允许的最大栈深度,就会抛出这个异常。
方法区物理上存在于堆里,而且是在堆的持久代里面;但在逻辑上,方法区和堆是独立的。
一般说堆的持久代就是说方法区,因为一旦JVM把方法区(类信息,常量池,静态字段,方法)加载进内存以后,这些内存一般是不会被回收的了。
永久代也就是我们通常说的方法区。
java8从Hotspot JVM中删除了永久代,所以我们不再需要为永久代设置大小,也就是不用设置PermSize和MaxPermSize。
在java8之前方法区是作为堆的永久代来实现的,启动JVM时我们需要设置永久代的大小,垃圾回收器也要回收这部分区域,而且会抛出内存溢出异常。借鉴于JRockit虚拟机,java8之后 Hotspot 虚拟机从堆中彻底删除了永久代。
—把方法区中的String和静态变量移到了堆中。
—把其他的东西(比如类结构)放到了本地内存中,JVM会直接负责这部分的内存回收。
总之,我们不再需要设置PermSize和MaxPermSize;方法区的内存溢出将不再出现,除非本地内存耗光。
32单例模式,工厂模式和统计一个数组里出现次数超过一半的数
一、懒汉式单例
- //懒汉式单例类.在第一次调用的时候实例化自己
- public class Singleton {
- private Singleton() {}
- private static Singleton single=null;
- //静态工厂方法
- public static Singleton getInstance() {
- if (single == null) {
- single = new Singleton();
- }
- return single;
- }
- }
(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)
但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全,如果你第一次接触单例模式,对线程安全不是很了解,可以先跳过下面这三小条,去看饿汉式单例,等看完后面再回头考虑线程安全的问题:
1、在getInstance方法上加同步
- public static synchronized Singleton getInstance() {
- if (single == null) {
- single = new Singleton();
- }
- return single;
- }
2、双重检查锁定
- public static Singleton getInstance() {
- if (singleton == null) {
- synchronized (Singleton.class) {
- if (singleton == null) {
- singleton = new Singleton();
- }
- }
- }
- return singleton;
- }
3、静态内部类
- public class Singleton {
- private static class LazyHolder {
- private static final Singleton INSTANCE = new Singleton();
- }
- private Singleton (){}
- public static final Singleton getInstance() {
- return LazyHolder.INSTANCE;
- }
- }
就记住工厂方法是一个工厂创建一种产品,抽象工厂是一个方法创建多个商品。
//出现次数大于一半,意味着肯定有挨着的两个数
int[] i = new int[]{8,1,1,8,8,8,3,3,5,8,6,7,8,8,8,8,1,2,8};
//先考虑如果是奇数数组如果中间没有挨着的首尾肯定相等
if(i[0] == i[i.length-1]){
int times = 0;
for(int p=0;p<i.length;p++){
if(i[p] == i[0]){
times ++;
}
}
if(times > i.length /2){
System.out.println(i[0]);
}
}else{
for(int j = 0 ;j < i.length - 1; j ++){
if(i[j] == i[j + 1]){
int times = 0;
for(int p=0;p<i.length;p++){
if(i[p] == i[j]){
times ++;
}
}
if(times > i.length /2){
System.out.println(i[j]);
break;
}
}
}
}
33高并发下的优化手段
那要看瓶颈在哪了,是数据库就去优化数据库,如果数据库瓶颈在IO还要加强硬件,如果性能瓶颈就要负载均衡,拆表之类,HTML静态化,利用NGINX,CDN等,如果是分布式直接的互通也是IO吧还要看用什么实现的,如果发的内容大甚至可以压缩了传。系统性能用缓存,软件集群数据库集群等了。
http://www.ablanxue.com/prone_1020_1.html
CDN:内容分发网络,你可以理解为一切为了用户体验,为了用户更快的打开网页,把常用资源放在离用户最近的节点,CDN就是做的这个工作。
HA:High Availability Cluster,简称HACluster
具体HA衡量标准:
99% 一年宕机时间不超过4天
99.9% 一年宕机时间不超过10小时
99.99% 一年宕机时间不超过1小时
99.999% 一年宕机时间不超过6分钟
一想到我们公司的系统,呵呵呵呵呵呵
在集群服务器架构中,当主服务器故障时,备份服务器能够自动接管主服务器的工作,并及时切换过去,以实现对用户的不间断服务。
http://aokunsang.iteye.com/blog/2053719
分布式系统中还有一个问题就是SESSION共享http://www.cnblogs.com/yanweidie/archive/2015/08/17/4678095.html
可以放在REDIS中,
34jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
http://guafei.iteye.com/blog/1815222
35JS作用域
http://www.studyofnet.com/news/294.html
简单说就是如果没有显示指定的就是全局变量,如果显示指定了看位置如果在方法里就是私有变量,根据作用域链,私有变量找到后就不会向上查找了。
36spring的annotation
注解 1简化配置 2自定义操作
简化配置好理解,自定义操作就是像公司项目做了分表,在执行SQL的时候自动找到对应的表。
37用java语言打印出a,b,c,d的所有可能组合
static int c = 1;
public static void main(String[] args) {
String s = "abcde";
printAllArray(s, "");
}
private static void printAllArray(String s, String n) {
if (s.length() == 0) {
System.out.println(n + " --- " + c++);
} else {
for (int i = 0; i < s.length(); i ++) {
System.out.println(s.substring(1) + ":" + (n + s.charAt(0)));
printAllArray(s.substring(1), n + s.charAt(0));
s = s.substring(1) + s.charAt(0);
}
}
}
38哈希一致性、ZK等知识
Zookeeper主要可以干哪些事情:配置管理,名字服务,提供分布式同步以及集群管理.
http://blog.csdn.net/yoara/article/details/45308937 ZOOKEEPER使用了观察者模式
JNDI是把数据源配置在文件中,减少了代码和配置的耦合。
哈希一致性算法是用于解决服务器均衡问题,http://blog.csdn.net/caigen1988/article/details/7708806
consistent hashing 是一种 hash 算法,简单的说,在移除 / 添加一个 cache 时,它能够尽可能小的改变已存在 key 映射关系,尽可能的满足单调性的要求。
39Cookie和Session的区别和优缺点
首先COOKIE是存在客户端的,而SESSION是存在服务器端的。cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围。cookie可以存在内存和硬盘里,存储和清除的策略由浏览器实现。
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie
http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html
http://www.admin10000.com/document/1034.html
40类似京东商城网站设计需要注意些什么
首先肯定是安全性,高并发,稳定性这些,包括首页的载入速度,搜索查询速度的优化。
41Java中的switch语句的参数
能转为INT的 包括char,byte,short,int,后来支持了STRING和ENUM,但是STRING的字节码发现是用HASHCODE比的,还是INT的比较
42Java中线程安全的机制,如何实现?实现方式?yeild的方法的使用?会释放锁吗?线程死锁?
线程安全就是同步,保证当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替运行,并且在主调试代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,则称这个类时线程安全的。同步就用到了SYNCHRONIZED以及CONCURRENT包。
yeild就是让当前线程停止运行等待CPU召唤,也可能立刻被召唤了,
释放锁就看你是隐式还是显式了,CONCURRENT包里很多类如果显式上锁了就需要你显式释放掉。隐式就是代码块执行完了自动释放。
线程死锁就是两个线程等待同一份资源,
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
http://www.cnblogs.com/Jessy/p/3540724.html
43Java中内存泄露有几种?如何分析泄露原因
内存泄露我们都知道是OOM,可能产生的原因有
1)静态集合类引起
2)各种连接比如数据库连接
3)监听器
4)内部和外部的引用
5)单例模式对外部资源的引用
等。
首先用分析工具DUMP,
Dump的本意是"倾卸垃圾"、"把(垃圾桶)倒空"。在计算机技术中使用Dump的主要意思仍
然如此,即当电脑运行发现故障后,无法排除而死机,通常要重新启动。为了找出故障的原因
,需要分析现场(即死机时整个内存的当前状况),在重新启动系统之前要把内存中的一片0、
1(这时它们尤如一堆垃圾)"卸出"保存起来,以便由专家去分析引起死机的原因。技术资料中
把这个"卸出"的过程叫dump;有时把卸出的"内容"也叫dump。
这种工具很多比如JMAP,然后分析哪些数据量太大了,比如char[]太多了就可能有大STRING对象,然后找到谁引用的,
http://blog.sina.com.cn/s/blog_644eb93501012jje.html 比如文中的问题,实际就需要StreamTokenizer来代替split
44IOc如何实现依赖注入的?Spring动态代理的实现方式?
依赖注入:常用的就是SET注入和构造器注入
AOP有两种配置方式,注解和文件配置,我在工作中平时用的是文件配置。
JDK自带的动态代理
一个动态代理类实现了INVOCATIONHANDLER接口 有个BIND方法返回创建好的代理对象 执行该对象自己的方法即可。
但是该方法有个缺陷,仅能针对有接口的类,所以针对没有接口的类有了CGLIB,原理是对指定类生产一个子类,覆盖其中的方法
1:如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2:目标对象实现了接口,可以强制使用CGLIB实现AOP
3:如目标对象没有实现接口,必须采用CGLIB库,spirng会自动在JDK动态代理和CGLIB之间转换
http://www.tuicool.com/articles/3AzAnuA CGLIB性能高但是创建时间长,对于FINAL的类和方法由于不能继承无法使用CGLIB
45索引什么时候会失效?
关于索引的使用和其数据结构(B,B+树,就是个查找问题)前面都说过,
何时会失效:1条件中有OR且OR的左右并没有都建立索引时2多列索引3like查询以%开头4索引列进行了数学运算5根据索引的不同比如B树索引位图索引,对IS NULL ISNOT NULL的支持不一样6查询小表或者返回值大于10%
http://blog.csdn.net/colin_liu2009/article/details/7301089 这里很全
46Java的Object类中的方法及其作用
equal(内部用的==),hashcode,tostring(会把名字和HASHCODE一起打出来)
47Java中 volatile关键字的含义及其使用方法?
在HOTSPOT中,用volatile修饰的变量不会再线程中保存副本,而是直接指向堆中的引用,他比synchronized快十几倍。
volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。
48拦截器
http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors
49简述一下常用的一些算法和其时间复杂度?冒泡、选择、插入、位排序、堆排序、快速排序、二分法排序等?
这个就是个大工程了,包括每个算法最优和最差平均的时间复杂度以及具体实现的代码。
排序:空间复杂度 时间复杂度 是否稳定
1冒泡:最好On 最坏On2 1个额外空间 稳定
2选择:On2 P1 不稳定
for(int i = 0;i < size -1; i ++){
for(int j = i+1;j<size;j++ ){
data[i] data[j] 比较,交换
}
}
冒泡和选择每一轮的结果看上去都是选出了个大的,其他的看情况顺移了,但是实际上冒泡每次都会进行交换,可能最多进行了N次交换,他是顺序的交换。
而选择是针对2个比较交换,如果不满足条件就不会交换。所以选择比冒泡快。
3插入排序:On On2 P1 稳定
for(int i = 0;i < size;i ++){
tmp=data[i];
j = i -1;
while(j >= 0 && tmp>data[j]){
data[j+1] = data[j];
j --;
}
data[j + 1] = tmp;
}
第一次会出现data[-1 + 1] = data[0],注意换的时候是用前面的那个数给后面的数!!是前给后!
比如2 5 6 9
2 5 6 9
2 2 6 9
5 2 6 9
5 2 2 9
5 5 2 9
6 5 2 9
不像冒泡和选择,把那个数放在里面来回倒,直接拎出来,让要移动的数创建个分身到拎出来的数之前的位置,再把拎出来的数替换掉原来分身的数,也就是那个数就只有分身没有原版了。
4希尔排序 On3/2 P1 稳定 适用于大部分数据都已排序完成的情况下
jump = size /2
while(jump != 0){位移间隔 不断/2到0为之
for(int i = jump; i <size; i ++){//一定注意!!这里I=JUMP!!!
tmp=data[i];
j = i - jump;
while(j>=0 && tmp>data[j]){
data[j + jump] = data[j] 后面的等于前面的!
j = j - jmp 这里很巧妙 和下面的话完成了最后的赋值,因为是前面赋值给后面,最后的值又要给前面不能少值,这么处理后就在下面赋值了
}
data[jmp + j ] = tmp 这里很巧妙
}
jump = jump/2
}
比如4个数,JUMP开始为2 【2 5 6 9】
tmp =data[i] = 6
i=jump = 2
j = i - jump = 0
因为j>0且tmp >data0
data0 + 2 = data[0]
J = J- JUMP = -2
data 2+ j = data 2 + -2 赋值为tmp = 2
2569 - 2529 -6529这才是FOR循环中的一次
然后是i= 3了,会一直增加到SIZE-1,不会有漏的情况,如果是奇数个就会变成3个一组了,反正是从后面往前按照JUMP比较的,前面的数组第 1 3项比较完已经有序了,第5项加进来比较没有任何问题,以此类推
5合并排序 ONLOGN PN 稳定
6快速排序 ONLOG2N-ON2 PN-PLOG2N 不稳定,平均运行时间最快的排序,没有之一。
关键在于K的取值,不能太大也不能太小。
WHILE(TRUE){
int K = data【0】
for()左到右找到比K大的KI
for(int i = left + 1;i < right i ++){
if K < KI
break
leftINDEX = I
}
FOR右到左找到比K小的KJ,如果I<J则I J互换 继续左右两头查找
FOR(INT J = RIGH; J > LEFT ; J --){
IF KJ < K
BREAK
RIGHTINDEX = J
}
IF(LEFTINDEX < RIGHTINDEX ){
KI KJ互换
}ELSE{
BREAK;
}
}
K KJ互换 ;
以RIGHTINDEX为基点分为两部分,也就是不包括KJ这个点,注意现在这个点放的其实是之前K的值了
QUICKSORT(INT D[];SIZE;LEFT;RIGHTINDEX-1);
QUICKSORT(INT D[];SIZE;RIGHTINDEX + 1;传到这个方法里的RIGHT的值也就是最右边的INDEX);
如果I >= J 则 K与KJ互换,用J分割数组为两部分,递归方式分别进行快排。
所以需要的参数为 1数组,2大小,3参数1这次要排序的起止位置
}
7堆积排序ONLOGN P1 不稳定
下面想的八成应该是错误的,因为看起来就是一个插入排序,只不过为了维持树还要多移动比较几次。跟堆排序的效率完全是相反。只能叫如何构成完美的堆积数,是完美的,效率还很低的那种。
虽然这里没看明白,但是基本道理还是懂的。
需要一个堆积树,那么就有一个根据数组元素一个一个插入构成堆积树的过程。
构成后顶点的就是最大值,把他拿下来放到树的最后一一个位置,把其他的值再一个一个插入构成一个堆积树,再取下树顶,依次循环这个过程就可以了。
所以关键就是构成堆积树的过程。
插入的过程去想嘛,一个数肯定就是树顶,第二个数比较跟第一个数交换或者放在左1,第三个数跟左1比看互换还是放在右1,互换后再跟顶比,也就是从最下面的右叉开始一个一个比,因为前面的都已经排好序了,第四个再跟右1比,换或者放在左2,所以放在左叉的是第2468.。。这样的偶数,右叉是3开始的奇数。一直在最左侧的,是24816这样每次乘2的结果因为每个节点都会分叉嘛,自然X2.
那么插入的过程 INSERTINTOTREE(DATA[N])
if tree.size
上面说了最左叉是2 4 8 16这样的数 2开始的偶数和他紧挨着的奇数都在一个节点。那就看这个树你用数组是怎么表示了,如果按照顺序1开始到最后就把新加的数从最后一个开始比,直到比他小的数截止,让他和最后一个比他大的数互换,再让那个数作为新的值插入!!!!!!
1 1
2 1< <3
3 3< <8
8基数排序 ONLOGPK K是最大值 P是最大值位数 PN*P N是数据个数 P前面说了是最大值位数 当N很大而P很小时,会很高效。稳定排序
基数排序利用的就是0-9 10个桶因为每个桶可能放的数不确定,所以初始化这个数组可以为[10][N] 也就是二维数组10行 每行最多数组大小的数应付极端情况
第一次根据个位数把数放进桶里,然后从0-9的10个桶依次取其中不为0的数放进原来的数据,因为原来的数组里的数就没有0,所以如果带0,这个数组就可以初始化为都是-1这样的极端情况。
第二次根据十位数把数放进桶,再放回去,如果还有百位就继续这样。
50wait notity notifyall
可以说这3个都是针对对象的,而不是线程的方法,属于OBJECT,而且他们都需要在同步代码块中去执行,WAIT顾名思义把对当前资源的占用让出去,直到被人NOTIFY了他才会继续运行。
这里就要切记一点。线程的同步就是一个加解锁的过程,锁的是什么?看你需要就锁什么。只有持有对相同对象的锁的线程之间,才是同步关系,不同对象的锁互不影响!!
http://www.jb51.net/article/56440.htm
而这个锁对象可以有这么几种:
1类锁,STATIC SYNCHRONIZE 与 FOO.CLASS
2对象锁 SYNCHRONIZE与THIS
3私有锁:都对一个OBJECY同步代码块
也就是这几种锁中是一样的锁对象,他们的代码就会阻塞。
51join yiele
http://www.tuicool.com/articles/BF7Bfq
JOIN就是一个线程A创建好后,把它传入另一个线程B,在B中调用A.JOIN,就会先执行完A再继续执行B。
YIELD相反,也是A传入B,B执行过程中A.YIELD,这时候A就不执行了,等B执行完再执行A。
以上两个方法在特定场景下,什么时候谁优先很重要。
52生产者 消费者模型
http://blog.csdn.net/luohuacanyue/article/details/14648185
也是ACTIVEMQ的基础,竟然用的就是上面的WAIT,NOTIFY,
在说WAIT NOTIFY时我们知道他们共有引用了一个变量,这个变量在P-C中可能就是仓库,直到仓库有东西了,才会NOTIFY去处理,处理完没东西了,继续WAIT。
实际实现过程中还是会遇到很多问题,所以也有一些现成的解决方案:
多线程环境中,通过队列可以很容易实现数据共享,比如经典的“生产者”和“消费者”模型中,通过队列可以很便利地实现两者之间的数据共享。假设我们有若干生产者线程,另外又有若干个消费者线程。如果生产者线程需要把准备好的数据共享给消费者线程,利用队列的方式来传递数据,就可以很方便地解决他们之间的数据共享问题。但如果生产者和消费者在某个时间段内,万一发生数据处理速度不匹配的情况呢?理想情况下,如果生产者产出数据的速度大于消费者消费的速度,并且当生产出来的数据累积到一定程度的时候,那么生产者必须暂停等待一下(阻塞生产者线程),以便等待消费者线程把累积的数据处理完毕,反之亦然。然而,在concurrent包发布以前,在多线程环境下,我们每个程序员都必须去自己控制这些细节,尤其还要兼顾效率和线程安全,而这会给我们的程序带来不小的复杂度。好在此时,强大的concurrent包横空出世了,而他也给我们带来了强大的BlockingQueue。(在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤醒)
http://blog.itpub.net/143526/viewspace-1060365/
先进先出(FIFO):先插入的队列的元素也最先出队列,类似于排队的功能。从某种程度上来说这种队列也体现了一种公平性。
后进先出(LIFO):后插入队列的元素最先出队列,这种队列优先处理最近发生的事件。
concurrent包太屌了,很多东西都有了1.5加入的
countdownlatch
http://www.importnew.com/15731.html
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
53大数据排序?
大数据排序也就是要用到我们说的外部排序,常见的就是归并排序,分成小块再组合,思想是分治法。
http://www.cnblogs.com/springsource/archive/2013/03/20/2970913.html
54数据分组查询后取前几条记录的SQL
语法:ROW_NUMBER() OVER(PARTITION BY COLUMNX ORDER BY COLUMNY)
最下面一层是物理层,关心的是接口,信号,和介质,只是说明标准,如EIA-232接口,以太网,fddi令牌环网
第二层是数据链路层:一类是局域网中数据连路层协议:MAC子层协议,有LLC子层协议.另一类是广域网的协议如:HDLC,PPP,SLIP.
第三层是网络层:主要是IP协议.
第四层是传输层:主要是面向连接的TCP传输控制协议.另一个是不面向连接的UDP用户数据报协议.
第五层是会话层:主要是解决一个会话的开始进行和结束.(真的想不起有什么协议)
第六层是表示层:主要是编码如ASⅡ
第七层是应用层,就是应用程序里面的拉,文件传输协议FTP、电子邮件传输协议SMTP、域名系统服务DNS、网络新闻传输协议NNTP和HTTP协议等。 HTTP协议(Hypertext Transfer Protocol,超文本传输协议)是用于从WWW服务
见实例:此例子中声明了两个Map对象,一个是HashMap,一个是WeakHashMap,同时向两个map中放入a、b两个对象,当HashMap remove掉a 并且将a、b都指向null时,WeakHashMap中的a将自动被回收掉。出现这个状况的原因是,对于a对象而言,当HashMap remove掉并且将a指向null后,除了WeakHashMap中还保存a外已经没有指向a的指针了,所以WeakHashMap会自动舍弃掉a,而对于b对象虽然指向了null,但HashMap中还有指向b的指针,所以
WeakHashMap将会保留
注意2:不是线程安全的。
注意3:迭代器的快速失败行为不能得到保证。
注意4:WeakHashMap是无序的。
注意5:确保值对象不会直接或间接地强引用其自身的键,
* 基于XHTML和CSS标准的表示;
* 使用Document Object Model进行动态显示和交互;
* 使用XMLHttpRequest与服务器进行异步通信;
* 使用JavaScript绑定一切。
这非常好,但为什么要以Ajax命名呢?其实术语Ajax是由Jesse James Garrett创造的,他说它是“Asynchronous JavaScript + XML的简写”。
栈帧由三部分组成:局部变量区,操作数栈和帧数据区。 局部变量区和操作数栈要视对应的方法而定,它们是按照字长计算的。
局部变量区: java栈帧的局部变量区被组织为一个以字长为单位,从0开始计数的数组。字节码指令通过从0开始的索引来使用其中的数据。类型为int,float,reference和returnaddress的值在数组中只占一项,而类型为byte,short和char的值在存入数组前都将被转换为int。但是long和double类型在数组中却占据连续的两项。
操作数栈和局部变量区一样。也被组织成一个以字长为单位的数组。但是不是通过索引来访问,而是通过标准栈操作--压栈和出栈来访问。
不同于程序计数器,java虚拟机没有寄存器,程序计数器也无法被程序指令直接访问。java虚拟机是由操作数栈而不是从寄存器中取得操作数的,因此它的运行方式是基于栈的而不是基于寄存器的。
虚拟机把操作数栈作为它的工作区--大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈
第一,继承不同。
public class Hashtable extends Dictionary implements Map public class HashMap extends AbstractMap implements Map
第二
Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
第三
Hashtable中,key和value都不允许出现null值。
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
第四,两个遍历方式的内部实现上不同。
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
第五
哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
第六
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
每组前几条记录的SQL写
每组前几条记录的SQL写
每组前几条记录的SQL写
每组前几条记录的SQL写