JD、QQ12

1、set集合从原理上如何保证不重复 1)在往set中添加元素时,如果指定元素不存在,则添加成功。也就是说,如果set中不存在(e==null ? e1==null : e.queals(e1))的元素e1,则e1能添加到set中。
2)具体来讲:当向HashSet中添加元素的时候,首先计算元素的hashcode值,然后用这个(元素的hashcode)%(HashMap集合的大小)+1计算出这个元素的存储位置,如果这个位置位空,就将元素添加进去;如果不为空,则用equals方法比较元素是否相等,相等就不添加,否则找一个空位添加。
2、HashMap和HashTable的主要区别是什么?,两者底层实现的数据结构是什么? HashMap:
HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。
HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。
HashMap存数据的过程是:
HashMap内部维护了一个存储数据的Entry数组,HashMap采用链表解决冲突,每一个Entry本质上是一个单向链表。当准备添加一个key-value对时,首先通过hash(key)方法计算hash值,然后通过indexFor(hash,length)求该key-value对的存储位置,计算方法是先用hash(key)位运算length,这就保证每一个key-value对都能存入HashMap中,当计算出的位置相同时,由于存入位置是一个链表,则把这个key-value对插入链表头。
HashMap中key和value都允许为null。key为null的键值对永远都放在以table[0]为头结点的链表中。HashMap内存储数据的Entry数组默认是16.HashMap内部扩容机制
变量size,它记录HashMap的底层数组中已用槽的数量;
变量threshold,它是HashMap的阈值,用于判断是否需要调整HashMap的容量(threshold = 容量*加载因子)
变量DEFAULT_LOAD_FACTOR= 0.75f,默认加载因子为0.75
HashMap扩容的条件是:当size大于threshold时,对HashMap进行扩容
扩容是是新建了一个HashMap的底层数组,而后调用transfer方法,将就HashMap的全部元素添加到新的HashMap中(要重新计算元素在新的数组中的索引位置)。 很明显,扩容是一个相当耗时的操作,因为它需要重新计算这些元素在新的数组中的位置并进行复制处理。因此,我们在用HashMap的时,最好能提前预估下HashMap中元素的个数,这样有助于提高HashMap的性能。扩容时可能会出现无限循环问题。
HashMap共有四个构造方法。构造方法中提到了两个很重要的参数:初始容量和加载因子。这两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中槽的数量(即哈希数组的长度),初始容量是创建哈希表时的容量(从构造函数中可以看出,如果不指明,则默认为16),加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 resize 操作(即扩容)。
HashTable:
Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。
Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。
Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
HashMap和HashTable的区别:
二者都实现了Map 接口,是将惟一键映射到特定的值上;主要区别在于:
1)HashMap 没有排序,允许一个null 键和多个null 值,而Hashtable 不允许,若有会报空指针异常;
2)HashMap 把Hashtable 的contains 方法去掉了,改成containsvalue 和
containsKey,因为contains 方法容易让人引起误解;
3)Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。
4)Hashtable 的方法是Synchronize 的,而HashMap 不是,在多个线程访问Hashtable 时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。Hashtable 和HashMap 采用的hash/rehash 算法大致一样,所以性能不会有很大的差异。
hashmap线程不安全可能:put方法、addEntry方法、删除方法
5)Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
6)HashMap和哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。
Hashtable计算hash值,直接用key的hashCode(),而HashMap重新计算了key的hash值,Hashtable在求hash值对应的位置索引时,用取模运算,而HashMap在求位置索引时,则用与运算,且这里一般先用hash&0x7FFFFFFF后,再对length取模,&0x7FFFFFFF的目的是为了将负的hash值转化为正值,因为hash值有可能为负数,而&0x7FFFFFFF后,只有符号外改变,而后面的位都不变。
8)HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。
HashTable的底层实现数据结构:
HashMap和Hashtable的底层实现都是数组+链表结构实现的。
JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
3、HashMap何时扩容,扩容的算法是什么? HashMap何时扩容:
当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值---即当前数组的长度乘以加载因子的值的时候,就要自动扩容
扩容的算法是什么:
扩容(resize)就是重新计算容量,向HashMap对象里不停的添加元素,而HashMap对象内部的数组无法装载更多的元素时,对象就需要扩大数组的长度,以便能装入更多的元素。当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组


JD、QQ12
文章图片
JD、QQ12
文章图片
4、Java的虚拟机JVM的两个内存:栈内存和堆内存的区别是什么? Java把内存划分成两种:一种是栈内存,一种是堆内存。两者的区别是:
1)栈内存:在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
2)堆内存:堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
5、Java中对异常是如何进行分类的?
Throwable分为两个分支:Error和Exception
一、Error
1、Error类层次描述了Java运行时系统的内部错误和资源耗尽错误。对于这类错误是无法难通过程序来解决的,所以程序不应该抛出这种类型的对象。如果出现了这样的内部错误,除了通知给用户,并尽力使程序安全地终止。当然这类情况是很少出现的
二、Exception
在设计Java程序时,Exception是我们需要重点关注的错误,在Java程序中Exception又可以分为两类:Runtime Exception、其它异常如:IOException。
1、派生于Runtime Exception 的异常主要包含以下几种情况
错误的类型转换
数组访问越界
访问空指针
2、不是派生于Runtime Exception的异常包含
试图在文件尾部读取数据
试图打开一个错误格式的URL
试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
运行时异常和检查性异常
1、在Java语言中将派生于Error或RuntimeException类的所有异常称为运行时异常,这类异常我们可以不处理,当出现这个的异常时,总是由虚拟机接管,比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。运行时异常我们常见的有ClassCastException(类转换异常)、IndexOutOfBoundsException(数组越界)、NullPointerException(空指针)、ArrayStoreException(数据存储异常,操作数组时类型不一致)、还有IO操作的BufferOverflowException异常;
2、除了运行时异常,其它的异常都被称为检查性异常,我们经常遇到的IO异常及sql异常就属于检查式异常。对于这种异常,Java编译器要求我们必须对出现的这些异常进行catch 所以 面对这种异常不管我们是否愿意,只能自己去写一堆catch来捕捉这些异常。常见的查检性异常有:FileNotFoundException 文件不存在异常、SQLException SQL异常等。
一、使用throws抛出异常
二、使用try{....}catch(){....}finally{....}捕捉异常


6、数据库设计中常讲的三范式是指什么? 1)第一范式1NF(域的原子性)
如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式
2)第二范式2NF(表中除主键外的字段都完全依赖主键)
第二范式是在第一范式基础上建立的。第二范式有两个重点:(1)表中必须有主键;(2)其他非主属性必须完全依赖主键,不能只依赖主键的一部分(主要针对联合主键而言)。
3)第三范式3NF(表中除主键外的字段都完全直接依赖,不能是传递依赖)
不能是传递依赖,即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。第二范式和第三范式区分的关键点:2NF:非主键列是否完全依赖于主键,还是依赖于主键的一部分;3NF:非主键列是直接依赖于主键,还是直接依赖于非主键列。
7、Java中的线程池共有几种? Java四种线程池
第一种:newCachedThreadPool
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
第二种:newFixedThreadPool
创建一个指定工作线程数量的线程池
第三种:newScheduledThreadPool
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
第四种:newSingleThreadExecutor
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
8、volatile和synchronized区别 volatile和synchronized简介:
在Java中,为了保证多线程读写数据时保证数据的一致性,可以采用两种方式:
1)使用synchronized关键字
2)使用volatile关键字:用一句话概括volatile,它能够使变量在值发生改变时能尽快地让其他线程知道。
两者的区别:
1)volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
2)volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.
3)volatile仅能实现变量的修改可见性,而synchronized则可以保证变量的修改可见性和原子性.
4)volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.
两者原理:
1.synchronized:monitor 监视器;monitor enter,monitor exit
2.volatile:内存屏障,会在处理器上加一个Lock指令
9、Spring的特性 1.方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。
2.AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程。
3.声明事物的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4.方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
6.降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
10、spring aop的应用场景: AOP用来封装横切关注点,具体可以在下面的场景中使用
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务
11、Mybaits中#和$区别 1)${}是Properties文件中的变量占位符,它可以用于标签属性值和sql内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdbc.Driver。
2)#{}是sql的参数占位符,Mybatis会将sql中的#{}替换为?号,在sql执行前会使用PreparedStatement的参数设置方法,按序给sql的?号占位符设置参数值,比如ps.setInt(0, parameterValue),#{item.name}的取值方式为使用反射从参数对象中获取item对象的name属性值,相当于param.getItem().getName()。
12、排序都有哪几种方法?请列举。用JAVA 实现一个快速排序。 排序的方法有:
插入排序(直接插入排序、希尔排序),交换排序(冒泡排序、快速排序),选择排序(直接选择排序、堆排序),归并排序,分配排序(箱排序、基数排序);
快速排序的伪代码:
//使用快速排序方法对a[ 0 :n- 1 ]排序
从a[ 0 :n- 1 ]中选择一个元素作为middle,该元素为支点;
把余下的元素分割为两段left 和right,使得left 中的元素都小于等于支点,
而right 中的元素都大于等于支点;
递归地使用快速排序方法对left 进行排序;
递归地使用快速排序方法对right 进行排序;
所得结果为left + middle + right。
【JD、QQ12】快速排序的Java代码实现如下:
JD、QQ12
文章图片
JD、QQ12
文章图片

    推荐阅读