Skip to content

Commit

Permalink
'合并冲突'
Browse files Browse the repository at this point in the history
  • Loading branch information
ShiHaoyang committed Sep 2, 2016
2 parents af7ec4d + 88b97dd commit f0f739f
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 57 deletions.
2 changes: 2 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,6 @@
* [Activity、View及Window之间关系](android/activity-view-window.md)
* [EventBus](android/eventbus.md)
* [面试题](android/questions.md)
* [Spring](Spring/spring.md)
* [基础](Spring/base.md)

13 changes: 13 additions & 0 deletions Spring/base.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# **Bean生命周期**

1. Spring对bean进行实例化。
2. Spring将值和bean的引用注入到bean对应的属性中。
3. 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName\(\)方法。
4. 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory\(\)方法,将BeanFactory容器实例传入。
5. 如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext\(\)方法,将bean所在的应用上下文的引用传入进来。
6. 如果bean实现了BeanPostProcessor接口,Spring将调用它的postProcessBeforeInitializetion\(\)方法。
7. 如果bean实现了InitailizingBean接口,Spring将调用它的afterPropertiesSet\(\)方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用。
8. 如果bean实现了BeanPostPorcessor接口,Spring将调用它的postProcessAfterInitializetion\(\)方法。
9. 此时,bean已经准备就绪,可以被应用程序使用了,它将一直驻留在应用上下文中,直到该应用上下文被销毁。
10. 如果bean实现了DisposableBean接口,Spring将调用它的destroy\(\)接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

2 changes: 2 additions & 0 deletions Spring/spring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Introduction

36 changes: 19 additions & 17 deletions java/collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,30 @@ Java集合框架提供了数据持有对象的方式,提供了对数据集合

![](collection.png)

- `ArrayList`:线程不同步。默认初始容量为10,当数组大小不足时增长率为当前长度的`50%`
- `Vector`**线程同步**。默认初始容量为10,当数组大小不足时增长率为当前长度的`100%`。它的同步是通过`Iterator`方法加`synchronized`实现的。
- `LinkedList`:线程不同步。**双端队列形式**
- `Stack`**线程同步**。继承自`Vector`,添加了几个方法来完成栈的功能。
- `Set`:Set是一种不包含重复元素的Collection,Set最多只有一个null元素。
- `HashSet`:线程不同步,内部使用`HashMap`进行数据存储,提供的方法基本都是调用`HashMap`的方法,所以两者本质是一样的。**集合元素可以为`NULL`**
- `NavigableSet `:添加了搜索功能,可以对给定元素进行搜索:小于、小于等于、大于、大于等于,放回一个符合条件的最接近给定元素的 key。
- `TreeSet`:线程不同步,内部使用`NavigableMap`操作。默认元素“自然顺序”排列,可以通过`Comparator`改变排序。
- `EnumSet`:线程不同步。内部使用Enum数组实现,速度比`HashSet`快。**只能存储在构造函数传入的枚举类的枚举值**
* `ArrayList`:线程不同步。默认初始容量为10,当数组大小不足时增长率为当前长度的`50%`
* `Vector`**线程同步**。默认初始容量为10,当数组大小不足时增长率为当前长度的`100%`。它的同步是通过`Iterator`方法加`synchronized`实现的。
* `LinkedList`:线程不同步。**双端队列形式**
* `Stack`**线程同步**。继承自`Vector`,添加了几个方法来完成栈的功能。
* `Set`:Set是一种不包含重复元素的Collection,Set最多只有一个null元素。
* `HashSet`:线程不同步,内部使用`HashMap`进行数据存储,提供的方法基本都是调用`HashMap`的方法,所以两者本质是一样的。**集合元素可以为**`NULL`
* `NavigableSet`:添加了搜索功能,可以对给定元素进行搜索:小于、小于等于、大于、大于等于,放回一个符合条件的最接近给定元素的 key。
* `TreeSet`:线程不同步,内部使用`NavigableMap`操作。默认元素“自然顺序”排列,可以通过`Comparator`改变排序。
* `EnumSet`:线程不同步。内部使用Enum数组实现,速度比`HashSet`快。**只能存储在构造函数传入的枚举类的枚举值**

## Map

![](map.png)

- `HashMap`:线程不同步。根据`key``hashcode`进行存储,内部使用静态内部类`Node`的数组进行存储,默认初始大小为16,每次扩大一倍。当发生Hash冲突时,采用拉链法(链表)。**可以接受为null的键值(key)和值(value)**
- `LinkedHashMap`**保存了记录的插入顺序**,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的. 也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
- `TreeMap`:线程不同步,基于 **红黑树** (Red-Black tree)的NavigableMap 实现,**能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。**
- `HashTable`:线程安全,HashMap的迭代器(Iterator)是`fail-fast`迭代器。**HashTable不能存储NULL的key和value。**
* `HashMap`:线程不同步。根据`key``hashcode`进行存储,内部使用静态内部类`Node`的数组进行存储,默认初始大小为16,每次扩大一倍。当发生Hash冲突时,采用拉链法(链表)。**可以接受为null的键值\(key\)和值\(value\)**。JDK 1.8中:当单个桶中元素个数大于等于8时,链表实现改为红黑树实现;当元素个数小于6时,变回链表实现。由此来防止hashCode攻击
* `LinkedHashMap`**保存了记录的插入顺序**,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的. 也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
* `TreeMap`:线程不同步,基于 **红黑树** (Red-Black tree)的NavigableMap 实现,**能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。**
* `HashTable`:线程安全,HashMap的迭代器\(Iterator\)`fail-fast`迭代器。**HashTable不能存储NULL的key和value。**

## 工具类

- `Collections``Arrays`:集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
- `Comparable``Comparator`:一般是用于对象的比较来实现排序,两者略有区别。
> - 类设计者没有考虑到比较问题而没有实现Comparable接口。这是我们就可以通过使用Comparator,这种情况下,我们是不需要改变对象的。
> - 一个集合中,我们可能需要有多重的排序标准,这时候如果使用Comparable就有些捉襟见肘了,可以自己继承Comparator提供多种标准的比较器进行排序。
* `Collections``Arrays`:集合类的一个工具类\/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
* `Comparable``Comparator`:一般是用于对象的比较来实现排序,两者略有区别。
> * 类设计者没有考虑到比较问题而没有实现Comparable接口。这是我们就可以通过使用Comparator,这种情况下,我们是不需要改变对象的。
> * 一个集合中,我们可能需要有多重的排序标准,这时候如果使用Comparable就有些捉襟见肘了,可以自己继承Comparator提供多种标准的比较器进行排序。

153 changes: 121 additions & 32 deletions java/questions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,35 @@

用数组实现队列时要注意 **溢出** 现象,这是我们可以采用循环数组的方式来解决,即将数组收尾相接。使用front指针指向队列首位,tail指针指向队列末位。

***

### 内部类访问局部变量的时候,为什么变量必须加上final修饰?
---

>Java8不需要加final
### 内部类访问局部变量的时候,为什么变量必须加上final修饰? {#xuan}

在java中,类是封装的,内部类也不例外。我们知道,非静态内部类能够访问外部类成员是因为它持有外部类对象的引用 Outer.this, 就像子类对像能够访问父类成员是持有父类对象引用super一样。局部内部类也和一般内部类一样,只持有了Outer.this,能够访问外部类成员,但是它又是如何访问到局部变量的呢?
因为生命周期不同。局部变量在方法结束后就会被销毁,但内部类对象并不一定,这样就会导致内部类引用了一个不存在的变量。

**实际上java是将局部变量作为参数传给了局部内部类的构造函数,而将其作为内部类的成员属性封装在了类中。我们看到的内部类访问局部变量实际上只是访问了自己的成员属性而已,这和类的封装性是一致的**
所以编译器会在内部类中生成一个局部变量的拷贝,这个拷贝的生命周期和内部类对象相同,就不会出现上述问题

那么问题又来了,我们写代码的目的是在内部类中直接控制局部变量和引用,但是java这么整我们就不高兴了,我在内部类中整半天想着是在操作外部变量,结果你给整个副本给我,我搞半天丫是整我自己的东西啊?要是java不这么整吧,由破坏了封装性--------你个局部内部类牛啊,啥都没有还能看局部变量呢。这不是java风格,肯定不能这么干。这咋整呢?
但这样就导致了其中一个变量被修改,两个变量值可能不同的问题。为了解决这个问题,编译器就要求局部变量需要被final修饰,以保证两个变量值相同。

想想,类的封装性咱们一定是要遵守的,不能破坏大局啊。但又 **要保证两个东西是一模一样的,包括对象和普通变量,那就使用final嘛,当传递普通变量的之前我把它变成一个常量给你,当传递引用对象的时候加上final就声明了这个引用就只能指着这一个对象了。这样就保证了内外统一**
在JDK8之后,编译器不要求内部类访问的局部变量必须被final修饰,但局部变量值不能被修改(无论是方法中还是内部类中),否则会报编译错误。利用javap查看编译后的字节码可以发现,编译器已经加上了final

***
---

### long s = 499999999 * 499999999 在上面的代码中,s的值是多少?
### long s = 499999999 \* 499999999 在上面的代码中,s的值是多少?

根据代码的计算结果,`s`的值应该是`-1371654655`**这是由于Java中右侧值的计算默认是`int`**,所以要强转。
根据代码的计算结果,`s`的值应该是`-1371654655`**这是由于Java中右侧值的计算默认是**`int`,所以要强转。

***
---

### NIO相关,Channels、Buffers、Selectors

`NIO(Non-blocking IO)`为所有的原始类型提供(Buffer)缓存支持,字符集编码解码解决方案。 `Channel` :一个新的原始I/O 抽象。 支持锁和内存映射文件的文件访问接口。提供多路(non-bloking) 非阻塞式的高伸缩性网络I/O 。
`NIO(Non-blocking IO)`为所有的原始类型提供\(Buffer\)缓存支持,字符集编码解码解决方案。 `Channel` :一个新的原始I\/O 抽象。 支持锁和内存映射文件的文件访问接口。提供多路\(non-bloking\) 非阻塞式的高伸缩性网络I\/O 。

| IO | NIO |
| :----- | :------ |
|面向流 | 面向缓冲|
|阻塞IO | 非阻塞IO|
|| 选择器|
| IO | NIO |
| --- | --- |
| 面向流 | 面向缓冲 |
| 阻塞IO | 非阻塞IO |
|| 选择器 |

##### 流与缓冲

Expand All @@ -50,19 +48,18 @@ Java IO的各种流是阻塞的。这意味着,当一个线程调用`read()`

Java NIO 的 **选择器允许一个单独的线程来监视多个输入通道**,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

***
---

### 反射的用途

Java反射机制可以让我们在编译期(Compile Time)之外的运行期(Runtime)检查类,接口,变量以及方法的信息。反射还可以让我们在运行期实例化对象,调用方法,通过调用`get/set`方法获取变量的值。同时我们也可以通过反射来获取泛型信息,以及注解。还有更高级的应用--动态代理和动态类加载(`ClassLoader.loadclass()`)。
Java反射机制可以让我们在编译期\(Compile Time\)之外的运行期\(Runtime\)检查类,接口,变量以及方法的信息。反射还可以让我们在运行期实例化对象,调用方法,通过调用`get/set`方法获取变量的值。同时我们也可以通过反射来获取泛型信息,以及注解。还有更高级的应用--动态代理和动态类加载(`ClassLoader.loadclass()`)。

下面列举一些比较重要的方法:

- getFields:获取所有 `public` 的变量。
- getDeclaredFields:获取所有包括 `private` , `protected` 权限的变量。
- setAccessible:设置为 true 可以跳过Java权限检查,从而访问`private`权限的变量。
- getAnnotations:获取注解,不仅可以用在类上。

* getFields:获取所有 `public` 的变量。
* getDeclaredFields:获取所有包括 `private` , `protected` 权限的变量。
* setAccessible:设置为 true 可以跳过Java权限检查,从而访问`private`权限的变量。
* getAnnotations:获取注解,不仅可以用在类上。

获取方法的泛型参数:

Expand Down Expand Up @@ -127,19 +124,20 @@ for(Annotation annotation : annotations){
}
```

***
---

### Java注解的继承

| | @Inherited | 没有@Inherited |
| :------------- | :------------- |:------------- |
|子类的类上能否继承到父类的类上的注解?|||
|子类实现了父类上的抽象方法|||
|子类继承了父类上的方法|||
|子类覆盖了父类上的方法|||
| | @Inherited | 没有@Inherited |
| --- | --- | --- |
| 子类的类上能否继承到父类的类上的注解? |||
| 子类实现了父类上的抽象方法 |||
| 子类继承了父类上的方法 |||
| 子类覆盖了父类上的方法 |||

通过测试结果来看,`@Inherited` 只是可控制对类名上注解是否可以被继承。不能控制方法上的注解是否可以被继承。


***

### 非静态内部类能定义静态方法吗?
Expand Down Expand Up @@ -202,3 +200,94 @@ fabs(x) < 0.00001f
可以包含:字母、数字、$、`_`(下划线),不可用数字开头,不能是 Java 的关键字和保留字。

***

---

### **你知道哪些JDK中用到的设计模式?**

* 装饰模式:java.io
* 单例模式:Runtime类
* 简单工厂模式:Integer.valueOf方法
* 享元模式:String常量池、Integer.valueOf\(int i\)、Character.valueOf\(char c\)
* 迭代器模式:Iterator
* 职责链模式:ClassLoader的双亲委派模型
* 解释器模式:正则表达式java.util.regex.Pattern


---

### **ConcurrentHashMap如何保证线程安全**

JDK 1.7及以前:

ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段\(Segment\)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

详细参考:

[http:\/\/www.cnblogs.com\/ITtangtang\/p\/3948786.html](http://www.cnblogs.com/ITtangtang/p/3948786.html)

[http:\/\/qifuguang.me\/2015\/09\/10\/\[Java并发包学习八\]深度剖析ConcurrentHashMap\/](http://qifuguang.me/2015/09/10/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E5%85%AB]%E6%B7%B1%E5%BA%A6%E5%89%96%E6%9E%90ConcurrentHashMap/)

JDK 1.8:

Segment虽保留,但已经简化属性,仅仅是为了兼容旧版本。

插入时使用CAS算法:unsafe.compareAndSwapInt\(this, valueOffset, expect, update\)。 CAS\(Compare And Swap\)意思是如果valueOffset位置包含的值与expect值相同,则更新valueOffset位置的值为update,并返回true,否则不更新,返回false。插入时不允许key或value为null

与Java8的HashMap有相通之处,底层依然由“数组”+链表+红黑树;

底层结构存放的是TreeBin对象,而不是TreeNode对象;

CAS作为知名无锁算法,那ConcurrentHashMap就没用锁了么?当然不是,当hash值与链表的头结点相同还是会synchronized上锁,锁链表。

---

### **i++在多线程环境下是否存在问题,怎么解决?**

虽然递增操作++i是一种紧凑的语法,使其看上去只是一个操作,但这个操作并非原子的,因而它并不会作为一个不可分割的操作来执行。实际上,它包含了三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。这是一个“读取 - 修改 - 写入”的操作序列,并且其结果状态依赖于之前的状态。所以在多线程环境下存在问题。

要解决自增操作在多线程环境下线程不安全的问题,可以选择使用Java提供的原子类,如AtomicInteger或者使用synchronized同步方法。

---

### **new与newInstance\(\)的区别**

* new是一个关键字,它是调用new指令创建一个对象,然后调用构造方法来初始化这个对象,可以使用带参数的构造器
* newInstance\(\)是Class的一个方法,在这个过程中,是先取了这个类的不带参数的构造器Constructor,然后调用构造器的newInstance方法来创建对象。

Class.newInstance\(\)不能带参数,如果要带参数需要取得对应的构造器,然后调用该构造器的Constructor.newInstance\(Object ... initargs\)方法


---

### **你了解哪些JDK1.8的新特性?**

* 接口的默认方法和静态方法

JDK8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,也可以定义被static修饰的静态方法

* 对HashMap进行了改进,当单个桶的元素个数大于6时就会将实现改为红黑树实现,以避免构造重复的hashCode的攻击

* 多并发进行了优化。如ConcurrentHashMap实现由分段加锁、锁分离改为CAS实现。
* JDK8拓宽了注解的应用场景,注解几乎可以使用在任何元素上,并且允许在同一个地方多次使用同一个注解
* Lambda表达式

---

### 你用过哪些JVM参数?

-Xms 堆最小值

-Xmx 堆最大值

-Xmn: 新生代容量

-XX:SurvivorRatio 新生代中Eden与Surivor空间比例

-Xss 栈容量

-XX:PermSize 方法区初始容量

-XX:MaxPermSize 方法区最大容量

-XX:+PrintGCDetails 收集器日志参数
Loading

0 comments on commit f0f739f

Please sign in to comment.