61.Path和ClassPath的区别?
PATH是你要使用编译器的命令时,去寻找的路径。 CLASSPATH是你要编译时,对编译文件的操作时找被编译文件的路径 一个是对于操作者来说的,一个是对于被操作者来说的
62.GC机制讲一讲
GC:垃圾回收站,是将java的无用的堆对象进行清理,释放内存,以免发生内存泄露。
1.引用计数: 当一个对象A被其他对象B引用时,对象A引用+1,断开引用则-1,GC工作时,会检查所有对象中的引用计数,如果为0则代表要清除,>0则表示有其他对象引用不能清除。这种机制有一个致命缺点,就是当两个对象互引用时,在遍历时可能会发生这两个对象引数永远不为0,则永远不会被删除。此机制java从不使用。
2. 停止-复制: 程序暂停运行,启动GC,GC从堆或静态存储区开始遍历所有对象,判断对象是否“活”的对象,如果是活不删除,反之删除。判断是否“活”就是判断该对象是否有被其他对象引用,从链上去查找。当是活对象时,GC会从另外堆里开避一个大空间,然后将活对象复制一份到新空间里,在复制时按着紧密排列,同时更新所有引用地址为新的地址,不活对象原封不动。遍历完后,再遍历一次,这次是将不活的对象彻底给删除。
3. 标记-删除: 程序暂停运行,启动GC,GC从堆或静态存储区开始遍历所有对象,判断对象是否“活”的对象,如果是活不删除,反之删除。判断是否“活”就是判断该对象是否有被其他对象引用,从链上去查找。当是活对象时,会给对象给个标记符号,死对象则不标记,遍历完后,第二次遍历时,只保留标记的对象,把所有没标记的对象都删除。
java GC具体工作原理: JVM分配内存是以较大的块为单位,如果对象为较大,则该对象本身为一个块。GC先启动“停止-复制”模式,遍历对象时,遇到活对象,则把对象复制到新块里,同时块代数+1,如果对象较大,则保持不动,代数+1;如果检测到垃圾对象稀少,则自动切换到“标记-删除”模式,如果检测到对象分布到内存太零散,则又会自动切换到“停止-复制”模式来重新整理内存紧密分布。这就是自适应技术。
63.数据库驱动为什么使用反射调用不直接new
因为反射是运行时根据全类名动态生成的Class对象,完全可以把这个全类名写在xml或者properties中去,不仅从代码上解耦和,而且需要更换数据库时,不需要进行代码的重新编译,这比直接new对象更加灵活,更符合实际应用场景
64.阻塞队列
在前面我们接触的队列都是非阻塞队列,比如PriorityQueue、LinkedList(LinkedList是双向链表,它实现了Dequeue接口)。 使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素。当队列中有元素后,被阻塞的线程会自动被唤醒(不需要我们编写代码去唤醒)。这样提供了极大的方便性。
65.JAVA集合类了解吗?简单介绍一下?
JAVA集合类主要分为两大体系:Collection和Map体系。其中Collection又派生出List、Set、Queue等三大体系。
其中,List主要用来存放一些有序、可重复的元素;主要实现类有:ArrayList、LinkedList、Vector和Stack。
① ArrayList是基于数组实现的,增删改比较慢,查询比较快。
② LinkedList是基于链表实现的,与ArrayList正好相反,它的增删改比较快,查询比较慢。
③ Vector也是基于数组实现的,但它是线程安全的类,一般不推荐使用。
④ Stack是Vector的派生类,是“栈”数据结构的应用,具有后进显出的特点,也是线程安全的,一般不推荐使用,因为效率比较低。(那么在多线程环境中,如何保证线程安全那?通过代码来保证同步)
Set主要用来存放一些无序、不可重复的元素。主要实现类有:HashSet、TreeSet、LinkedHashSet。
① HashSet按照Hash算法来存储集合元素,具有很好的存取和查找性能,常用。
② TreeSet是SortedSet接口的实现类,采用红黑树数据结构存储集合元素,可以保证集合元素处于有序状态,不是元素插入顺序,而是元素实际大小数据。
③ LinkedHashSet是HashSet的子类,根据Hash值决定元素存放位置,同时使用链表维护元素次序,以插入顺序保存元素。性能低于HashSet,但是迭代访问Set里全部元素时具有很好的性能。
Queue是基于队列实现的,通常采用先进先出存储元素。主要实现类有PriorityQueue、ArrayDeque实现类。
① PriorityQueue 标准的队列实现类,按照元素实际大小重新排序保存。最后取出的是最小元素,而不是最先插入的元素。
② ArrayDeque 基于数组实现的双端队列。
Map 保存的键值对数组。主要实现类有HashMap、HashTable、LinkedHashMap.
① HashMap 非线程安全类,可以使用Null作为键或值。
② HashTable 线程安全类,不能使用Null作为键或值。
③ LinkedHashMap.是HashMap的子类。
66.任何自定义类都能放入hashmap吗?有什么要求?如何实现?
要重写hashCode()和equals()两个方法才能实现自定义键在HashMap中的查找
67.MySQL主键与索引的区别和联系
1. 主键一定是唯一性索引,唯一性索引并不一定就是主键。 所谓主键就是能够唯一标识表中某一行的属性或属性组,一个表只能有一个主键,但可以有多个候选索引。主键可以保证记录的唯一和主键域非空,数据库管理系统对于主键自动生成唯一索引,所以主键也是一个特殊的索引。
2. 一个表中可以有多个唯一性索引,但只能有一个主键。
3. 主键列不允许空值,而唯一性索引列允许空值。 4. 索引可以提高查询的速度。
68.java中的乐观锁与悲观锁
悲观锁:一段执行逻辑加上悲观锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放.
乐观锁:一段执行逻辑加上乐观锁,不同线程同时执行时,可以同时进入执行,在最后更新数据的时候要检查这些数据是否被其他线程修改了(版本和执行初是否相同),没有修改则进行更新,否则放弃本次操作. 从解释上可以看出,悲观锁具有很强的独占性,也是最安全的.而乐观锁很开放,效率高,安全性比悲观锁低,因为在乐观锁检查数据版本一致性时也可能被其他线程修改数据.
69.equals与hashcode的区别,存入集合时的判断过程
在Java中任何一个对象都具备equals(Object obj)和hashCode()这两个方法,因为他们是在Object类中定义的。equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。 hashCode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。
总结:
1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。
2.equals和hashCode需要同时覆盖。
3.若两个对象equals返回true,则hashCode有必要也返回相同的int数。
4.若两个对象equals返回false,则hashCode不一定返回不同的int数,但为不相等的对象生成不同hashCode值可以提高哈希表的性能。
5.若两个对象hashCode返回相同int数,则equals不一定返回true。
6.若两个对象hashCode返回不同int数,则equals一定返回false。
7.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。
70.java的内存模型,什么数据放在什么区域
栈区: 栈分为java虚拟机栈和本地方法栈
1)重点是Java虚拟机栈,它是线程私有的,生命周期与线程相同。
2)每个方法执行都会创建一个栈帧,用于存放局部变量表,操作栈,动态链接,方法出口等。每个方法从被调用,直到被执行完。对应着一个栈帧在虚拟机中从入栈到出栈的过程。
3)通常说的栈就是指局部变量表部分,存放编译期间可知的8种基本数据类型,及对象引用和指令地址。局部变量表是在编译期间完成分配,当进入一个方法时,这个栈中的局部变量分配内存大小是确定的。
4)会有两种异常StackOverFlowError和 OutOfMemoneyError。当线程请求栈深度大于虚拟机所允许的深度就会抛出StackOverFlowError错误;虚拟机栈动态扩展,当扩展无法申请到足够的内存空间时候,抛出OutOfMemoneyError。
5)本地方法栈 为虚拟机使用到本地方法服务(native)
堆区:
1)堆被所有线程共享区域,在虚拟机启动时创建,唯一目的存放对象实例。
2)堆区是gc的主要区域,通常情况下分为两个区块年轻代和年老代。
3)会有异常OutOfMemoneyError
方法区:
1)被所有线程共享区域,用于存放已被虚拟机加载的类信息,常量,静态变量等数据。被Java虚拟机描述为堆的一个逻辑部分。习惯是也叫它永久代(permanmentgeneration)
2)垃圾回收很少光顾这个区域,不过也是需要回收的,主要针对常量池回收,类型卸载。
3)常量池具有一定的动态性,里面可以存放编译期生成的常量;运行期间的常量也可以添加进入常量池中,比如string的intern()方法。
程序计数器:
1)当前线程所执行的行号指示器。通过改变计数器的值来确定下一条指令,比如循环,分支,跳转,异常处理,线程恢复等都是依赖计数器来完成。
2)Java虚拟机多线程是通过线程轮流切换并分配处理器执行时间的方式实现的。为了线程切换能恢复到正确的位置,每条线程都需要一个独立的程序计数器,所以它是线程私有的。
3)唯一一块Java虚拟机没有规定任何OutofMemoryError的区块