面试总结v1.0
面试总结v1.0
- 基本数据类型
- String相关问题
- final,finally ,finalize
- hashmap相关
- 索引相关
- Spring注解
1. 基本数据类型
整型: byte , short,int ,long
浮点型:float ,double
字符型:char
布尔类型:boolean
2.String 相关问题
2.1 String 是否是基本数据类型?
答:不是。String 是引用数据类型,除了string之外,引用数据类型还有:接口,枚举,数组,注解类型,共5种
扩展:基本数据类型和应用数据类型的区别
基本数据类型在被创建时,在栈上给其划分一块内存,将数值直接存储在栈上。
引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。
2.2 String是否是可变的?
答:不可变,因为String 有final 修饰(这是表象),不可以被继承,这样做的目的是为了线程安全着想。
String 底层是一个char[]数组,而且是用final修饰的;这里的final修饰不可变指的是stack里的这个value的应用地址是不可变的,但是在堆中value本身数据是可以发生变化的。(也可以理解为一个被final 修饰的数组,地址不会发生变化,但是其数据会发生变化)
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage.(值用char保存)*/
private final char value[];
以int数组为例做示范:
final int[] arr = {1, 2, 3};
System.out.println(arr);
arr[2] = 100;
System.out.println(arr);
System.out.println(Arrays.toString(arr));
/**
输出结果:
[aaa@qq.com
[aaa@qq.com
[1, 2, 100]
*/
2.3 final修饰在方法,类,变量,对象前的区别
- 修饰在方法前:方法不可重写
- 修饰在类前:无子类,不可被继承或重写
- 修饰在变量前:修饰的变量,为常量,值不可变
- 修饰在对象前:值可变,引用不可变
3.final,finally ,finalize
- final:用于声明属性,方法和类,表示属性不可变,方法不可被重写,类不可被继承。
- finally: 是异常处理语句结构的一部分,表示总会执行
- finalize:finalize是方法名,是object类的一个方法,在垃圾收集器执行的时候会调用这个对象回收的方法。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的,子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。
4. hashmap 相关
4.1 hashmap的数据结构是什么?
答:JDK1.8之前 链表+数组
JDK1.8之后 数组+红黑树(下面详解)
4.2 hashmap的默认容量(长度)时多少?
答:默认长度是16
/**
* The default initial capacity - MUST be a power of two.(默认容量 16)
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30. (最大容量1*2^30)
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* The load factor used when none specified in constructor.(负载因子0.75)
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/** 8就从 链表 转 树
* The bin count threshold for using a tree rather than list for a
* bin. Bins are converted to trees when adding an element to a
* bin with at least this many nodes. The value must be greater
* than 2 and should be at least 8 to mesh with assumptions in
* tree removal about conversion back to plain bins upon
* shrinkage.
*/
static final int TREEIFY_THRESHOLD = 8;
/** 6就从树转链表
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
*/
static final int UNTREEIFY_THRESHOLD = 6;
4.3 HashMap和Hashtable的区别
答:
- 产生的时间不同:hashtable 是java一开始发布就提供的键值映射的数据结构;hashmap产生于JDK1.2(目前hashtable基本已启用,且没有遵循驼峰命名法)
- 继承的父类不同:HashMap 继承的是AbstracMap类,Hashtable继承的是Dictionary类。但是他们都实现了map,Cloneable(可复制)、Serializable(可序列化)这三个接口
- 对Null key 和Null value的支持不同 :Hashtable既不支持Null key也不支持Null value。HashMap中null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null
- 线程安全性不同 :Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法;HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题.(ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。是将HashMap安全的一种方式)
- 遍历方式的内部实现上不同 (JDK8之前):Hashtable、HashMap都使用了 Iterator。由于历史原因,Hashtable还使用了Enumeration的方式 ,HashMap的Iterator是fail-fast迭代器。JDK8之后都是fail-fast迭代器。
- 初始容量大小和每次扩充容量大小的不同 :Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1(素数,奇数)。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍(2的幂次方大小)。
- 计算hash值的方法不同 :Hashtable直接使用对象的hashCode;HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
4.4 hashmap是线程安全的吗?
答:不安全,因为hashmap超过临界值时会进行扩容,进行resize()(rehash)操作在多线程情况下,会导致hashmap出现链表闭环,一旦进入了闭环get数据,程序就会进入死循环,所以导致HashMap是非线程安全的。
扩展:
1.HashMap的底层存储结构,HashMap底层是一个Entry数组,一旦发生Hash冲突的的时候,HashMap采用拉链法解决碰撞冲突
2.当多个线程同时检测到总数量超过门限值的时候就会同时调用resize操作,各自生成新的数组并rehash后赋给该map底层的数组table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会有问题。
3. 代码验证HashMap线程不安全
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < 100; i++) {
MyThread myThread = new MyThread(map, "线程名字:" + i);
myThread.start();
}
}
static class MyThread extends Thread {
public Map map;
public String name;
public MyThread(Map map, String name) {
this.map = map;
this.name = name;
}
public void run() {
double i = Math.random() * 100000;
map.put("键" + i, "值" + i);
try{
Thread.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
map.remove("键" + i);
System.out.println(name + "当前时间:" + i + " size = " + map.size());
}
4.5 怎样让hashmap变成线程安全?
答:1.替换成Hashtable,效率比较低
2.使用Collections类的synchronizedMap方法包装一下。
方法如下:
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
返回由指定映射支持的同步(线程安全的)映射
3.使用ConcurrentHashMap,它使用分段锁来保证线程安全。
说明:在JDK8中 ConcurrentHashMap摒弃了 Segment(锁段)的概念,而是启用了一种全新的方式实现,利用 CAS 算法
4.6 怎样解决hash冲突?
答:1.开放定址法(线性探测在散列,二次探测再散列,伪随机探索再散列)
2.再哈希法
3.链地址法
4.建立一个公共溢出区
5.索引相关
5.1 什么是索引
答:在关系数据库中,索引是存储的表中一个特定列的值数据结构(最常见的是B-Tree)
在数据库系统中建立索引主要有以下作用:
(1)快速取数据;
(2)保证数据记录的唯一性;
(3)实现表与表之间的参照完整性;
(4)在使用ORDER by、group by子句进行数据检索时,利用索引可以减少排序和分组的时间。
5.2 索引的优缺点
优点
1.大大加快数据的检索速度;
2.创建唯一性索引,保证数据库表中每一行数据的唯一性;
3.加速表和表之间的连接;
4.在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。
缺点
1.索引需要占物理空间。
2.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。
5.3 索引是不是越多越好?
答:不是,因为索引也需要更新,多的时候也会影响效率
也可以自己拓展了解一下关于哈希索引
6.Spring 注解
Bean容器相关的:
- @Autowired:autowire=byType 就是根据类型的自动注入依赖(基于注解的依赖注入),可以被使用再属性域,方法,构造函数上。
- @Resource 属于JSR250标准,用于属性域额和方法上。也是 byName 类型的依赖注入。使用方式:@Resource(name=”xxBean”). 不带参数的 @Resource 默认值类名首字母小写。
- @Qualifier 就是 autowire=byName, @Autowired注解判断多个bean类型相同时,就需要使用 @Qualifier(“xxBean”) 来指定依赖的bean的id:
- @Required:表明bean的属性必须在配置时设置,可以在bean的定义中明确指定也可通过自动装配设置。如果bean的属性未设置,则抛出BeanInitializationException异常。
- @PostConstruct
- @PreDestory
- @Singleton(从这儿开始是Spring3.0之后开始支持的)
- @Scope(“prototype”)
MVC相关的
- @Controller
- @RequestMapping
- @RequestParam
- @ResponseBody
- @ Repository @ Repository(value=”userDao”)注解是告诉Spring,让Spring创建一个名字叫“userDao”的UserDaoImpl实例。 @Resource(name = “userDao”)注解告诉Spring,Spring把创建好的userDao注入给Service即可。
小知识点:
@Autowired和@Resource的区别:
前者是根据类型(byType)的自动注入依赖,
后者是根据名字(byName)进行依赖注入的。
spring注解觉得不错的一篇博客:https://www.cnblogs.com/digdeep/p/4525567.html
推荐阅读
-
索引的创建与使用 博客分类: 项目经验总结 Oracle索引
-
索引的创建与使用 博客分类: 项目经验总结 Oracle索引
-
JS中push()的作用简单说明 博客分类: 项目经验总结 JS
-
如何获取配置文件的内容 博客分类: 项目经验总结 java
-
编程错误总结 博客分类: c++
-
如何更改TomCat服务器的端口号 博客分类: 项目经验总结 tomcat
-
框架学习总结-----MyBatis--- 映射文件配置(简述) 博客分类: 项目经验总结 MyBatis
-
JAVA IO流学习总结----字节流 博客分类: java java、IO流
-
框架学习总结-----MyBatis---核心配置文件 博客分类: 项目经验总结 框架 MyBatis
-
如何更改TomCat服务器的端口号 博客分类: 项目经验总结 tomcat