Java基础
1、集合Hash系列:HashMap,HashTable,HashSet,ConcurrentHashMap的区别(未完)
数据结构 | 原理 | 线程安全 | 初始容量 | 扩容机制 | 有否有序 | |
HashMap | jdk1.7及以前:链表+数组的数据结构 jdk1.8:链表+数组+红黑树的数据结构 用Entry数组实现哈希表 | 使用键值对的方式来存储数据,可存储null的键和值。在jdk1.7中,会直接找到数组的第一个节点,去寻找有没有null的键,有则将value替换,没有则将该元素添加到第一个节点链表的表头;jdk1.8中也是类似,它是插入的时候将null的键的hash设为了0 | 非线程安全 | 16 | 当HashMap新添元素的时候,会判断元素的个数是否大于容量*负载因子0.75,如果大于,则进行扩容,扩容的容量为原容量的2倍 | 无序 |
TreeMap | 是一个有序的key-value集合,是通过红黑树实现的。 | 可以对元素进行排序,是基于元素的固有属性(由Comparator或者Comparable确定,要么传入Comparator实现,要么key对象实现Comparable接口)排序的 | 非线程安全 | 有序 | ||
LinkedHashMap | 基于HashMap | 继承自HashMap,在HashMap的基础上,新增了一个链表,用来存放元素的顺序,基于元素进入集合的顺序或被访问的先后顺序排序 | 非线程安全 | 有序 | ||
HashTable | 也是使用链表+数组的数据结构,用Entry数组实现哈希表,就是说数组中存储的是Entry | 不允许null的键和值 | 线程安全 | 11 | 也是根据容量*负载因子0.75和元素个数作比较,扩容后的长度为2n+1 | |
HashSet | 基于HashMap实现 | 存储的是对象,存放位置为key
| 非线程安全 | 无序 | ||
TreeSet | 基于TreeMap实现 | 非线程安全 | 有序 | |||
LinkedList | 由相互引用的节点组成的双向链表 | 非线程安全 | ||||
ArrayList | 可变长的数组 | 非线程安全 | 10 | 插入数据的时候,首先会判断长度,长度不够的会将原来的长度乘以1.5,得到新的长度,然后创建一个新的数组,将原数组的数据复制进去,再将要添加的元素添加到新数组 | ||
Vector | 可变长的数组 | 线程安全 | 10 | 根据capacityIncrement增长系数来增长,可通过创建对象是指定,如不指定则根据默认方式实现增长 | ||
Stack | 线程安全 |
https://blog.csdn.net/gldemo/article/details/44653787
HashMap实现了Map接口,是一种数组+链表的数据结构,使用键值对来存储数据,默认初始长度为16,元素存储规则:通过元素的key的哈希值对数组长度取模得到的,即hash(key)%len。key和value可为null,因为在put时,将null的hashcode设为0,HashMap是非线程安全的,但是Collections框架提供方法使其同步,Collections.synchronizedMap(new HashMap()),当hashmap元素的个数大于数组大小乘以负载因子时进行扩容,容量为2的倍数
jdk8中HashMap为数组+红黑树+链表的数据结构
HashTable也是实现了Map接口,和HashMap一样是键值对存储的结构,它的方法都是前面都有synchronized修饰,都是线程安全的,,不允许null的键和值
HashSet实现了Set接口,它使用的是HashMap的底层结构,它存储的不是键值对,而是对象,不允许有重复值
线程安全:HashTable,ConcurrentHashMap
非线程安全:HashMap,HashSet
2、ArrayList和LinkedList的区别(未完)
ArrayList是一个动态数组的结构,jdk8中初始长度为10,add添加元素的时候,首先判断数组的长度,如果不够长,则进行自动扩容,扩容大小为数组长度乘以1.5,新增或删除数据的时候需要改变该数据后面的数据的索引,效率较低
LinkedList是一个基于链表的数据结构,内存是分散的,查找较慢,新增或删除效 率高,只需要改变前后元素指向的位置
ArrayList和LinkedList都是非线程安全的
3、实现线程安全的方式
参考 https://www.cnblogs.com/lizhangyong/p/8029287.html
第一,同步代码块,由synchronized关键字修饰的语句块,即为同步代码块。同步代码块会被JVM自动加上内置锁,从而实现同步
第二,同步方法,由synchronized关键字修饰的方法,由于java每个对象都有一个内置锁,当用此关键字修改方法时,内置锁会保护整个方法,在调用该方法前,需要获得内置锁,否则就处于阻塞状态
第三,Lock锁机制,通过创建Lock对象,采用lock()加锁,采用unlock()解锁,来保护指定代码块
由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否;而ReentrantLock是使用代码实现的,系统无法自动释放锁,需要在代码中的finally子句中显示释放锁lock.unlock()
4、锁有哪些,含义是什么
可重入锁:又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。
独享锁:指该锁一次只能被一个线程所持有,读写锁(ReadWriteLock)中的写锁就是独享锁
共享锁:指该锁可被多个线程所持有,读写锁中的读锁就是共享锁。
分段锁:是一种锁的设计,并不是具体锁的一种,对于ConcurrentHashMap而言,其并发的实现就是通过分段的形式来实现高效的并发操作。
我们以ConcurrentHashMap
来说一下分段锁的含义以及设计思想,ConcurrentHashMap
中的分段锁称为Segment,它即类似于HashMap(JDK7与JDK8中HashMap的实现)的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)。
当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在那一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入。
但是,在统计size的时候,或者是获取hashmap全局信息的时候,就需要获取所有的分段锁才能统计。
分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。
自旋锁:是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU
5、final,finally,finalize的区别
final是修饰符,可声明类、代表类不能被继承;可声明变量,代表变量不可改变;可声明方法,代表方法不能被重写
finally是异常捕捉机制的一部分,通常放在try...catch后面表示总是执行代码块
finalize是垃圾回收机制的一个方法,在垃圾收集器将对象从内存中清除出去之前做必要的清理工作,这个方法是在垃圾收集器在销毁对象时调用的,它是在Object类中定义的,因此所有类都定义了它,子类覆盖finalize()方法以整理系统资源或者执行其他清理工作
6、同步代码块介绍
7、内部类介绍
8、基本数据类型的长度
4个整数的基本数据类型:byte,short,int,long
字节数(一个字节8位) | 范围 | |
byte | 1 | -2^7~2^7-1 |
short | 2 | -2^15~2^15-1 |
int | 4 | -2^31~2^31-1 |
long | 8 | -2^63~2^63-1 |
double和float:
位数 | 默认值 | 定义举例 | 错误例子 | ||
float | 单精度 | 32 | 0.0f | float f1 = 6.26F | float f1 = 6.26(错误,浮点数默认类型是double类型) |
double | 双精度 | 64 | 0.0d | double d1 = 123.4 |
9、使用多线程时,要将外部变量设置为final
10、枚举
11、java的三大特性
封装:是面向对象编程的核心思想,将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏实现的细节,这就是封装的思想
继承:子类继承父类的特征和行为,使得子类对象具有父类对象的属性和方法
多态:同一个行为具有多种不同的表现形式或形态的能力,同一个接口,使用不同的实例而执行不同的操作
12、面向对象和面向过程的区别
面向对象是把构成问题的事物分解成一个个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个调用就可以了。
优缺点:面向过程优点是性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源,缺点是没有面向对象易维护、易复用、易扩展。
面向对象的优点是易维护、易复用、易扩展,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护,缺点是性能比面向过程低。
13、接口和抽象类的区别
接口是对动作的抽象,抽象类是对事物的抽象
抽象类表示的是这个对象是什么,接口表示的是这个对象能做什么
接口中的变量只能是全局常量(public static final),方法只能是抽象方法
抽象类中除了接口中包含的全局常量,还可以有普通的变量,方法除了抽象方法,还可以有非抽象方法
14、==和equals的区别
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
int n=3;
int m=3;
System.out.println(n==m);//true
String str = new String("hello");
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1==str2);//false
str1 = str;
str2 = str;
System.out.println(str1==str2);//true
Integer p = 10000;
Integer q = 10000;
System.out.println(p == q);//false
System.out.println(p.equals(q));//true
}
}
对于==,如果作用于基本数据类型的变量,则直接比较其存储的“值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址。
对于equals方法,注意:equals方法不能作用于基本数据类型的变量,
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址,
诸如String、Date等类对equals方法进行重写的话,比较的是所指向的对象的内容
框架部分
spring框架的原理
答:spring框架的核心是控制反转(IOC)和面向切面编程(AOP)。
控制反转指的是将控制权从对象转移到容器,由容器根据配置文件来创建实例并创建各个实例之间的依赖关系,它的核心是bean工厂(beanfactory),在spring中,bean工厂创建的各个实例称为bean。
面向切面编程可以为某一类对象进行监督和控制,可以在调用这类对象的具体方法的前后去调用我们指定的模块,从而达到对一个模块扩充的功能(这是通过配置文件完成的)。
spring的三种注入方式
setter,interface,constructor
spring的核心接口及核心类,核心配置文件是什么?(未完)
主要的核心类是BeanFactory,由它来实现IOC和DI
ApplicationContext ac = new FileXmlApplicationContext("appliactionContext.xml");
Object obj = ac.getBean("id值");
spring中用到了哪些设计模式
https://www.cnblogs.com/yuefan/p/3763898.html
单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。
核心提示点:Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope=“?”来指定
观察者模式(Observer)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
工厂模式(Factory Method)
代理模式(Proxy)
为其他对象提供一种代理以控制对这个对象的访问。 从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。
spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。
包装器模式(Decorator)
spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
适配器模式(Adapter)
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
策略模式(Strategy)
模板方法模式(Template Method)
适配器模式(Adapter)
springmvc的流程
答:
springmvc中控制器和服务类是如何写的,路径是如何定义的
答:
spring的AOP的使用场景有哪些
答:
spring的scope介绍
https://www.cnblogs.com/qq78292959/p/3716827.html
缓存介绍
答:
前端技术
ajax是如何调用的
答:
jquery有哪些选择器
答:
23种设计模式
参考https://www.cnblogs.com/tongkey/p/7170826.html
写一个设计模式
单例模式(考虑线程安全问题)
public class SingleTon {
private static SingleTon instance = null;
public static SingleTon getInstance() {
if(instance == null) {
synchronized(SingleTon.class) {
if(instance == null) {
instance = new SingleTon();
}
}
}
return instance;
}
private SingleTon(){
}
}
面向对象的七种设计原则
参考https://www.cnblogs.com/WuXuanKun/p/5386495.html
1、依赖倒置原则
高层模块不应该依赖低层模块,两者都应该依赖其抽象
抽象不应该依赖细节
细节应该依赖抽象
2、单一职责原则
核心:解耦和增强内聚
3、开闭原则
核心:对扩展开发,对修改关闭,即在设计一个模块的时候,应该使这个模块可以在不被修改的前提下被扩展
4、里氏替换原则
5、接口分离原则
6、合成复用原则
7、迪米特原则
数据库设计
数据库中的字段类型有哪些(以oracle数据库为例子)
char,nvarchar2,varchar2,number,date,timestamp,blob,cblob,long,long raw,raw
char和varchar2的区别
char的长度是固定的,而varchar2的长度是可变的。比如存储字符串“abc”,对于char(20),表示你存储的字符将占20字符(包括17空字符串),在数据库中它是以空格的,而同样的varchar2(20)则只占用3个字节的长度,20只是最大值,当你存储的字符小于20时,按实际长度存储。
char的效率比varchar2高
CHAR与VARCHAR2是一对矛盾的统一体,两者是互补的关系.VARCHAR2比CHAR节省空间,在效率上比CHAR会稍微差一些,即要想获得效率,就必须牺牲一定的空间,这也就是我们在数据库设计上常说的‘以空间换效率’。VARCHAR2虽然比CHAR节省空间,但是假如一个VARCHAR2列经常被修改,而且每次被修改的数据的长度不同,这会引起‘行迁移’(RowMigration)现象,而这造成多余的I/O,是数据库设计和调整中要尽力避免的,在这种情况下用CHAR代替VARCHAR2会更好一些。
oracle和mysql的左连接的区别
oracle中可以使用(+)做外连接,mysql中left join .. on来做左外连接
行转列是什么意思
https://blog.csdn.net/mezheng/article/details/7426765
JVM是怎么实现synchronized锁的:
ConcurrentHashMap是怎么实现线程安全的,线程安全实现的方式是什么:
这两年工作以来,你最擅长的技术是什么
红黑树的原理:
wsdl的原理: