以后的筆記按照這個圖片的思路來做筆記:基礎篇->進階篇->高級篇->提高篇

一、基礎篇:
1.基礎篇
(1)面向對象:
2013年剛開始學C語言的時候,我們解決一個問題或者開發一個系統的時候都是按照這個系統需要哪些功能我們要編程哪些方法的思維來開發的,這種按照就是所謂的面向過程編程.
等到14年學習java編程前,記得有個計算機系主任來進行講課《計算機導論》這節課,形象得講說人類也是類(即java的class類),主任是人類的實例化,即實實在在的人類的對象,人類具有手、腳、眼睛等,這些就是類的成員變量(即屬性),人類會跳舞、吃飯等行為屬于成員方法(行為),也就是說我們看待現實世界客觀事物的時候,不再以一種具備哪些功能的思路看待的時候(這種思路就是面向過程),而是這個對象具有哪些屬性、哪些行為的時候,那就可以說,你具備了面向對象的思維了;
借此再說一下類和對象的關系:類就是對象的抽象,對象是類的實例化,例如說的人類就是一個抽象的概念,我們覺得具備有四肢、有頭腦、有思維等特征的就是人類,主任就是實實在在的人,他就是人類的對象。
(2)三大特性
封裝:封裝就是想讓成員方法和變量不讓外界直接訪問到,java用private進行私有化,類似我們生活中手機,提供了撥打電話的按鈕,你不用去在乎這個打電話的功能是那些器件組成的,這個過程調制器,cpu,電話卡是怎么配合工作,都隱藏起來了,這就是封裝的作用
說到private:提供一個圖片

繼承:我們有個汽車類,具有汽車架構、行駛功能,但是我們陸陸續續有定制化的小轎車也有汽車的架構、行駛功能,但是轎車還有自己獨特的功能,這時候就可以繼承汽車類,具備汽車的功能,對于自己其它的特征用途轎車自己添加,這樣子可以實現代碼復用
多態:同一個行為具有不同的表現形式就稱為多態,例如畫畫這個行為,有的用彩色筆畫畫,有的用石墨畫畫,有的抽象派畫畫,有的現實派畫畫等等
下面經典的動物類多態例子,可以快速理解多態
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃魚");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨頭");
}
public void work() {
System.out.println("看家");
}
}
(3)關鍵字:
關鍵字有50個,兩個java團隊還沒有用到:goto 跳轉到某個地方、const 常量(c語言也有這個常量關鍵詞),其實還有3個特殊直接量:true、false、null,這里沒有羅列進來
| abstract | 表明類或者成員方法具有抽象屬性 |
| assert | 斷言,用來進行程序調試 |
| boolean | 基本數據類型之一,聲明布爾類型的關鍵字 |
| break | 提前跳出一個塊 |
| byte | 基本數據類型之一,字節類型 |
| case | 用在switch語句之中,表示其中的一個分支 |
| catch | 用在異常處理中,用來捕捉異常 |
| char | 基本數據類型之一,字符類型 |
| class | 聲明一個類 |
| const | 保留關鍵字,沒有具體含義 |
| continue | 回到一個塊的開始處 |
| default | 默認,例如,用在switch語句中,表明一個默認的分支。Java8 中也作用于聲明接口函數的默認實現 |
| do | 用在do-while循環結構中 |
| double | 基本數據類型之一,雙精度浮點數類型 |
| else | 用在條件語句中,表明當條件不成立時的分支 |
| enum | 枚舉 |
| extends | 表明一個類型是另一個類型的子類型。對于類,可以是另一個類或者抽象類;對于接口,可以是另一個接口 |
| final | 用來說明最終屬性,表明一個類不能派生出子類,或者成員方法不能被覆蓋,或者成員域的值不能被改變,用來定義常量 |
| finally | 用于處理異常情況,用來聲明一個基本肯定會被執行到的語句塊 |
| float | 基本數據類型之一,單精度浮點數類型 |
| for | 一種循環結構的引導詞 |
| goto | 保留關鍵字,沒有具體含義 |
| if | 條件語句的引導詞 |
| implements | 表明一個類實現了給定的接口 |
| import | 表明要訪問指定的類或包 |
| instanceof | 用來測試一個對象是否是指定類型的實例對象 |
| int | 基本數據類型之一,整數類型 |
| interface | 接口 |
| long | 基本數據類型之一,長整數類型 |
| native | 用來聲明一個方法是由與計算機相關的語言(如C/C++/FORTRAN語言)實現的 |
| new | 用來創建新實例對象 |
| package | 包 |
| private | 一種訪問控制方式:私用模式 |
| protected | 一種訪問控制方式:保護模式 |
| public | 一種訪問控制方式:共用模式 |
| return | 從成員方法中返回數據 |
| short | 基本數據類型之一,短整數類型 |
| static | 表明具有靜態屬性 |
| strictfp | 用來聲明FP_strict(單精度或雙精度浮點數)表達式遵循IEEE 754算術規范 |
| super | 表明當前對象的父類型的引用或者父類型的構造方法 |
| switch | 分支語句結構的引導詞 |
| synchronized | 表明一段代碼需要同步執行 |
| this | 指向當前實例對象的引用 |
| throw | 拋出一個異常 |
| throws | 聲明在當前定義的成員方法中所有需要拋出的異常 |
| transient | 聲明不用序列化的成員域 |
| try | 嘗試一個可能拋出異常的程序塊 |
| void | 聲明當前成員方法沒有返回值 |
| volatile | 表明兩個或者多個變量必須同步地發生變化 |
| while | 用在循環結構中 |
(3-1)用于數據類型。
用于數據類型的關鍵字有 boolean、byte、char、 double、 false、float、int、long、new、short、true、void、instanceof。
(3-2)用于語句。
用于語句的關鍵字有break、case、 catch、 continue、 default 、do、 else、 for、 if、return、switch、try、 while、 finally、 throw、this、 super。
(3-3)用于修飾
用于修飾的關鍵字有 abstract、final、native、private、 protected、public、static、synchronized、
transient、 volatile。
(3-4)用于方法、類、接口、包和異常。
用于方法、類、接口、包和異常的關鍵字有 class、 extends、 implements、interface、 package、import、throws。
還有些關鍵字,如cat、 future、 generic、innerr、 operator、 outer、rest、var等都是Java保留的沒有意義的關鍵字。
另外,Java還有3個保留字:true、false、null。它們不是關鍵字,而是文字。包含Java定義的值。和關鍵字一樣,它們也不可以作為標識符使用。
(4)基本數據類型:
整數
4-1) byte Byte
byte是一個8位數的整數型,繼承Nunber并且實現Compareable
extends Number implements Comparable<Byte>
最大值最小值
public static final byte MIN_VALUE = -128;
/**
* A constant holding the maximum value a {@code byte} can
* have, 2<sup>7</sup>-1.
*/
public static final byte MAX_VALUE = 127;
compareTo方法返回 x-y
public static int compare(byte x, byte y) {
return x - y;
}
hashcode返回對應的int值
public static int hashCode(byte value) {
return (int)value;
}
等等
4-2)short
繼承實現同上
由于是2字節16位,最小值-1*2的15次方 最大值 2的-15次方-1
public static final short MIN_VALUE = -32768;
public static final short MAX_VALUE = 32767;
hashcode一樣返回int
public static int hashCode(short value) {
return (int)value;
}
compare 一樣
4-3)int
類似的
4-4)long
類似的
浮點型
4-5)float
每次都返回新的對象
public static Float valueOf(float f) {
return new Float(f);
}
4-6)double
每次都返回新的對象
public static Double valueOf(double d) {
return new Double(d);
}
字符型
4-7)char
這個也是有緩存
static final Character cache[] = new Character[127 + 1];
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
布爾型
4-8)bool
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
(5)String
5-1)為了寫這個總結,特意去java的官網https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/String.html看了一下String描述:
The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class.
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. For example:
String str = "abc";
大概講了就是String類屬于不可變的,看源碼可以知道 public final class String 用了final修飾
5-2)除此之外,String都是放在方法區,有一個字符串常量池維護著,所以我們每次創建字符串都會去查看常量池看看是否已經存在,若已經存在直接引用
5-3)字符串比較,比較是屬于ascii,例如
String a="1";
String b="a";
System.out.print(a.compareTo(b));
打印-48 因為1對應49,a對應97,相減為-48
5-4)常用的幾個String方法
字符串下標截取
String b="123456";
System.out.println(b.substring(2,4));
打印34
int等基礎類型轉換成字符串
int n=123456;
String c=String.valueOf(n);
5-5)比較StringBuffer,StringBuilder
(6)集合
這個有點多,具體參照下圖

具體參照:https://blog.csdn.net/qingwengang/article/details/80394957
由于篇幅太多,我們就講幾個
Collection下面的List:Vector(線程安全)LinkedList/ArrayList
6-1) ArrayList 繼承->AbstractList 繼承->AbstractCollection具體看圖
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
說一下核心:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
// 序列化id
private static final long serialVersionUID = 8683452581122892189L;
// 默認初始的容量
private static final int DEFAULT_CAPACITY = 10;
// 一個空對象
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
// 一個空對象,如果使用默認構造函數創建,則默認對象內容默認是該值
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
// 當前數據對象存放地方,當前對象不參與序列化
transient Object[] elementData;
// 當前數組長度
private int size;
// 數組最大長度
private static final int MAX_ARRAY_SIZE = 2147483639;
// 省略方法。。
}
然后看看三個構造方法
/**
* Constructs an empty list with an initial capacity of ten.我們沒有傳變量的時候設置為空,此時還沒有開辟新的內存,直接指向類成員DEFAULTCAPACITY_EMPTY_ELEMENTDATA
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//根據傳過來的容量來,大于0初始化,等于0,用到EMPTY_ELEMENTDATA,小于0報錯
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;//這個1.7版本是會直接 this.elementData = new Object[initialCapacity]; 這里避免了new 空對象
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//這個構造方法直接可以傳Collection過來,Arrays.copyOf是深拷貝,相當于elementData用了新的地址了
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
看到這里,其實有人還是沒太大明白,為什么要聲明EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA呢?
其實在add方法,每次add,都要保證不會下標溢出,所以有了ensureCapacityInternal方法
步驟1
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! 這里是保證容量的方法,調用calculateCapacity
elementData[size++] = e;
return true;
}
步驟2
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
步驟3 //計算容量的
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);//如果你剛開始沒有賦值,那我就給你默認值DEFAULT_CAPACITY 10
}
return minCapacity;
}
步驟4
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
步驟5 真正在擴容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//這里就是經常說的擴容1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
參照:
https://blog.csdn.net/weixin_43390562/article/details/101236833
https://blog.csdn.net/augfun/article/details/82323164
6-2)LinkedList
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
看一下主要有兩個
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
//學過C就知道是指針的頭部,這里是指第一個對象 順便提一下transient 是不進行序列化
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
//最后一個
transient Node<E> last;
//內部類
private static class Node<E> {
E item;//正在的對象,存放數據
Node<E> next;//下一個node地址
Node<E> prev;//前面一個node地址
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
public boolean add(E e) {
linkLast(e);//默認添加后末端
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)//如果為空,說明加的第一個
first = newNode;
else
l.next = newNode;//下一個指向新add的node
size++;
modCount++;
}
//向某個下標插入E
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));//node方法根據index遍歷獲取node對象
}
//主要看linkBefore,下面畫了個圖,大概可以描述清楚
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;//
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
、

我做了個實驗,分別給LinkedList和ArrayList添加100000和打印100000,添加效率差不多,打印的時候,Link就慢得多
Arr:4297
Link:46282
6-3)ArrayList
ArrayList和Vector都是使用數組方式存儲數據,其余區別不大
這個加了同步鎖,例如
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
modCount++;
ensureCapacityHelper(minCapacity);
}
}
Vector:4166
還有Map下面的:HashMap、Hashtable、ConcurrentMap
6-4)HashMap主要為散列表:
table為數組,然后每個Node為鏈表,簡稱散列表
transient Node<K,V>[] table;
添加時候主要調用
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)//數組的數量-1,和hash做與運算,初始值為16,16-1為15,二進制位1111,這種情況的哈希沖突是最少的
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
6-5)HashTable主要是加了synchronized
6-6)ConcurrentMap這個在1.7使用segment分段鎖,好處就是改進了Hashtable的鎖住整個table,壞處就是要每次查找2次hash
<7>枚舉
枚舉就兩種寫法
public enum TestEnum {
RED(1), GREEN(2), BLANK(3), YELLOW(41);
int testStatus;
TestEnum(int i) {//一定要構造方法
testStatus=i;
}
public int getTestStatus() {
return testStatus;
}
public void setTestStatus(int testStatus) {
this.testStatus = testStatus;
}
}
public static void main(String[] args) {
System.out.println(TestEnum.YELLOW.testStatus);//這里有點類似于static的使用
}
結果
Connected to the target VM, address: '127.0.0.1:57115', transport: 'socket'
41
Disconnected from the target VM, address: '127.0.0.1:57115', transport: 'socket'
寫法2
public enum UseStatusEnum {
PACKING_NOT_USE(1,"11"), // 未領用
PACKING_HAS_USED(2,"22"), // 已領用
PACKING_BACK_USE(3,"33"); // 已打回
private Integer useStatus;
private String str;
private UseStatusEnum(int useStatus,String str) {
this.useStatus = useStatus;
this.str=str;
CollectionUtils.isEmpty(new HashMap<>());
}
public Integer getUseStatus() {
return useStatus;
}
public String getStr() {
return str;
}
public static void main(String[] args) {
System.out.println(UseStatusEnum.PACKING_NOT_USE.getStr());
}
}
結果
Disconnected from the target VM, address: '127.0.0.1:57131', transport: 'socket'
11
Process finished with exit code 0
(8)包裝類
查看基礎數據類型
(9)反射
我以前文章
http://www.rzrgm.cn/imfjj/p/8075496.html
(10)動態代理
http://www.rzrgm.cn/imfjj/p/11603135.html
(11)序列化
public class MySerial implements Serializable {
private static final long serialVersionUID = 1L;
String name="imfjj";
byte age=18;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte getAge() {
return age;
}
public void setAge(byte age) {
this.age = age;
}
public static void main(String[] args) {
try {
ObjectOutputStream o=new ObjectOutputStream(new FileOutputStream("mySerial.out"));
MySerial mySerial=new MySerial();
o.writeObject(mySerial);
o.flush();
o.close();
} catch (IOException e) {
e.printStackTrace();
}
deserialize();
}
private static void deserialize(){
ObjectInputStream objectInputStream = null;
try {
objectInputStream =new ObjectInputStream(new FileInputStream("mySerial.out"));
} catch (IOException e) {
e.printStackTrace();
}
try {
MySerial mySerial = (MySerial) objectInputStream.readObject();
System.out.println(mySerial.getAge());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
結果:
Connected to the target VM, address: '127.0.0.1:58620', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:58620', transport: 'socket'
18
Process finished with exit code 0
假如改動
byte age=18;改動為
transient byte age=18;
輸出則為 0;
(12)注解
http://www.rzrgm.cn/imfjj/p/9890061.html
(13)泛型
參照:概念性的描述http://www.rzrgm.cn/wyb666/p/10349178.html
<T>T 和T 的區別http://www.rzrgm.cn/jpfss/p/9929108.html
https://blog.csdn.net/weixin_52772307/article/details/126868855
補充:T相對于<T>T是調用前就限制了類型了,而<T>T還沒有限制死,調用的時候用哪個類型,就返回哪個T
(14)SPI
SPI就是java設計了
SPI全稱Service Provider Interface,是Java提供的一套用來被第三方實現或者擴展的接口,它可以用來啟用框架擴展和替換組件。 SPI的作用就是為這些被擴展的API尋找服務實現。
參考:
http://www.rzrgm.cn/jy107600/p/11464985.html
https://blog.csdn.net/codingtu/article/details/79004657
(15)異常
一種可捕獲Exception,錯誤為Error,例如StackOverFlow OMM

(16)IO流
分為字節流和字符流,具體看我以往文章
http://www.rzrgm.cn/imfjj/p/10972199.html
(17)補充反編譯
字符串反編譯命令:寫了一個Test.java
public class Test {
public static void main(String[] args) {
String a="hello";
}
}
使用指令 javac Test.java & javap -c Test
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String hello
2: astore_1
3: return
}
idc代表存進字符串常量池,hello寫進去了
浙公網安備 33010602011771號