Skip to content

Commit 340202d

Browse files
author
guanzhenxing
committed
修改
1 parent 2b69308 commit 340202d

9 files changed

Lines changed: 603 additions & 20 deletions

File tree

‎README.md‎

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@
55
主要分为以下部分:
66

77
- [Java基础](./java-basic/index.md)
8-
- [面向对象](./java-basic/oop.md)
9-
- [基本功](./java-basic/basic.md)
10-
- [集合](./java-basic/collections.md)
11-
- [多线程](./java-basic/multithread.md)
12-
- [JVM](./java-basic/jvm.md)
13-
- [数据结构与算法](./java-basic/data-structures-and-algorithms.md)
8+
- [面向对象](./java-basic/oop.md)
9+
- [基本功](./java-basic/basic.md)
10+
- [集合](./java-basic/collections.md)
11+
- [多线程](./java-basic/multithread.md)
12+
- [JVM](./java-basic/jvm.md)
13+
- [数据结构与算法](./java-basic/data-structures-and-algorithms.md)
1414
- 设计模式
1515
- JavaWeb
16-
- HTTP基础
17-
- Servlet与JSP
18-
- Spring系列
19-
- MyBatis
20-
- Hibernate
16+
- HTTP基础
17+
- Servlet与JSP
18+
- Spring系列
19+
- MyBatis
20+
- Hibernate
2121
- 数据库
22-
- 基本理论
23-
- MySQL
24-
- MongoDB
25-
- Redis
22+
- 基本理论
23+
- MySQL
24+
- MongoDB
25+
- Redis
2626
- 分布式
2727
- 安全
2828

76.7 KB
Loading

‎java-basic/basic.md‎

Lines changed: 296 additions & 0 deletions
Large diffs are not rendered by default.

‎java-basic/collections.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# 集合
2+
3+
## List、Set、Map是否继承自Collection接口?
4+
5+
List、Set 是,Map 不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形。
6+
7+
## 阐述ArrayList、Vector、LinkedList的存储性能和特性。
8+
9+
ArrayList 和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。Vector中的方法由于添加了synchronized修饰,因此Vector是线程安全的容器,但性能上较ArrayList差,因此已经是Java中的遗留容器。
10+
11+
LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
12+
13+
Vector属于遗留容器(Java早期的版本中提供的容器,除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器),已经不推荐使用,但是由于ArrayList和LinkedListed都是非线程安全的,如果遇到多个线程操作同一个容器的场景,则可以通过工具类Collections中的synchronizedList方法将其转换成线程安全的容器后再使用(这是对装潢模式的应用,将已有对象传入另一个类的构造器中创建新的对象来增强实现)。
14+
15+
## Collection和Collections的区别?
16+
17+
Collection是一个接口,它是Set、List等容器的父接口;Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。
18+
19+
## List、Map、Set三个接口存取元素时,各有什么特点?
20+
21+
List以特定索引来存取元素,可以有重复元素。
22+
23+
Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。
24+
25+
Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。
26+
27+
Set和Map容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。

‎java-basic/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Java基础
22

33
- [面向对象](./oop.md)
4-
- [基本功](./basic.md)
4+
- [JAVA基本](./basic.md)
55
- [集合](./collections.md)
66
- [多线程](./multithread.md)
77
- [JVM](./jvm.md)

‎java-basic/jvm.md‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# JVM
2+
3+
## 解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法
4+
5+
通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;而通过new关键字和构造器创建的对象放在堆空间;程序中的字面量(literal)如直接书写的100、”hello”和常量都是放在静态区中。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,理论上整个内存没有被其他进程使用的空间甚至硬盘上的虚拟内存都可以被当成堆空间来使用。
6+
7+
String str = new String("hello");
8+
9+
上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而”hello”这个字面量放在静态区。
10+
11+
## 描述一下JVM加载class文件的原理机制?
12+
13+
JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。
14+
15+
由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。
16+
17+
类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。从Java 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM更好的保证了Java平台的安全性,在该机制中,JVM自带的Bootstrap是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM不会向Java程序提供对Bootstrap的引用。
18+
19+
下面是关于几个类加载器的说明:
20+
21+
- ootstrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);
22+
- Extension:从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是Bootstrap;
23+
- System:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中记载类,是用户自定义加载器的默认父加载器。
24+
25+
## Java 中会存在内存泄漏吗,请简单描述。
26+
27+
理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。下面例子中的代码也会导致内存泄露。
28+
29+
```java
30+
import java.util.Arrays;
31+
import java.util.EmptyStackException;
32+
33+
public class MyStack<T> {
34+
private T[] elements;
35+
private int size = 0;
36+
37+
private static final int INIT_CAPACITY = 16;
38+
39+
public MyStack() {
40+
elements = (T[]) new Object[INIT_CAPACITY];
41+
}
42+
43+
public void push(T elem) {
44+
ensureCapacity();
45+
elements[size++] = elem;
46+
}
47+
48+
public T pop() {
49+
if(size == 0)
50+
throw new EmptyStackException();
51+
return elements[--size];
52+
}
53+
54+
private void ensureCapacity() {
55+
if(elements.length == size) {
56+
elements = Arrays.copyOf(elements, 2 * size + 1);
57+
}
58+
}
59+
}
60+
```
61+
62+
上面的代码实现了一个栈(先进后出(FILO))结构,乍看之下似乎没有什么明显的问题,它甚至可以通过你编写的各种单元测试。
63+
然而其中的pop方法却存在内存泄露的问题,当我们用pop方法弹出栈中的对象时,该对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,因为栈内部维护着对这些对象的过期引用(obsolete reference)。在支持垃圾回收的语言中,内存泄露是很隐蔽的,这种内存泄露其实就是无意识的对象保持。
64+
如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象,也不会处理该对象引用的其他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大影响,极端情况下会引发Disk Paging(物理内存与硬盘的虚拟内存交换数据),甚至造成OutOfMemoryError。
65+
66+
## GC是什么?为什么要有GC?
67+
68+
GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
69+
Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
70+
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
71+
在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
72+
73+
补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
74+
75+
- 伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
76+
- 幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
77+
- 终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
78+
79+
与垃圾回收相关的JVM参数:
80+
81+
- -Xms / -Xmx — 堆的初始大小 / 堆的最大大小
82+
- -Xmn — 堆中年轻代的大小
83+
- -XX:-DisableExplicitGC — 让System.gc()不产生任何作用
84+
- -XX:+PrintGCDetails — 打印GC的细节
85+
- -XX:+PrintGCDateStamps — 打印GC操作的时间戳
86+
- -XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小
87+
- -XX:NewRatio — 可以设置老生代和新生代的比例
88+
- -XX:PrintTenuringDistribution — 设置每次新生代GC后输出幸存者乐园中对象年龄的分布
89+
- -XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:设置老年代阀值的初始值和最大值
90+
- -XX:TargetSurvivorRatio:设置幸存区的目标使用率
91+

0 commit comments

Comments
 (0)