, RandomAccess, Cloneable, Serializable
46 |
47 | > Vector 类可以**实现可增长的对象数组**。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。
48 |
49 | > 每个向量会试图通过维护 capacity 和 capacityIncrement 来优化存储管理。capacity 始终至少应与向量的大小相等;这个值通常比后者大些,因为随着将组件添加到向量中,其存储将按 capacityIncrement 的大小增加存储块。应用程序可以在插入大量组件前增加向量的容量;这样就减少了增加的重分配的量。
50 |
51 | > 由 Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的:如果在迭代器创建后的任意时间从结构上修改了向量(通过迭代器自身的 remove 或 add 方法之外的任何其他方式),则迭代器将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就完全失败,而不是冒着在将来不确定的时间任意发生不确定行为的风险。Vector 的 elements 方法返回的 Enumeration 不是 快速失败的。
52 |
53 | > 注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测 bug。
54 |
55 | > 从 Java 2 平台 v1.2 开始,此类改进为可以实现 List 接口,使它成为 Java Collections Framework 的成员。与新 collection 实现不同,**Vector 是同步的**。
56 |
57 | - 区别
58 |
59 |
60 | ArrayList 本质上是一个可改变大小的**数组**.当元素加入时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问.元素顺序存储 ,**随机访问很快,删除非头尾元素慢,新增元素慢而且费资源** ,较适用于无频繁增删的情况 ,比数组效率低,如果不是需要可变数组,可考虑使用数组 ,**非线程安全**.
61 |
62 | LinkedList 是一个**双链表**,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList. 适用于 :没有大规模的随机读取,大量的增加/删除操作.**随机访问很慢,增删操作很快**,不耗费多余资源 ,允许null元素,**非线程安全.**
63 |
64 | Vector (类似于ArrayList)但其是**同步**的,开销就比ArrayList要大。如果你的程序本身是线程安全的,那么使用ArrayList是更好的选择。
65 | Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.
--------------------------------------------------------------------------------
/java/[Java] Collection包结构,与Collections的区别.md:
--------------------------------------------------------------------------------
1 | > Collection家族
2 |
3 | 
4 |
5 |
6 |
7 | Collection是集合继承结构中的顶层接口
8 |
9 | Collections 是提供了对集合进行操作的强大方法的工具类 ,它包含有各种有关集合操作的静态多态方法。此类不能实例化
--------------------------------------------------------------------------------
/java/[Java] Excption与Error包结构,OOM和SOF.md:
--------------------------------------------------------------------------------
1 |
2 | >Java 异常类继承关系图
3 |
4 | 
5 |
6 |
7 | (一)Throwable
8 |
9 | Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类或其子类之一的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出,才可以是 catch 子句中的参数类型。
10 | Throwable 类及其子类有两个构造方法,一个不带参数,另一个带有 String 参数,此参数可用于生成详细消息。
11 | Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。
12 |
13 | Java将可抛出(Throwable)的结构分为三种类型:
14 | 错误(Error)
15 | 运行时异常(RuntimeException)
16 | 被检查的异常(Checked Exception)
17 |
18 | 1.**Error**
19 | Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。大多数这样的错误都是异常条件。
20 | 和RuntimeException一样, 编译器也不会检查Error。
21 | 当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误,程序本身无法修复这些错误的。
22 |
23 | 2.**Exception**
24 | Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。
25 | 对于可以恢复的条件使用**被检查异常**(Exception的子类中除了RuntimeException之外的其它子类),对于程序错误使用运行时异常。
26 |
27 | >① ClassNotFoundException
28 |
29 | 当应用程序试图使用以下方法通过字符串名加载类时:
30 | Class 类中的 forName 方法。
31 | ClassLoader 类中的 findSystemClass 方法。
32 | ClassLoader 类中的 loadClass 方法。
33 | 但是没有找到具有指定名称的类的定义,抛出该异常。
34 |
35 | ② CloneNotSupportedException
36 |
37 | 当调用 Object 类中的 clone 方法复制对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。重写 clone 方法的应用程序也可能抛出此异常,指示不能或不应复制一个对象。
38 |
39 |
40 | > ③ IOException
41 | 当发生某种 I/O 异常时,抛出此异常。此类是失败或中断的 I/O 操作生成的异常的通用类。
42 |
43 | -EOFException
44 | 当输入过程中意外到达文件或流的末尾时,抛出此异常。
45 | 此异常主要被**数据输入流**用来表明到达流的末尾。
46 | 注意:其他许多输入操作返回一个特殊值表示到达流的末尾,而不是抛出异常。
47 |
48 | -FileNotFoundException
49 | 当试图打开指定路径名表示的文件失败时,抛出此异常。
50 | 在不存在具有指定路径名的文件时,此异常将由 FileInputStream、FileOutputStream 和 RandomAccessFile 构造方法抛出。如果该文件存在,但是由于某些原因不可访问,比如试图打开一个只读文件进行写入,则此时这些构造方法仍然会抛出该异常。
51 |
52 | -MalformedURLException
53 | 抛出这一异常指示出现了错误的 URL。或者在规范字符串中找不到任何合法协议,或者无法解析字符串。
54 |
55 | -UnknownHostException
56 | 指示主机 IP 地址无法确定而抛出的异常。
57 |
58 | >④ RuntimeException
59 | 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明。
60 | Java编译器不会检查它。当程序中可能出现这类异常时,还是会编译通过。
61 | 虽然Java编译器不会检查运行时异常,但是我们也可以通过throws进行声明抛出,也可以通过try-catch对它进行捕获处理。
62 |
63 | -ArithmeticException
64 | 当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
65 |
66 | -ClassCastException
67 | 当试图将对象强制转换为不是实例的子类时,抛出该异常。
68 | 例如:Object x = new Integer(0);
69 |
70 | -LllegalArgumentException
71 | 抛出的异常表明向方法传递了一个不合法或不正确的参数。
72 |
73 | -IllegalStateException
74 | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
75 |
76 | -IndexOutOfBoundsException
77 | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
78 | 应用程序可以为这个类创建子类,以指示类似的异常。
79 |
80 | -NoSuchElementException
81 | 由 Enumeration 的 nextElement 方法抛出,表明枚举中没有更多的元素。
82 |
83 | -NullPointerException
84 | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括:
85 | 调用 null 对象的实例方法。
86 | 访问或修改 null 对象的字段。
87 | 将 null 作为一个数组,获得其长度。
88 | 将 null 作为一个数组,访问或修改其时间片。
89 | 将 null 作为 Throwable 值抛出。
90 | 应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用。
91 |
92 |
93 |
94 | (二) SOF (堆栈溢出 StackOverflow)
95 |
96 | > StackOverflowError 的定义:
97 | > 当应用程序递归太深而发生堆栈溢出时,抛出该错误。
98 | >
99 | 因为栈一般默认为1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出。
100 |
101 | 栈溢出的原因:
102 |
103 | 递归调用
104 |
105 | 大量循环或死循环
106 |
107 | 全局变量是否过多
108 |
109 | 数组、List、map数据过大
110 |
111 |
112 |
113 | (三)Android的OOM(Out Of Memory)
114 |
115 | 当内存占有量超过了虚拟机的分配的最大值时就会产生内存溢出(VM里面分配不出更多的page)。
116 |
117 | 一般出现情况:加载的图片太多或图片过大时、分配特大的数组、内存相应资源过多没有来不及释放。
118 |
119 | 解决方法:
120 | ①在内存引用上做处理
121 |
122 | 软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。
123 |
124 | ②对图片做边界压缩,配合软引用使用
125 |
126 | ③显示的调用GC来回收内存
127 |
128 |
129 | ```
130 | if(bitmapObject.isRecycled()==false) //如果没有回收
131 | bitmapObject.recycle();
132 | ```
133 | ④优化Dalvik虚拟机的堆内存分配
134 |
135 | 1.增强程序堆内存的处理效率
136 |
137 |
138 | ```
139 | //在程序onCreate时就可以调用 即可
140 | private final static floatTARGET_HEAP_UTILIZATION = 0.75f;
141 |
142 | VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
143 |
144 | ```
145 | 2 .设置堆内存的大小
146 | ```
147 | private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
148 | //设置最小heap内存为6MB大小
149 | VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);
150 | ```
151 | ⑤ 用LruCache 和 AsyncTask<>解决
152 |
153 | 从cache中去取Bitmap,如果取到Bitmap,就直接把这个Bitmap设置到ImageView上面。
154 | 如果缓存中不存在,那么启动一个task去加载(可能从文件来,也可能从网络)。
--------------------------------------------------------------------------------
/java/[Java] HashMap和HashTable的区别.md:
--------------------------------------------------------------------------------
1 | - HashTable
2 |
3 |
4 | >
5 | Hashtable继承于Dictionary字典,实现Map接口
6 |
7 | > 键、值都不能是空对象
8 |
9 | >多次访问,映射元素的顺序相同
10 |
11 | >线程安全
12 | >
13 | >
14 | >hash算法 ,Hashtable则直接利用key本身的hash码来做验证
15 | >
16 | >数据遍历的方式 Iterator (支持fast-fail)和 Enumeration (不支持fast-fail)
17 | >
18 | > 缺省初始长度为11,内部都为抽象方法,需要 它的实现类一一作自己的实现
19 |
20 | 备注:程序在对 collection 进行迭代时,某个线程对该 collection 在结构上对其做了修改,这时迭代器就会抛出 ConcurrentModificationException 异常信息,从而产生 fail-fast。
21 |
22 | - HashMap
23 |
24 | > HashMap继承于AbstractMap抽象类
25 | >
26 | > 键和值都可以是空对象
27 | >
28 | 多次访问,映射元素的顺序可能不同
29 |
30 | > 非线程安全
31 | HashMap可以通过下面的语句进行同步:
32 | Map m = Collections.synchronizeMap(hashMap);
33 | >
34 | > 检测是否含有key时,HashMap内部需要将key的hash码重新计算一边再检测
35 | >
36 | > 数据遍历的方式 Iterator (支持fast-fail)
37 | >
38 | > 缺省初始长度为16,其内部已经实现了Map所需 要做的大部分工作, 它的子类只需要实现它的少量方法
--------------------------------------------------------------------------------
/java/[Java] HashMap源码分析.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] HashMap源码分析.md
--------------------------------------------------------------------------------
/java/[Java] Hashcode的作用.md:
--------------------------------------------------------------------------------
1 | 关于HashCode的官方文档定义:
2 |
3 | > hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。 hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
4 | 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
5 | 以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
6 | 实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
7 | 当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
8 |
9 | - 以上这段官方文档的定义,我们可以抽出成以下几个关键点:
10 |
11 | 1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;
12 |
13 | 2、如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;
14 |
15 | 3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;
16 |
17 | 4、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。
18 |
19 | 再归纳一下就是hashCode是用于查找使用的,而equals是用于比较两个对象的是否相等的。
20 |
21 | - 总的来说,Java中的集合(Collection)有两类,一类 是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一 次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它 就要调用1000次equals方法。这显然会大大降低效率。
22 | 于是,Java采用了哈希表的原理。哈希算法也称为散列算法,是 将数据依特定算法直接指定到一个地址上。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以 直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散 列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
23 | 所以,Java对于eqauls方法和hashCode方法是这样规定的:
24 |
25 | 1、如果两个对象相同,那么它们的hashCode值一定要相同;
26 | 2、如果两个对象的hashCode相同,它们并不一定相同
--------------------------------------------------------------------------------
/java/[Java] Map、Set、List、Queue、Stack的特点与用法.md:
--------------------------------------------------------------------------------
1 | - Map
2 |
3 |
4 |
5 | > 键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
6 |
7 | >某些映射实现可明确保证其顺序,如 TreeMap 类;另一些映射实现则不保证顺序,如 HashMap 类。
8 |
9 | >Map中元素,可以将key序列、value序列单独抽取出来。
10 | 使用keySet()抽取key序列,将map中的所有keys生成一个Set。
11 | 使用values()抽取value序列,将map中的所有values生成一个Collection。
12 | 为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。
13 |
14 | - Set
15 |
16 |
17 |
18 | >一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。
19 | >
20 | > 不可随机访问包含的元素
21 | >
22 | 只能用Iterator实现单向遍历
23 | >
24 | > Set 没有同步方法
25 |
26 | - List
27 |
28 |
29 |
30 | > 可随机访问包含的元素
31 | 元素是有序的
32 | 可在任意位置增、删元素
33 | 不管访问多少次,元素位置不变
34 | 允许重复元素
35 | 用Iterator实现单向遍历,也可用ListIterator实现双向遍历
36 |
37 | - Queue
38 |
39 | > 先进先出
40 | >
41 | > Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常。 如果要使用前端而不移出该元素,使用element()或者peek()方法。
42 | 值得注意的是LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。
43 |
44 | > Queue 实现通常不允许插入 null 元素,尽管某些实现(如 LinkedList)并不禁止插入 null。即使在允许 null 的实现中,也不应该将 null 插入到 Queue 中,因为 null 也用作 poll 方法的一个特殊返回值,表明队列不包含元素。
45 |
46 | - Stack
47 |
48 | > 后进先出
49 | >
50 | > Stack继承自Vector(可增长的对象数组),也是同步的
51 | > 它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈。它提供了通常的 push 和 pop 操作,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并确定到**堆栈顶**距离的 search 方法。
52 |
53 | - 用法
54 |
55 |
56 | > 如果涉及到堆栈、队列等操作,应该考虑用List;
57 |
58 | > 对于需要快速插入,删除元素,应该使用LinkedList;
59 |
60 | > 如果需要快速随机访问元素,应该使用ArrayList。
61 |
62 | > 如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高
--------------------------------------------------------------------------------
/java/[Java] Object有哪些公用方法?.md:
--------------------------------------------------------------------------------
1 | > 官方文档 http://docs.oracle.com/javase/8/docs/api/
2 |
3 | 
4 | 
5 |
6 | protected Object clone()
7 | 创建并返回此对象的一个副本。
8 |
9 | boolean equals(Object obj)
10 | 指示其他某个对象是否与此对象“相等”。
11 |
12 | protected void finalize()
13 | 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
14 |
15 | Class getClass()
16 | 返回此 Object 的运行时类。
17 |
18 | int hashCode()
19 | 返回该对象的哈希码值。
20 |
21 | void notify()
22 | 唤醒在此对象监视器上等待的单个线程。
23 |
24 | void notifyAll()
25 | 唤醒在此对象监视器上等待的所有线程。
26 |
27 | String toString()
28 | 返回该对象的字符串表示。
29 |
30 | void wait()
31 | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
32 |
33 | void wait(long timeout)
34 | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
35 |
36 | void wait(long timeout, int nanos)
37 | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
--------------------------------------------------------------------------------
/java/[Java] Override和Overload的使用规则和区别.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] Override和Overload的使用规则和区别.md
--------------------------------------------------------------------------------
/java/[Java] Switch能否用string做参数?.md:
--------------------------------------------------------------------------------
1 | 1 . 在jdk 7 之前,switch 只能支持 byte、short、char、int 这几个基本数据类型和其对应的封装类型。switch后面的括号里面只能放int类型的值,但由于byte,short,char类型,它们会 **自动** 转换为int类型(精精度小的向大的转化),所以它们也支持。
2 |
3 | 对于精度比int大的类型,long、float、double,不会自动转换成int。要想使用就得加强转如(int)long。
4 |
5 | 另外boolean类型不参与转换,任何类型不能转换为boolean型.
6 |
7 | 2 .我们也可以用枚举类型实现switch可传入string参数
8 |
9 | ```
10 | public enum En{
11 | a,b,c
12 | }
13 | public static void main(String[] args) {
14 | En t = En.a;
15 | function(t);
16 | }
17 | public static void function(En type){
18 | switch (type) {
19 | case a:
20 | System.err.println("a");
21 | break;
22 | case b:
23 | System.err.println("b");
24 | break;
25 | case c:
26 | System.err.println("c");
27 | break;
28 | default:
29 | break;
30 | }
31 | }
32 | ```
33 | 运行结果:
34 |
35 | 
36 |
37 | 3 . jdk7之后java加入了switch对string的支持,就不用枚举来实现啦!
38 |
39 | ```
40 | public static void main(String[] args) {
41 | String s = "a";
42 | switch (s) {
43 | case "a":
44 | System.err.println("a");
45 | break;
46 | case "b":
47 | System.err.println("b");
48 | break;
49 | case "c":
50 | System.err.println("c");
51 | break;
52 | default:
53 | break;
54 | }
55 | }
56 | ```
57 | 运行结果:
58 |
59 | 
--------------------------------------------------------------------------------
/java/[Java] ThreadLocal的使用规则和源码分析.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] ThreadLocal的使用规则和源码分析.md
--------------------------------------------------------------------------------
/java/[Java] ThreadPool用法与示例.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] ThreadPool用法与示例.md
--------------------------------------------------------------------------------
/java/[Java] equals与==的区别.md:
--------------------------------------------------------------------------------
1 | - == 是一个运算符。
2 | equals则是string对象的方法。
3 |
4 | - java中 **值类型** 是存储在内存中的**栈**中。
5 | 而**引用类型**在栈中仅仅是存储引用类型变量的地址,而其本身则存储在**堆**中。所以字符串的内容相同,引用地址不一定相同,有可能创建了多个对象。
6 |
7 | - ==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同。
8 |
9 | - equals将此字符串与指定的对象比较。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的 String 对象时,结果才为 true。即堆中的内容是否相同。==比较的是2个对象的地址(栈中),而equals比较的是2个对象的内容(堆中)。所以当equals为true时,==不一定为true。
10 |
11 | > 下面是String类equals方法源码,它复写了类 Object 中的 equals方法。
12 |
13 | ```
14 | public boolean equals(Object anObject) {
15 | 965 if (this == anObject) {
16 | 966 return true;
17 | 967 }
18 | 968 if (anObject instanceof String) {
19 | 969 String anotherString = (String)anObject;
20 | 970 int n = value.length;
21 | 971 if (n == anotherString.value.length) {
22 | 972 char v1[] = value;
23 | 973 char v2[] = anotherString.value;
24 | 974 int i = 0;
25 | 975 while (n-- != 0) {
26 | 976 if (v1[i] != v2[i])
27 | 977 return false;
28 | 978 i++;
29 | 979 }
30 | 980 return true;
31 | 981 }
32 | 982 }
33 | 983 return false;
34 | 984 }
35 | ```
36 | 上面已经说到equals是比较两个对象的内容,我们可以看到方法中,先是比较两个String对象是否为同一对象,如果是就直接返回true(两个对象为同一对象那他们的内容必然相等)。
37 | 如果不是同一对象,先确定传入的对象是否是String类型,如果是,则比较两对象的字符序列(String类内部存储是用char[]实现的,可以查看源码了解),遍历过程中只要有一个字符不相同,就返回false,否则返回true。这里**注意**比较次数为第一个String对象的长度n,而不是传入的String对象参数的长度。
38 |
--------------------------------------------------------------------------------
/java/[Java] try catch finally,try里有return,finally还执行么?.md:
--------------------------------------------------------------------------------
1 |
2 | *Condition 1:* 如果try中**没有异常**且try中**有return** (执行顺序)
3 |
4 | ```
5 | try ---- finally --- return
6 | ```
7 |
8 | *Condition 2:* 如果try中**有异常**并且try中**有return**
9 |
10 | ```
11 | try----catch---finally--- return
12 | ```
13 |
14 | 总之 finally 永远执行!
15 |
16 |
17 |
18 | *Condition 3:* try中有异常,try-catch-finally里都没有return ,finally 之后有个return
19 |
20 | ```
21 | try----catch---finally
22 | ```
23 |
24 | try中有异常以后,根据java的异常机制先执行catch后执行finally,此时错误异常已经抛出,程序因异常而终止,所以你的return是不会执行的
25 |
26 | *Condition 4:* 当 try和finally中都有return时,finally中的return会覆盖掉其它位置的return(多个return会报unreachable code,编译不会通过)。
27 |
28 | *Condition 5:* 当finally中不存在return,而catch中存在return,但finally中要修改catch中return 的变量值时
29 |
30 | ```
31 | int ret = 0;
32 | try{
33 | throw new Exception();
34 | }
35 | catch(Exception e)
36 | {
37 | ret = 1; return ret;
38 | }
39 | finally{
40 | ret = 2;
41 | }
42 |
43 | ```
44 | 最后返回值是1,因为return的值在执行finally之前已经确定下来了
--------------------------------------------------------------------------------
/java/[Java] 九种基本数据类型的大小,以及他们的封装类.md:
--------------------------------------------------------------------------------
1 | 变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。
2 | 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。
3 | 因此,通过定义不同类型的变量,可以在内存中储存整数、小数或者字符。
4 |
5 |
6 |
7 |
8 | Java的两大数据类型:
9 |
10 | (一).内置数据类型(基本数据类型)
11 |
12 | 1 六种数字类型 ( byte, short, int, long, float, double) + void
13 |
14 | 8 16 32 64 32 64 位
15 |
16 |
17 | 2 一种字符类型 char
18 |
19 | 16位Unicode字符
20 |
21 |
22 | 3 一种布尔型 boolean
23 |
24 | 1位
25 |
26 | (二).引用数据类型
27 |
28 | 引用类型变量由类的构造函数创建,可以使用它们访问所引用的对象。这些变量在声明时被指定为一个特定的类型。变量一旦声明后,类型就不能被改变了。
29 |
30 | 对象、数组都是引用数据类型,所有引用类型的默认值都是null。
31 |
32 |
33 |
34 | 基本数据类型只能按值传递,而封装类按引用传递。
35 |
36 | Void无返回值类型,作为伪类型对应类的对象,也被认为是 基本数据类型
37 |
--------------------------------------------------------------------------------
/java/[Java] 从源码分析String、StringBuffer与StringBuilder区别和联系.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] 从源码分析String、StringBuffer与StringBuilder区别和联系.md
--------------------------------------------------------------------------------
/java/[Java] 多线程下生产者消费者问题的五种同步方法实现.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] 多线程下生产者消费者问题的五种同步方法实现.md
--------------------------------------------------------------------------------
/java/[Java] 实现多线程的两种方法.md:
--------------------------------------------------------------------------------
1 |
2 | Java提供了两种创建线程方法:
3 |
4 | -
5 |
6 | 通过实现Runable接口;
7 |
8 | - 通过继承Thread类本身。
9 |
10 |
11 | 1 .声明实现 Runnable 接口的类,该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。例如,计算大于某一规定值的质数的线程可以写成:
12 |
13 |
14 | ```
15 | class PrimeRun implements Runnable {
16 | long minPrime;
17 | PrimeRun(long minPrime) {
18 | this.minPrime = minPrime;
19 | }
20 |
21 | public void run() {
22 | // compute primes larger than minPrime
23 | . . .
24 | }
25 | }
26 | ```
27 |
28 | 然后,下列代码会创建并启动一个线程:
29 |
30 | ```
31 | PrimeRun p = new PrimeRun(143);
32 | new Thread(p).start();
33 | ```
34 |
35 | 2.将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。
36 | ```
37 | class PrimeThread extends Thread {
38 | long minPrime;
39 | PrimeThread(long minPrime) {
40 | this.minPrime = minPrime;
41 | }
42 |
43 | public void run() {
44 | // compute primes larger than minPrime
45 | . . .
46 | }
47 | }
48 | ```
49 |
50 | 然后,下列代码会创建并启动一个线程:
51 |
52 | ```
53 | PrimeThread p = new PrimeThread(143);
54 | p.start();
55 | ```
56 |
57 | 当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:
58 |
59 |
60 |
61 | -
62 |
63 | 调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。
64 |
65 | - 非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。
66 |
67 | 3.使用和区别
68 |
69 | Runable源码:
70 |
71 |
72 | ```
73 | public interface Runnable {
74 | /**
75 | * When an object implementing interface Runnable
is used
76 | * to create a thread, starting the thread causes the object's
77 | * run
method to be called in that separately executing
78 | * thread.
79 | *
80 | * The general contract of the method run
is that it may
81 | * take any action whatsoever.
82 | *
83 | * @see java.lang.Thread#run()
84 | */
85 | public abstract void run();
86 | }
87 | ```
88 | Thread 类实现了 Runnable。激活的意思是说某个线程已启动并且尚未停止。此外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。**大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法**,那么应使用 Runnable 接口。这很重要,因为**除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类**。
89 |
90 | 继承Thread类实现多线程,要求放入多线程中的类不能继承其他类(Java的单继承特性),如果需要请用 Runnable 实现(接口可以多实现并不影响继承其他类)。
91 |
92 | 一个实现Runnable接口的类可以放在多个线程中执行,多个线程可以去执行同一资源;而继承Thread只能实现多个线程分别去处理自己的资源。(通过Runnable创建的多个线程可以由编程人员传入同一个Runnable对象,即执行同一个run方法,而通过Thread创建的多线程它们运行的都是自己的run方法)。
93 |
--------------------------------------------------------------------------------
/java/[Java] 接口(Interface)与 抽象类 (Abstract)使用规则和区别.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] 接口(Interface)与 抽象类 (Abstract)使用规则和区别.md
--------------------------------------------------------------------------------
/java/[Java] 方法锁、对象锁和类锁的意义和区别.md:
--------------------------------------------------------------------------------
1 | > 首先的明白java中锁的机制
2 | >
3 | > synchronized
4 | > 在修饰代码块的时候需要一个reference对象作为锁的对象.
5 | 在修饰方法的时候默认是当前对象作为锁的对象.
6 | 在修饰类时候默认是当前类的Class对象作为锁的对象.
7 |
8 | > [线程同步的方法:sychronized、lock、reentrantLock分析](http://blog.csdn.net/amazing7/article/details/51219714)
9 |
10 | #方法锁(synchronized修饰方法时)
11 |
12 | 通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。
13 |
14 | synchronized 方法控制对类成员变量的访问:
15 | 每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,**方法一旦执行,就独占该锁**,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中**至多只有一个**处于可执行状态,从而有效避免了类成员变量的访问冲突。
16 |
17 |
18 | # 对象锁(synchronized修饰方法或代码块)
19 |
20 | 当一个对象中有synchronized method或synchronized block的时候调用此对象的同步方法或进入其同步区域时,就必须先获得对象锁。如果此对象的对象锁已被其他调用者占用,则需要等待此锁被释放。(方法锁也是对象锁)
21 |
22 | java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程进入synchronized方法的时候获取该对象的锁,当然如果已经有线程获取了这个对象的锁,那么当前线程会等待;synchronized方法正常返回或者抛异常而终止,JVM会自动释放对象锁。这里也体现了用synchronized来加锁的1个好处,**方法抛异常的时候,锁仍然可以由JVM来自动释放。**
23 |
24 | 对象锁的两种形式:
25 |
26 | ```
27 | public class Test
28 | {
29 | // 对象锁:形式1(方法锁)
30 | public synchronized void Method1()
31 | {
32 | System.out.println("我是对象锁也是方法锁");
33 | try
34 | {
35 | Thread.sleep(500);
36 | } catch (InterruptedException e)
37 | {
38 | e.printStackTrace();
39 | }
40 |
41 | }
42 |
43 | // 对象锁:形式2(代码块形式)
44 | public void Method2()
45 | {
46 | synchronized (this)
47 | {
48 | System.out.println("我是对象锁");
49 | try
50 | {
51 | Thread.sleep(500);
52 | } catch (InterruptedException e)
53 | {
54 | e.printStackTrace();
55 | }
56 | }
57 |
58 | }
59 | }
60 | ```
61 |
62 | # 类锁(synchronized 修饰静态的方法或代码块)
63 |
64 |
65 | 由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都**只有一份**。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。
66 |
67 | **对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。**
68 |
69 | 类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。
70 | java类可能会有很多个对象,但是只有1个Class对象,也就是说类的不同实例之间共享该类的Class对象。Class对象其实也仅仅是1个java对象,只不过有点特殊而已。由于每个java对象都有1个互斥锁,而类的静态方法是需要Class对象。所以所谓的类锁,不过是Class对象的锁而已。获取类的Class对象有好几种,最简单的就是[类名.class]的方式。
71 |
72 | ```
73 | public class Test
74 | {
75 | // 类锁:形式1
76 | public static synchronized void Method1()
77 | {
78 | System.out.println("我是类锁一号");
79 | try
80 | {
81 | Thread.sleep(500);
82 | } catch (InterruptedException e)
83 | {
84 | e.printStackTrace();
85 | }
86 |
87 | }
88 |
89 | // 类锁:形式2
90 | public void Method2()
91 | {
92 | synchronized (Test.class)
93 | {
94 | System.out.println("我是类锁二号");
95 | try
96 | {
97 | Thread.sleep(500);
98 | } catch (InterruptedException e)
99 | {
100 | e.printStackTrace();
101 | }
102 |
103 | }
104 |
105 | }
106 | }
107 | ```
--------------------------------------------------------------------------------
/java/[Java] 的四种引用,强弱软虚,用到的场景.md:
--------------------------------------------------------------------------------
1 | > 从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
2 |
3 | 1 . 强引用(StrongReference)
4 |
5 | 强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。如代码String s=”abc”中变量s就是字符串对象”abc”的一个强引用。只要你给强引用对象s赋空值null,该对象就可以被垃圾回收器回收。因为该对象此时不再含有其他强引用。
6 |
7 | 2 . 弱引用(WeakReference)
8 |
9 | 弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象(s),不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象,弱引用非常适合存储元数据。另一个使用弱引用的例子是WeakHashMap,它是除HashMap和TreeMap之外,Map接口的另一种实现。WeakHashMap有一个特点:map中的键值(keys)都被封装成弱引用,也就是说一旦强引用被删除,WeakHashMap内部的弱引用就无法阻止该对象被垃圾回收器回收。
10 |
11 | 如下代码创建弱引用:
12 |
13 | ```
14 | Counter counter = new Counter(); // strong reference - line 1
15 | WeakReference weakCounter = new WeakReference(counter); //weak reference
16 | counter = null; // now Counter object is eligible for garbage collection
17 | ```
18 | 3 . 软引用(SoftReference)
19 |
20 | 如果一个对象(如 s)只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
21 |
22 | 可以使用如下代码创建软引用:
23 | ```
24 | Counter prime = new Counter(); // prime holds a strong reference
25 | SoftReference soft = new SoftReference(prime) ; //soft reference variable has SoftReference to Counter Object created at line 2
26 |
27 | prime = null; // now Counter object is eligible for garbage collection but only be collected when JVM absolutely needs memory
28 | ```
29 |
30 |
31 | 4 . 虚引用(PhantomReference)
32 |
33 | "虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
34 | 虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用 **必须** 和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
35 |
36 | 如下代码创建虚引用:
37 |
38 | ```
39 | DigitalCounter digit = new DigitalCounter(); // digit reference variable has strong reference – line 3
40 | PhantomReference phantom = new PhantomReference(digit); // phantom reference to object created at line 3
41 |
42 | digit = null;
43 | ```
44 |
45 | 弱引用、软引用**可以和**一个引用队列(ReferenceQueue)联合使用,如果其所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
46 |
47 | 在创建任何弱引用、软引用和虚引用的过程中你可以通过如下代码提供引用队列ReferenceQueue。
48 |
49 | ```
50 | ReferenceQueue refQueue = new ReferenceQueue(); //reference will be stored in this queue for cleanup
51 | DigitalCounter digit = new DigitalCounter();
52 | PhantomReference phantom = new PhantomReference(digit, refQueue);
53 | ```
--------------------------------------------------------------------------------
/java/[Java] 线程同步的方法:sychronized、lock、reentrantLock分析.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] 线程同步的方法:sychronized、lock、reentrantLock分析.md
--------------------------------------------------------------------------------
/java/[Java] 集合框架的层次结构和使用规则梳理.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/java/[Java] 集合框架的层次结构和使用规则梳理.md
--------------------------------------------------------------------------------
/java/[Java] 面向对象的三个特征与含义.md:
--------------------------------------------------------------------------------
1 | > 对象
2 | > 是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
3 | >
4 | > 类
5 | > 是一个模板,它描述一类对象的行为和状态。
6 |
7 | 1 . **封装性**
8 |
9 | 将对象的状态信息尽可能的隐藏在对象内部,只保留有限的接口和方法与外界进行交互,从而避免了外界对对象内部属性的破坏。
10 |
11 | Java中使用访问控制符来保护对类、变量、方法和构造方法的访问。
12 | Java支持4种不同的访问权限。
13 |
14 | 默认的,也称为default,在同一包内可见,不使用任何修饰符。
15 | 私有的,以private修饰符指定,在同一类内可见。
16 | 共有的,以public修饰符指定,对所有类可见。
17 | 受保护的,以protected修饰符指定,对同一包内的类和所有子类可见。
18 |
19 | 2. **继承**
20 |
21 | java通过继承创建分等级层次的类,可以理解为一个对象从另一个对象获取属性的过程。
22 |
23 | 类的继承是单一继承,也就是说,一个子类只能拥有一个父类
24 | 下面的做法是不合法的:
25 |
26 | ```
27 | public class extends Animal, Mammal{}
28 | ```
29 | 但是我们可以用多继承接口来实现, 如:
30 |
31 |
32 | ```
33 | public class Apple extends Fruit implements Fruit1, Fruit2{}
34 | ```
35 |
36 |
37 | 继承中最常使用的两个关键字是extends(用于基本类和抽象类)和implements(用于接口)。
38 |
39 | 注意:子类拥有父类所有的成员变量,但对于父类private的成员变量却没有访问权限,这保障了父类的封装性。
40 | 下面是使用关键字extends实现继承。
41 |
42 |
43 | ```
44 | public class Animal{
45 | }
46 |
47 | public class Mammal extends Animal{
48 | }
49 |
50 | public class Reptile extends Animal{
51 | }
52 |
53 | public class Dog extends Mammal{
54 | }
55 | ```
56 | 通过使用关键字extends,子类可以继承父类所有的方法和属性,但是无法使用 private(私有) 的方法和属性。
57 | 我们通过使用instanceof 操作符能够确定一个对象是另一个对象的一个分类。
58 |
59 | ```
60 | public class Dog extends Mammal{
61 |
62 | public static void main(String args[]){
63 |
64 | Animal a = new Animal();
65 | Mammal m = new Mammal();
66 | Dog d = new Dog();
67 |
68 | System.out.println(m instanceof Animal);
69 | System.out.println(d instanceof Mammal);
70 | System.out.println(d instanceof Animal);
71 | }
72 | }
73 | ```
74 | 结果如下:
75 |
76 | ```
77 | true
78 | true
79 | true
80 | ```
81 | Implements关键字使用在类继承接口的情况下, 这种情况不能使用关键字extends。
82 |
83 | ```
84 | public interface Animal {}
85 |
86 | public class Mammal implements Animal{
87 | }
88 |
89 | public class Dog extends Mammal{
90 | }
91 | ```
92 | 可以使用 instanceof 运算符来检验Mammal和dog对象是否是Animal类的一个实例。
93 |
94 | ```
95 | interface Animal{}
96 |
97 | class Mammal implements Animal{}
98 |
99 | public class Dog extends Mammal{
100 | public static void main(String args[]){
101 |
102 | Mammal m = new Mammal();
103 | Dog d = new Dog();
104 |
105 | System.out.println(m instanceof Animal);
106 | System.out.println(d instanceof Mammal);
107 | System.out.println(d instanceof Animal);
108 | }
109 | }
110 | ```
111 | 运行结果如下:
112 |
113 | ```
114 | true
115 | true
116 | true
117 | ```
118 |
119 | 3.**多态**
120 |
121 | 多态是同一个行为具有多个不同表现形式或形态的能力。
122 | 多态性是**对象多种表现形式的体现**
123 |
124 | 比如:我到宠物店说"请给我一只宠物",服务员给我小猫、小狗或者蜥蜴都可以,我们就说"宠物"这个对象就具备多态性。
125 |
126 | 例子
127 | ```
128 | public interface Vegetarian{}
129 | public class Animal{}
130 | public class Deer extends Animal implements Vegetarian{}
131 | ```
132 | 因为Deer类具有多重继承,所以它具有多态性。
133 | 访问一个对象的唯一方法就是通过引用型变量 (编译时变量)。
134 | 引用型变量只能有一种类型,一旦被声明,引用型变量的类型就不能被改变了。
135 | 引用型变量不仅能够被重置为其他对象,前提是这些对象没有被声明为final。还可以引用和它类型相同的或者相兼容的对象。它可以声明为类类型或者接口类型。
136 |
137 | ```
138 | Deer d = new Deer();
139 | Animal a = d;
140 | Vegetarian v = d;
141 | Object o = d;
142 | ```
143 | 所有的引用型变量d,a,v,o都指向堆中相同的Deer对象。
144 |
145 | 我们来看下面这个例子:
146 |
147 | ```
148 | public class Animal {
149 | public String name = "父类name";
150 | public void move(){
151 | System.out.println("父类move");
152 | }
153 | public void content(){
154 | System.out.println("父类content");
155 | }
156 | }
157 | ```
158 |
159 | ```
160 | public class Bird extends Animal{
161 | public String name = "子类name";
162 | @Override
163 | public void move() {
164 | // TODO Auto-generated method stub
165 | System.out.println("子类move");
166 | }
167 | public void content(){
168 | System.out.println("子类content");
169 | }
170 |
171 | }
172 | ```
173 |
174 | ```
175 | public class Test {
176 | public static void main(String[] args) {
177 | Animal a = new Animal();
178 | System.out.println(a.name);
179 | a.move();
180 | a.content();
181 |
182 | System.out.println("----------------------");
183 |
184 | Animal b = new Bird(); //向上转型由系统自动完成
185 | //编译时变量 运行时变量
186 | System.out.println(b.name);
187 | b.move();
188 | b.content();
189 |
190 | System.out.println("----------------------");
191 |
192 | Bird c = new Bird();
193 | System.out.println(c.name);
194 | c.move();
195 | c.content();
196 | }
197 | }
198 | ```
199 | 运行结果:
200 |
201 | ```
202 | 父类name
203 | 父类move
204 | 父类content
205 | ----------------------
206 | 父类name
207 | 子类move
208 | 子类content
209 | ----------------------
210 | 子类name
211 | 子类move
212 | 子类content
213 |
214 | ```
215 | 说明:Bird类继承Animal并重写了其方法。
216 | 因为Animal b = new Bird(),编译时变量和运行时变量不一样,所以多态发生了。可以从最后的运行结果中看出,调用了**父类的成员变量name和子类重写后的两个方法**。
217 | 上面继承说了,子类可以调用父类所有非private的方法和属性。因为name是一个String的对象,**与方法不同,对象的域不具有多态性**。通过引用变量来访问其包含的实例变量时,系统总是视图访问它编译时类型所定义的变量,而不是他运行时类型所定义的变量。
218 |
219 | 那么问题来了,如果我们把Animal的成员变量换成private,那会不会去调用Bird类的成员变量name来打印输出呢?
220 | 
221 |
222 | 也就是说 **系统访问的始终是去访问编译时类型所定义的变量**。
223 |
224 | > 重写定义:子类对父类的允许访问的方法的实现过程进行重新编写!返回值和形参都不能改变。即外壳不变,核心重写!
225 |
226 |
--------------------------------------------------------------------------------
/java/[java] static的作用和意义.md:
--------------------------------------------------------------------------------
1 | # static 静态修饰符
2 |
3 | 在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的。static修饰符表示静态的,在类加载时Jvm会把它放到**方法区**,被本类以及本类的所有实例所共用。在编译后所分配的内存会**一直存在**,直到程序退出内存才会释放这个空间。如果一个被所有实例共用的方法被申明为static,那么就可以节省空间,不用每个实例初始化的时候都被分配到内存。
4 |
5 | > java类被加载过程
6 |
7 | >类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:
8 | >①加载(以二进制形式来生成Class对象)
9 | >②链接(又分为验证、准备和解析)
10 | > 校验:检查导入类或接口的二进制数据的正确性;
11 | > 准备:给类的静态变量分配并初始化存储空间;
12 | > 解析:将符号引用转成直接引用;
13 | >③初始化(激活类的静态变量和静态代码块、初始化Java代码)
14 |
15 |
16 | ##静态变量
17 |
18 | Static关键字修饰成员变量被称为静态变量(也叫作类变量,同时 局部变量也能被声明为static),静态变量在内存中只有一个拷贝(节省内存,方便对象之间共享值),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(当然也可以通过对象来访问)。因为静态变量被类的所有实例共用,所以非线程安全的。
19 |
20 | 未被Static修饰的成员变量叫作实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量在内存中可以有多个拷贝(但互相不影响,更加灵活)。
21 |
22 | ```
23 | //静态变量的申明
24 | private static int count = 0;
25 | public static String str;
26 | ```
27 | ## 静态方法
28 |
29 | 静态方法可以直接通过类名调用,任何的实例也都可以调用。
30 | **只能**访问所属类的静态成员变量和成员方法,静态方法中也不能用this和super关键字。
31 | 类似于静态变量,静态方法也属于类,不属于实例的。
32 |
33 | ```
34 | //静态方法的申明
35 | public static void s(int param) {
36 | ......
37 | }
38 | ```
39 |
40 | ## 静态代码块
41 |
42 | 静态代码块就是在类加载器加载对象时,要执行的一组语句。静态块只会在类加载到内存中的时候执行一次,位置可以随便放,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。
43 |
44 | ```
45 | static{
46 | //在类被加载的时候用于初始化资源,仅能访问静态变量和静态方法
47 | System.out.println("StaticExample static block");
48 | }
49 | ```
50 |
51 | ## 静态类
52 |
53 | **只能在内部类中定义静态类**,静态内部类与外层类绑定,即使没有创建外层类的对象,它一样存在。
54 | 静态类的方法可以是静态的方法也可以是非静态的方法,静态的方法可以在外层通过静态类调用,而非静态的方法必须要创建类的对象之后才能调用。
55 | 只能引用外部类的static成员变量(也就是类变量)。
56 |
57 |
58 | 如果一个内部类不是被定义成静态内部类,那么在定义成员变量或者成员方法的时候,是不能够被定义成静态的。
59 |
60 |
61 |
62 | ```
63 | public class OuterClass {
64 | public static class InnerClass{
65 | InnerClass(){
66 | System.out.println("静态内部类");
67 | }
68 | }
69 | }
70 | ```
71 |
72 |
--------------------------------------------------------------------------------
/java/[java] 多态实现的JVM调用过程.md:
--------------------------------------------------------------------------------
1 | > 多态
2 | >
3 | >同一个类的不同表现形态,不同的形态是通过其不同的子类体现
4 | >java通过将子类对象引用赋值给超类对象变量, 来实现动态方法调用。
5 | >
6 | >[面向对象的三个特征与含义](http://blog.csdn.net/amazing7/article/details/51219687)
7 |
8 | 下面看例子:
9 |
10 | ```
11 | public class A{
12 | public String name = "父类name";
13 | public void move(){
14 | System.out.println("父类move");
15 | }
16 | }
17 | ```
18 |
19 | ```
20 | public class B extends A{
21 | public String name = "子类name";
22 | @Override
23 | public void move() {
24 | // TODO Auto-generated method stub
25 | System.out.println("子类move");
26 | }
27 | }
28 | ```
29 |
30 | ```
31 | public class Test {
32 | public static void main(String[] args) {
33 | A a = new B();
34 | a.move();
35 | }
36 | }
37 |
38 | ```
39 |
40 | **类B是类A的子类, A a = new B() 编译时变量和运行时变量不一样,所以多态发生了。**
41 |
42 |
43 | ① A a 作为一个引用类型数据,存储在JVM栈的**本地变量表**中。
44 | ② new B()作为**实例对象数据**存储在堆中
45 | B的对象实例数据(接口、方法、field、对象类型等)的地址也存储在堆中
46 | B的对象的类型数据(对象实例数据的地址所执行的数据)存储在方法区中,方法区中 对象类型数据 中有一个指向该类方法的**方法表**。
47 |
48 | ③Java虚拟机规范中并未对引用类型访问具体对象的方式做规定,目前主流的实现方式主要有两种:
49 |
50 | 1. 通过句柄访问
51 | 
52 |
53 | 在这种方式中,JVM堆中会专门有一块区域用来作为句柄池,存储相关句柄所执行的实例数据地址(包括在堆中地址和在方法区中的地址)。这种实现方法由于用句柄表示地址,因此十分**稳定**。
54 |
55 | 2.通过直接指针访问
56 | 
57 |
58 | 通过直接指针访问的方式中,reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。这种方法最大的优势是速度快,在HotSpot虚拟机中用的就是这种方式。
59 |
60 | ④实现过程
61 |
62 | 首先虚拟机通过reference类型(A的引用)查询java栈中的 本地变量表,得到堆中的 对象类型数据的地址,从而找到方法区中的 对象类型数据(B的对象类型数据) ,然后查询方法表定位到实际类(B类)的方法运行。
--------------------------------------------------------------------------------
/java/git命令使用.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | **Commit(提交)**: 点击会出现如下界面,commit message输入你提交的信息,一般是做了什么修改和工作,项目所有者和提交者会自动生成。下面Files选择哪些你做了修改的文件进行提交(这里注意你的.gitigonre文件的配置,没有的话新建一个加入相应的过滤规则,一般来说.class文件是不用提交的,否则别人提交就会有冲突)。最后Commit and push 是把你这次提交到本地仓库同时推送到服务器上的仓库中,而Commit是将本地修改保存到本地仓库中。
5 |
6 | 
7 |
8 |
9 | **stashes(储藏)**: 举个例,今天测试发现我昨天提交代码中有bug,然而我今天来后又做了些新功能,测试又让我马上修复bug,没办法只能改为去修复bug。那么stashes命令就派上用处了,它会把今天做的工作储藏到缓冲区,把工作目录和索引里的内容恢复到上次提交的状态,接下来我就可以修改bug了。修改完成后我把项目再提交一个版本给测试,然后我再找到我stashes的相应节点恢复我的工作目录,继续写我今天的东西。
10 |
11 |
12 | **push to Upstream(推送到远程分支)**: 先说明下upstream是什么,举个例,我在本地仓库中新建了一个分支a,把代码推送到远程仓库的分支b,那么分支b就是分支a的 upstream,反之分支a是分支b的downstream。
13 |
14 |
15 | **Fetch from Upstream(拉取远程仓库分支到本地)**: upstream上面说了,我们来说说fetch和pull的区别,都是从远程仓库拉取,fetch直接获取最新版本不做合并,而pull是获取最新版本并合并到本地。简单的说就是 pull = fetch + merge 。
16 |
17 |
18 | **push branch 'master'**(推送到master分支): 在 Git 的实现中每次提交都会保存一个提交对象,该对象包含0个或多个(第一次提交没有父对象)指向该对象的父对象指针,包含一个指向暂存内容的指针和本次提交的作者、时间等相关附属信息。Git会使用master作为分支的默认名称。
19 |
20 |
21 | **Pull**(拉取远程仓库分支到本地并与本地分支合并): 建议少用 Pull 多用 Fetch 和 Merge,pull把很多细节都隐藏起来了,不利于理解结构同时一旦出错也不容易找到出错的地方。
22 |
23 |
24 | **Remote/Push**(推送到远程代码库): remote命令用于管理远程主机, Tag指某个分支某个时间的特定状态,一般用于标记版本号。下面两个在远程代码库地址改变时需要配置。
25 |
26 | 
27 |
28 |
29 | **merge**(合并): 将其他分支的内容合并到当前分支中。
30 |
31 |
32 | **rebase**(修改合并): 将一个分支修改合并到当前分支。这里说一下merge和rebase的区别:merge是直接合并分支,如果有冲突,完成后在一并解决。 rebase则是按时间线依次合并,如果产生冲突,会提示你进行处理,处理好了可以continue直到rebase完成,如果冲突处理不好可以放弃rebase或skip。
33 |
34 |
35 | **Reset** (回溯):可以将当前分支切换到本分支以前的任何一个版本状态。
36 |
37 |
38 | **patch**(补丁): 生成文件的对比信息,可以通过diff(apply)生成的标准patch,或使用format-patch生成的git专用patch。
39 |
40 |
41 | **Index**(暂存区): 是一个包含文件索引的目录树,记录了一些文件的信息,如文件名、状态、时间戳、长度等。当解决完git冲突时要把文件 add to index
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/java/wait()和sleep()的区别.md:
--------------------------------------------------------------------------------
1 | 这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类。
2 | sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。
3 |
4 | 锁: 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
5 |
6 | sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
7 | Thread.sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。
8 |
9 | 使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。
10 |
11 | ```
12 | synchronized(x){
13 | x.notify()
14 | //或者wait()
15 | }
16 | ```
17 |
18 |
--------------------------------------------------------------------------------
/简历模板.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soyoungboy/AndroidInterview/b1d70e816c265fbf358061f0a501dc2c675b064b/简历模板.docx
--------------------------------------------------------------------------------