企業(yè)基礎(chǔ)知識點匯總
面向?qū)ο?/span>
面向?qū)ο笕筇卣?/span>

String,StringBuilder,StringBuffer

簡要的說, String 類型和 StringBuffer 類型的主要性能區(qū)別其實在于 String 是不可變的對象, 因此在每次對 String 類型進行改變的時候其實都等同于生成了一個新的 String 對象,然后將指針指向新的 String 對象,這樣不僅效率低下,而且大量浪費有限的內(nèi)存空間,所以經(jīng)常改變內(nèi)容的字符串最好不要用 String
String:字符串常量
StringBuffer:字符串變量;線程安全的
StringBuilder:字符串變量;線程非安全的
StringBuilder與StringBuffer二者的區(qū)別主要是在運行速度和線程安全這兩方面。
1、StringBuffer 與 StringBuilder 中的方法和功能完全是等價的
2、只是StringBuffer 中的方法大都采用了 synchronized 關(guān)鍵字進行修飾,因此是線程安全的,而 StringBuilder 沒有這個修飾,可以被認為是線程不安全的。
3、在單線程程序下,StringBuilder效率更快,因為它不需要加鎖,不具備多線程安全,而StringBuffer則每次都需要判斷鎖,效率相對更低。
三者使用的總結(jié):1.如果要操作少量的數(shù)據(jù)用 = String 2.單線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) = StringBuilder 3.多線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) = StringBuffer
重寫與重載
重寫(override)
遵循運行期綁定
什么時候使用重寫?
1、當(dāng)父類方法無法滿足子類需求,此時可以在子類中重寫父類方法
2、如果開發(fā)時,需要對父類方法功能拓展,此時還不想修改父類程序則使用繼承(定義一個類繼承父類),然后通過子類重寫該方法,然后其他類進行調(diào)用這個子類方法;
兩同兩小一大方法名相同,參數(shù)列表相同。派生類方法的返回值必須小于等于超類的派生類方法拋出的異常小于或等于超類的派生類方法的訪問權(quán)限大于或等于超類的
重載(overload)
發(fā)生在一個類中,方法名相同,參數(shù)列表不同,方法體不同
遵循 “編譯期綁定”,看參數(shù)/引用類型來綁定方法
this和super
this指代當(dāng)前對象,哪個對象調(diào)用方法,它就指向哪個對象this.成員變量名————訪問成員變量this.方法名()————調(diào)用方法this()————調(diào)用構(gòu)造方法
super指代當(dāng)前對象的超類對象super.成員變量名————訪問超類的成員變量super.方法名————調(diào)用超類的方法super()————調(diào)用超類的構(gòu)造方法
靜態(tài)Static
static 聲明方法為靜態(tài)方法(靜態(tài)方法只能訪問靜態(tài)成員。(非靜態(tài)既可以訪問靜態(tài),又可以訪問非靜態(tài))),聲明屬性為靜態(tài)屬性;
static 關(guān)鍵詞:1、static 修飾方法,該方法叫做靜態(tài)方法(也叫做類方法),可直接通過這個類的類名打點直接調(diào)用;2、靜態(tài)方法中不能使用this/super關(guān)鍵詞,靜態(tài)方法不能直接調(diào)用當(dāng)前類中的非靜態(tài)方法(或非靜態(tài)屬性),必須通過new實例化后在調(diào)用。3、static聲明的方法和屬性,該對象已經(jīng)被實例化,且只能被實例化一次(單例模式)4、static修飾的屬性,被相同類的不同實例所共享;
如果某個成員變量時被所有對象所共享的,那么這個成員變量就可以定義為靜態(tài)變量。
流程控制語句
break 跳出上一層循環(huán),不再執(zhí)行循環(huán)(結(jié)束當(dāng)前的循環(huán)體)
continue 跳出本次循環(huán),繼續(xù)執(zhí)行下次循環(huán)
return 程序返回,不再執(zhí)行下面的代碼(結(jié)束當(dāng)前方法,直接返回)
類與接口
抽象類和接口的對比
抽象類是用來捕捉子類的通用特性。接口是抽象方法的集合。
從設(shè)計層面來說,抽象類是對類的抽象,是一種模板設(shè)計,接口是行為的抽象,是一種行為的規(guī)范
相同點
接口和抽象類都不能實例化
都位于繼承的頂端,用于被其他類實現(xiàn)或繼承
都包含抽象方法,其子類都必須重寫這些抽象方法
不同點

構(gòu)造方法
概述:構(gòu)造方法存在于類中,給對象數(shù)據(jù)(屬性)初始化;
特點:方法名與類名一樣;無返回值無void;
默認構(gòu)造方法:我們不創(chuàng)建一個構(gòu)造方法時,系統(tǒng)默認提供一個無參構(gòu)造;當(dāng)我們創(chuàng)建一個構(gòu)造方法時,系統(tǒng)不再提供無參構(gòu)造,所以在實際項目中,全部手動給出無參構(gòu)造
主要作用是完成對類對象的初始化工作。
內(nèi)部類
將一個類的定義放在另外一個類的定義內(nèi)部,這就是內(nèi)部類。內(nèi)部類本身就是類的一個屬性,與其他屬性定義方式一致。
內(nèi)部類四種:
成員內(nèi)部類定義在類內(nèi)部,成員位置上的非靜態(tài)??梢栽L問外部類所有的變量和方法,包括靜態(tài)和非靜態(tài),私有和共有。成員內(nèi)部類依賴外部類的實例
局部內(nèi)部類定義在方法中的內(nèi)部類,就是局部內(nèi)部類
匿名內(nèi)部類沒有名字的內(nèi)部類必須繼承一個抽象類或者實現(xiàn)一個接口不能定義任何靜態(tài)成員和靜態(tài)方法當(dāng)所在的方法的形參需要被匿名內(nèi)部類使用時,必須聲明為final匿名內(nèi)部類不能是抽象的,它必須實現(xiàn)繼承的類或?qū)崿F(xiàn)的接口所有抽象方法
靜態(tài)內(nèi)部類定義在類內(nèi)部的靜態(tài)類,可以訪問外部類所有的靜態(tài)變量,而不可訪問外部類的非靜態(tài)變量。
優(yōu)點:
一個內(nèi)部對象可以訪問創(chuàng)建它的外部類對象的內(nèi)容
內(nèi)部類不為同一包的其他類所見,有很好的封裝性
內(nèi)部類有效實現(xiàn)了多繼承。
匿名內(nèi)部類可以很方便的定義回調(diào)
異常
1.Throwable是Java語言中所有錯誤與異常的超類
包含兩個子類:Error和Exception
2.Error(錯誤):非代碼性錯誤,運行應(yīng)用程序的錯誤
3.Exception(異常):程序本身可以捕獲并且可以處理的異常
運行時異常:RuntimeException
ClassCastException(類轉(zhuǎn)換異常)
IndexOutOfBoundsException(數(shù)組越界)
NullPointerException(空指針)
編譯時異常:ClassNotFoundException,IOException
異常處理:throw拋出,try-catch捕獲
throws在方法上聲明要拋出的異常
throw在方法內(nèi)部拋出異常對象
內(nèi)存管理
1.堆
存儲new出來的對象(包括實例變量)
2.棧
存儲正在調(diào)用的方法中的所有局部變量(包括方法的參數(shù))
調(diào)用方法時會在棧中為該方法分配一塊對應(yīng)的棧幀,棧幀中存儲方法中的局部變量(包括參數(shù)),方法調(diào)用結(jié)束,棧幀自動被清楚,局部變量(參數(shù))一并被清楚
3.方法區(qū)
存儲.class字節(jié)碼文件(包括靜態(tài)變量,方法)
方法只有一份,通過this來區(qū)分具體的調(diào)用對象
集合
集合框架
java.util.Collection接口,該接口是所有集合的頂級接口
里面規(guī)定了所有集合都要具備的功能。
集合與數(shù)組一樣,用來保存一組元素,但是集合有多種不同的數(shù)據(jù)
結(jié)構(gòu),和各自的特點
1.集合與數(shù)組的區(qū)別
長度區(qū)別:數(shù)組是固定長度,集合時可變長度。
內(nèi)容區(qū)別:數(shù)組可以是基本類型,也可以是引用類型。 集合只能是引用類型
元素內(nèi)容:數(shù)組只能存儲同一種類,集合可以存儲不同類型(其實集合一般存儲的也是同一種類型)
2.集合的方法
Boolean add(E e)在集合末尾添加元素
Boolean remove(Object o)若本類集合中有值與o的值相等的元素,則刪除該元素,并返回true
void clear() 清除本集合中所有元素,調(diào)用該方法后本集合將為空
boolean contains(Object o)判斷集合中是否包含某元素
boolean isEmpty()判斷集合是否為空
int size()返回集合中元素個數(shù)
boolean addAll(Collection c)將一個集合c中的所有元素添加到另一個集合
Object[ ]toArray()返回一個包含了本集合中所有元素的數(shù)組,數(shù)組類型為Object
數(shù)組轉(zhuǎn)List:使用Arrays.asList(array)進行轉(zhuǎn)換
Interator iterator()迭代器,集合專用遍歷方式
sort java.util.Collection提供了一個靜態(tài)方法sort,可以對List集合進行自然排序(從小到大)
3.常用集合的分類
Connection接口:
一.List 有序,可重復(fù)
ArrayList優(yōu)點:底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢缺點:線程不安全,效率高
Linkedlist優(yōu)點:底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快缺點:線程安全,效率低
二.Set 無序,唯一
HashSet底層數(shù)據(jù)結(jié)構(gòu)是哈希表(無序,唯一)依賴hashCode()和equals()來保證元素唯一性
TreeSet底層數(shù)據(jù)結(jié)構(gòu)是紅黑樹。(唯一,有序)通過自然排序,比較器排序根據(jù)比較的返回值是否為0來決定元素唯一性
Map接口:
HashMap: JDK1.8之前HashMap由數(shù)組+鏈表組成的,數(shù)組是HashMap的主體,鏈表則是主要為了解決哈希沖突而存在的(“拉鏈法”解決沖突).JDK1.8以后在解決哈希沖突時有了較大的變化,當(dāng)鏈表長度大于閾值(默認為8)時,將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時間
LinkedHashMap:LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈?zhǔn)缴⒘薪Y(jié)構(gòu)即由數(shù)組和鏈表或紅黑樹組成。另外,LinkedHashMap 在上面結(jié)構(gòu)的基礎(chǔ)上,增加了一條雙向鏈表,使得上面的結(jié)構(gòu)可以保持鍵值對的插入順序。同時通過對鏈表進行相應(yīng)的操作,實現(xiàn)了訪問順序相關(guān)邏輯。
HashTable: 數(shù)組+鏈表組成的,數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的
TreeMap: 紅黑樹(自平衡的排序二叉樹)
Queue接口 隊列
offer入隊操作,元素會添加到隊列末尾
poll出隊操作,獲取隊首元素并將其從隊列中刪除
peek是引用隊首元素,獲取后元素仍在隊列中Deque接口,雙端隊列
Deque繼承自Queue,雙端隊列的特點是隊列兩端都可以做
出入對的操作 offerFirst和offerLast
棧
棧是經(jīng)典的數(shù)據(jù)結(jié)構(gòu)之一,可以保存一組元素,但是存取元素必須
遵循先進后出原則。
一般使用棧來實現(xiàn)“后退”這樣的功能 方法push
迭代器Iterator
Iterator接口提供遍歷任何Collection的接口。迭代器允許在迭代過程中移出元素
二.List和Set集合詳解
1.List和Set的區(qū)別
有序性
List保證按插入順序排序
Set存儲和取出順序不一致
唯一性
List可以重復(fù)
Set元素唯一
獲取元素
List可以通過索引直接操作元素
Set不能根據(jù)索引獲取元素
2.List
(1)ArrayList:底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢,線程不安全,效率高,可以存儲重復(fù)元素(2)LinkedList 底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快,線程不安全,效率高,可以存儲重復(fù)元素
3.Set
(1)HashSet底層數(shù)據(jù)結(jié)構(gòu)采用哈希表實現(xiàn),元素?zé)o序且唯一,線程不安全,效率高,可以存儲null元素,元素的唯一性是靠所存儲元素類型是否重寫hashCode()和equals()方法來保證的,如果沒有重寫這兩個方法,則無法保證元素的唯一性。
(2)LinkedHashSet底層數(shù)據(jù)結(jié)構(gòu)采用鏈表和哈希表共同實現(xiàn),鏈表保證了元素的順序與存儲順序一致,哈希表保證了元素的唯一性。線程不安全,效率高。
(3)TreeSet底層數(shù)據(jù)結(jié)構(gòu)采用二叉樹來實現(xiàn),元素唯一且已經(jīng)排好序;唯一性同樣需要重寫hashCode和equals()方法,二叉樹結(jié)構(gòu)保證了元素的有序性。
(4)小結(jié):Set具有與Collection完全一樣的接口,因此沒有任何額外的功能,不像前面有兩個不同的List。實際上Set就是Collection,只 是行為不同。(這是繼承與多態(tài)思想的典型應(yīng)用:表現(xiàn)不同的行為。)Set不保存重復(fù)的元素。Set 存入Set的每個元素都必須是唯一的,因為Set不保存重復(fù)元素。加入Set的元素必須定義equals()方法以確保對象的唯一性。Set與Collection有完全一樣的接口。Set接口不保證維護元素的次序。
4.List和Set總結(jié)
(1)、List,Set都是繼承自Collection接口,Map則不是(2)、List特點:元素有放入順序,元素可重復(fù) ,Set特點:元素?zé)o放入順序,元素不可重復(fù),重復(fù)元素會覆蓋掉,(注意:元素雖然無放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實是固定的,加入Set 的Object必須定義equals()方法 ,另外list支持for循環(huán),也就是通過下標(biāo)來遍歷,也可以用迭代器,但是set只能用迭代,因為他無序,無法用下標(biāo)來取得想要的值。)(3).Set和List對比:Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。List:和數(shù)組類似,List可以動態(tài)增長,查找元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變。(4)、ArrayList與LinkedList的區(qū)別和適用場景Arraylist:優(yōu)點:ArrayList是實現(xiàn)了基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),因為地址連續(xù),一旦數(shù)據(jù)存儲好了,查詢操作效率會比較高(在內(nèi)存里是連著放的)。缺點:因為地址連續(xù), ArrayList要移動數(shù)據(jù),所以插入和刪除操作效率比較低。
LinkedList:優(yōu)點:LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu),地址是任意的,所以在開辟內(nèi)存空間的時候不需要等一個連續(xù)的地址,對于新增和刪除操作add和remove,LinedList比較占優(yōu)勢。LinkedList 適用于要頭尾操作或插入指定位置的場景缺點:因為LinkedList要移動指針,所以查詢操作性能比較低。適用場景分析:當(dāng)需要對數(shù)據(jù)進行對此訪問的情況下選用ArrayList,當(dāng)需要對數(shù)據(jù)進行多次增加刪除修改時采用LinkedList。
三.Map詳解
Map用于保存具有映射關(guān)系的數(shù)據(jù),Map里保存著兩組數(shù)據(jù):key和value,它們都可以使任何引用類型的數(shù)據(jù),但key不能重復(fù)。所以通過指定的key就可以取出對應(yīng)的value。
java.util.Map 接口 查找表
Map體現(xiàn)的樣子是一個多行兩列的表格,其中左列稱為Key
右列稱為Value。 map總是成對的保存數(shù)據(jù),并且總是根據(jù)
key去獲取對應(yīng)的value。因此保存數(shù)據(jù)時,我們經(jīng)常將查詢
的條件作為key,查詢的結(jié)果作為value保存到Map中方便提取
數(shù)據(jù)。
Map中的key是不允許重復(fù)的(equsls判斷)
Map的常用實現(xiàn)類:
java.util.HashMap:散列表,使用散列算法實現(xiàn)的Map,
當(dāng)今查詢速度最快的數(shù)據(jù)結(jié)構(gòu)。
TreeMap:二叉樹實現(xiàn)的Map
(1)、請注意!??!, Map 沒有繼承 Collection 接口, Map 提供 key 到 value 的映射,你可以通過“鍵”查找“值”。一個 Map 中不能包含相同的 key ,每個 key 只能映射一個 value 。 Map 接口提供 3 種集合的視圖, Map 的內(nèi)容可以被當(dāng)作一組 key 集合,一組 value 集合,或者一組 key-value 映射。
(2)Map:
(3)HashMap和HashTable的比較:
(4)TreeMap:
適用場景分析:HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap允許空鍵值,而HashTable不允許。
HashMap:適用于Map中插入、刪除和定位元素。Treemap:適用于按自然順序或自定義順序遍歷鍵(key)。
5.線程安全集合類與非線程安全集合類LinkedList、ArrayList、HashSet是非線程安全的,Vector是線程安全的;HashMap是非線程安全的,HashTable是線程安全的;StringBuilder是非線程安全的,StringBuffer是線程安全的。
數(shù)據(jù)結(jié)構(gòu)ArrayXxx:底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢LinkedXxx:底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快HashXxx:底層數(shù)據(jù)結(jié)構(gòu)是哈希表。依賴兩個方法:hashCode()和equals()TreeXxx:底層數(shù)據(jù)結(jié)構(gòu)是二叉樹。兩種方式排序:自然排序和比較器排序
進程與線程
什么是進程
進程是操作系統(tǒng)中運行的一個任務(wù)(一個應(yīng)用程序運行在一個進程中)。
進程是一塊包含了某些資源的內(nèi)存區(qū)域。操作系統(tǒng)利用進程把它的工作劃分為一些功能單元。
進程中所保護的一個或多個執(zhí)行單元稱為線程。
線程只能歸屬一個進程,并且他只能訪問該進程所擁有的資源。當(dāng)操作系統(tǒng)創(chuàng)建一個進程后,該進程會自動申請一個名為主線程或首要線程的線程。
什么是線程
一個線程是進程的一個順序執(zhí)行流
同類的多個線程共享一塊內(nèi)存空間或一組系統(tǒng)資源,線程本身有一個供程序執(zhí)行的堆棧。線程在切換時負荷小,因此,線程也被稱為輕負荷進程。一個進程中可以包含多個線程。
進程與線程的區(qū)別
一個進程至少有一個線程。線程的劃分尺度小于進程,使得多線程程序的并發(fā)性高。另外,進程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享內(nèi)存,從而極大的提高了程序的運行效率。線程在執(zhí)行過程中與進程的區(qū)別在于每個獨立的線程有一個程序運行的入口,順序執(zhí)行序列和程序的出口。但是線程不能夠獨立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制。
線程使用的場合
線程通常用于在一個程序中,需要同時完成多個任務(wù)的情況。我們可以將每個任務(wù)定義為一個線程,使他們得以一同工作。
也可以用于在單一線程中可以完成,但是使用多線程可以更快的情況。比如下載文件。
并發(fā)原理
多個線程"同時"運行只是我們感官上的一種表現(xiàn)。事實上線程是并發(fā)運行的,OS將時間劃分為很多時間片段(時間片),盡可能均勻分配給每一個線程,獲取時間片段的線程被CPU運行,而其他線程全部等待。所以微觀上是走走停停的,宏觀上都在運行。這種現(xiàn)象叫并發(fā),但不是絕對意義上的”同時發(fā)生“。
創(chuàng)建線程
繼承Thread并重寫run方法
Thread類是線程類,其每一個實例表示一個可以并發(fā)運行的線程。我們可以通過繼承該類并重寫run方法來定義一個具體的線程。其中重寫run方法的目的是定義該線程要執(zhí)行的邏輯。啟動線程時調(diào)用start()方法而非直接調(diào)用run()方法。start()方法會將當(dāng)前線程納入線程調(diào)度,使當(dāng)前線程可以開始并發(fā)運行。當(dāng)線程獲取時間片段后,會自動開始執(zhí)行run方法中的邏輯。
實現(xiàn)Runnable接口單獨定義線程任務(wù)
實現(xiàn)Runnable接口并重寫run方法來定義線程體,然后在創(chuàng)建線程的時候?qū)unnable的實例傳入并啟動線程。
第二種創(chuàng)建的好處在于可以將線程與線程要執(zhí)行的任務(wù)分離開,減少耦合,同時java是單繼承的,定義一個類實現(xiàn)Runnable接口的做法,可以更好的去實現(xiàn)其他父類或接口。
獲取線程信息
long getID():返回該線程的標(biāo)識符
String getName():返回該線程的名稱
int getPriority():返回線程的優(yōu)先級
Thread.state.getState():獲取線程的狀態(tài)
boolean isAlive():測試線程是否處于活動狀態(tài)
boolean isDaemon():測試線程是否為守護線程
boolean isInterrupted():測試線程是否已經(jīng)中斷
線程的優(yōu)先級
線程的切換是由線程調(diào)度控制的,我們無法通過代碼來干涉,但是可以通過線程的優(yōu)先級來最大程度的改善線程獲取時間片的幾率。
線程的優(yōu)先級為10級,1-10,其中1最低,10最高。線程提供了3個常量來表示最低,最高,以及默認優(yōu)先級:Thread.MIN_PRIORITY,Thread.MAX_PRIORITY,Thread.NROM_PRIORITY,void setPriority(int priority):設(shè)置線程的優(yōu)先級
守護線程
sleep方法
Thread的靜態(tài)方法sleep 用于使當(dāng)前線程進入阻塞狀態(tài):static void sleep(long ms)
該方法會使當(dāng)前線程進入阻塞狀態(tài)指定毫秒,當(dāng)阻塞指定毫秒后,當(dāng)前線程會重新進入Runnable狀態(tài),等待分配時間片。
該方法聲明會拋出一個InterruptException。所以在使用該方法時,需要捕獲這個異常。
yield()
Thread的靜態(tài)方法yield:static void yield()
該方法用于使當(dāng)前線程主動讓出當(dāng)次CPU時間片回到Runnable狀態(tài),等待分配時間片
join方法
void join()
該方法用于等待當(dāng)前線程結(jié)束。聲明拋出InterruptException。
線程同步
synchronized關(guān)鍵字
多個線程并發(fā)讀寫同一個臨界資源時,會發(fā)生"線程并發(fā)安全問題"。
常見的臨界資源:多線程共享實例變量,多線程共享靜態(tài)公共變量。
解決方法,需要將異步操作,變?yōu)橥讲僮鳌?/span>
異步操作:多線程并發(fā)的操作,相當(dāng)于各干各的。
同步操作:有先后順序的操作,相當(dāng)于你干完我再干
synchronized是java中的同步鎖
鎖機制
/*
* 線程池
* 線程池是管理線程的機制,主要解決兩個問題:
* 1:控制線程數(shù)量:線程數(shù)量過多會占用更多系統(tǒng)資源并可能出現(xiàn)
* CPU過度切換,造成并發(fā)性性能降低和內(nèi)存溢出等風(fēng)險
* 2:重用線程:頻繁的創(chuàng)建和銷毀線程會給線程調(diào)度帶來額外的
* 開銷,因此應(yīng)當(dāng)延長線程的生命周期。
*
*/
public class ThreadPoolDemo {
? ?public static void main(String[] args) {
? ? ? ?//創(chuàng)建一個固定大小的線程池,這里容量是2.
? ? ? ?ExecutorService threadPool
? ? ? ? ? ? ? ?=Executors.newFixedThreadPool(2);
? ? ? ?for(int i=0;i<5;i++) {
? ? ? ? ? ?Runnable r=new Runnable() {
? ? ? ? ? ? ? ?public void run() {
? ? ? ? ? ? ? ? ? ?try {
? ? ? ? ? ? ? ? ? ? ? ?Thread t=Thread.currentThread();
? ? ? ? ? ? ? ? ? ? ? ?System.out.println(t+"正在執(zhí)行一個任務(wù)...");
? ? ? ? ? ? ? ? ? ? ? ?Thread.sleep(3000);
? ? ? ? ? ? ? ? ? ? ? ?System.out.println(t+"執(zhí)行任務(wù)完畢!");
? ? ? ? ? ? ? ? ? ?} catch (Exception e) {
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?}
? ? ? ? ? ?};
? ? ? ? ? ?threadPool.execute(r);
? ? ? ? ? ?System.out.println("交給線程池一個任務(wù)...");
? ? ? ?}
? ? ? ?System.out.println("結(jié)束線程池");
? ? ? ?threadPool.shutdown();
? ? ? ?//立刻停止線程池
? ? ? ?//threadPool.shutdownNow();
? ?}
反射
JAVA反射機制是在運行狀態(tài)中,對任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息,調(diào)用對象的方法的功能,稱為反射。
反射就是把java類中的各種成分映射成一個個的Java對象
/*
* java反射機制
*
* 反射是一種動態(tài)機制,允許我們實例化對象,調(diào)用方法,操作
* 屬性從編碼期間確定,轉(zhuǎn)移到程序運行期確定。
* 因此反射提高了程序的靈活度,但是隨之帶來的是更多的系統(tǒng)開銷
* 和較慢的運行效率。因此反射機制不能過度的使用。
*/
public class ReflectDemo1 {
? ?public static void main(String[] args) {
? ? ? ?/*
? ? ? ? * 反射的第一步,獲取要利用反射操作的類的類對象
? ? ? ? * Class類的實例
? ? ? ? * JVM中每個被加載的類都有且只有一個Class的實例
? ? ? ? * 與之對應(yīng),通過類對象(Class的實例)我們可以得知
? ? ? ? * 其表示的類的一切信息,例如:類名,有哪些屬性,哪些
? ? ? ? * 方法,哪些構(gòu)造器等等。并利用這些在程序運行期間操作
? ? ? ? * 他們。
? ? ? ? *
? ? ? ? * 獲取一個類的類對象有三種方式:
? ? ? ? * 1.類名.class
? ? ? ? * ? ? 例如:
? ? ? ? * ? ? Class cls=String.class;
? ? ? ? * ? ? Class cls=int.class;
? ? ? ? *
? ? ? ? * 2.Class.forName(String className)
? ? ? ? * ? ? 例如:
? ? ? ? * ? ? Class cls=Class.forName("java.lang.String:);
? ? ? ? * ? ? 這里forName方法傳入的是類的完全限定名,格式為:包名.類名
? ? ? ? *
? ? ? ? * 3.使用對象的getClas()獲取
? ? ? ? ? ? ? Class cls=new Class();
? ? ? ? ? ? ? Class c=cls.getClass();
? ? ? ? */
? ? ? ?//優(yōu)點:簡單,直接 ?缺點:硬編碼獲取,不靈活
// Class cls=String.class;
// Class cls1=int.class;
? ? ? ?try {
? ? ? ? ? ?/*
? ? ? ? ? ? * java.util.ArrayList
? ? ? ? ? ? * java.util.HashMap
? ? ? ? ? ? * java.io.FileOutputStream
? ? ? ? ? ? */
? ? ? ? ? ?//cls = Class.forName("java.lang.String");
? ? ? ? ? ?Scanner sca=new Scanner(System.in);
? ? ? ? ? ?System.out.println("請輸入一個類名:");
? ? ? ? ? ?String className=sca.nextLine();
? ? ? ? ? ?Class cls=Class.forName(className);
? ? ? ? ? ?String name=cls.getName();
? ? ? ? ? ?System.out.println(name);
? ? ? ? ? ?//獲取String中所有公開方法
? ? ? ? ? ?//Method[]methods=cls.getMethods();
? ? ? ? ? ?/*
? ? ? ? ? ? * 獲取到本類自己定義的方法,包括私有方法
? ? ? ? ? ? */
? ? ? ? ? ?Method[]methods=cls.getDeclaredMethods();
? ? ? ? ? ?for(Method method:methods) {
? ? ? ? ? ? ? ?System.out.println(method.getName());
? ? ? ? ? ?}
? ? ? ?} catch (ClassNotFoundException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? ?}
? ?}
反射API
Java反射API提供了動態(tài)執(zhí)行能力
ClassAPI:
——java.long.Class類,用于加載類和獲取類的相關(guān)信息
Constructor:用來描述一個類的成員變量
Field:用來描述一個類的方法
Method:用來描述一個類的方法
Modifier:用來描述類內(nèi)各元素的修飾符
動態(tài)加載類
Class.forName():
Class cls=Class.forName(類名)
1.類名是運行期間動態(tài)輸入的類名,可以是任何類名
2.返回值是一個引用,利用這個引用指向的對象可以訪問方法區(qū)中的類信息
3.如果類名是錯誤的將出現(xiàn)“類沒有找到”的異常
動態(tài)創(chuàng)建對象
newInstance()
Object newInstance()
1.newInstance方法將調(diào)用類信息中的無參構(gòu)造器創(chuàng)建對象,如果沒有無參構(gòu)造器,將拋出沒有方法的異常。
2.如果需要調(diào)用有參構(gòu)造器,可以利用Constructor API實現(xiàn)。
3.返回值引用動態(tài)創(chuàng)建的對象,因為可以是任何類型的對象,所有其類型為Object。
動態(tài)調(diào)用方法
動態(tài)發(fā)現(xiàn)方法
Method[]getDeclaredMethods()
1.Method代表方法信息,可以利用Method API獲取方法對詳細信息,如:方法名,返回值類型,參數(shù)類型列表
2.這個方法返回對數(shù)組代表當(dāng)前類中對全部方法信息,每個元素代表一個方法信息。
動態(tài)執(zhí)行方法
Object invoke(Object obj,Object...args)
IO流
IS與OS
InputStream是所有字節(jié)輸入流的父類,其定義了基礎(chǔ)的讀取方法
int read()
OutputStream是所有字節(jié)輸出流的父類,其定義了基礎(chǔ)的寫出方法
void write()
文件流
FileOutputStream是文件的字節(jié)輸出流,使用該流可以以字節(jié)為單位將數(shù)據(jù)寫入文件
FileOutputStream(File file)
FileInputStream是文件的字節(jié)輸入流,使用該流可以以字節(jié)為單位從文件中讀取數(shù)據(jù)。
read()和write(int d)方法
●FileInputStream 繼承自InpuStream,其提供了以字節(jié)為單位讀取文件數(shù)據(jù)的方法read
●int read()從此輸出流中讀取一個數(shù)據(jù)字節(jié),若返回-1則表示(End Of File)讀到了文件末尾int read(byte[]b)批量讀取
●FileOutputStream繼承自O(shè)utputStream,其提供了以字節(jié)為單位向文件寫數(shù)據(jù)的方法write
●void write(int d)
●void write(byte[]d) 批量寫入將指定字節(jié)寫入此文件輸出流。這里只寫給定的int 值的“低八位”。
緩沖流
BOS基本工作原理
●使用緩沖輸出流來一次批量寫出若干數(shù)據(jù)減少寫出次數(shù),來提高寫出效率
●BufferOutputStream緩沖輸出流內(nèi)部維護著一個緩沖區(qū),每當(dāng)向該流寫數(shù)據(jù)時,都會先將數(shù)據(jù)存入緩沖區(qū),當(dāng)緩沖區(qū)已滿時,緩沖流會將數(shù)據(jù)一次性全部寫出。
BOS的flush方法
●void flush() 清空緩沖區(qū),將緩沖區(qū)的數(shù)據(jù)強制寫出。
BIS基本工作原理
●通過提高一次讀取的字節(jié)數(shù)量減少讀寫次數(shù)來提高讀取的效率
●BufferInputStream是緩沖字節(jié)輸入流。其內(nèi)部維護著一個緩沖區(qū)(字節(jié)數(shù)組),使用該流在讀取一個字節(jié)時,該流會盡可能多的一次性讀取若干字節(jié)并存入緩沖區(qū),然后逐一的將字節(jié)返回,直到全部讀取完畢。
●BIS是一個處理流
對象流
●對象是存在于內(nèi)存中的。有時我們需要將對象保存到硬盤上,或者傳輸?shù)搅硪慌_機器。這時我們需要將對象轉(zhuǎn)換為一個字節(jié)序列,而這個過程就稱為對象序列化。相反,將字節(jié)序列轉(zhuǎn)換為對應(yīng)的對象,稱為對象的反序列化。
使用OOS實現(xiàn)對象序列化
●ObjectOutputStream是用來對對象進行序列化的輸出流
●void writeObject(Object o) 該方法可以將給定的對象轉(zhuǎn)換為一個字節(jié)序列后寫出。
使用OIS實現(xiàn)對象反序列化
●ObjectputStream是用來對對象進行反序列化的輸入流
●Object readObject() 該方法可以從流中讀取字節(jié)并轉(zhuǎn)換為對應(yīng)的對象。
transient關(guān)鍵字
●被該關(guān)鍵字修飾的屬性在序列化時,其值將被忽略
字符流原理
●Reader是字符輸入流的父類
●Write是字符輸出流的父類
●字符流是以字符(char)為單位讀寫數(shù)據(jù)的,一次處理一個Unicode。
●字符流的底層仍然是基本的字節(jié)流。
●字符流封裝了字符的編碼解碼算法。
Reader的常用方法:
int read():讀取一個字符,返回的int值"低16位"有效
int read(char[]chs):從該流中讀取一個字符數(shù)組的length個字符存入該數(shù)組,返回值為實際讀取的字符量
Write的常用方法:
void write
轉(zhuǎn)換流
字符轉(zhuǎn)換流原理
●InputStreamReader:字符輸入流使用該流可以設(shè)置字符集,并按照指定的字符集從流中按照編碼將字節(jié)數(shù)據(jù)轉(zhuǎn)換為字符并讀取。
●OutputStreamWrite:字符輸出流使用該流可以設(shè)置字符集,并按照指定的字符集將字符轉(zhuǎn)換為對應(yīng)字節(jié)后通過該流寫出。
PrintWriter
創(chuàng)建PW對象
●PrintWriter是具有自動行刷新的緩沖字符輸出流。其提供了比較豐富的構(gòu)造方法。
BufferedReader
構(gòu)建BufferedReader
●BufferedReader是緩沖字符輸入流,其內(nèi)部提供了緩沖區(qū),可以提供讀取效率
IO流總結(jié)
一、IO流的三種分類方式:
1.按照流向來分:輸入流:只能從中讀取字節(jié)數(shù)據(jù),不能向其寫出數(shù)據(jù)輸出流:只能向其寫入字節(jié)數(shù)據(jù),不能從中讀取數(shù)據(jù)2.按照流所處理的數(shù)據(jù)類型劃分:可分為:字節(jié)流:用于處理字節(jié)數(shù)據(jù)。字符流:用于處理Unicode字符數(shù)據(jù)。3.按照格式可以分為:節(jié)點流(低級流)可以從向一個特定的IO設(shè)備(如磁盤,網(wǎng)絡(luò))讀寫數(shù)據(jù)的流。處理流(高級流):可以對一個已存在的流的連接和封裝,通過所封裝的流的功能實現(xiàn)數(shù)據(jù)讀寫功能的流。
二.按操作方式分類
三.按照操作對象
WEB
1.web前端(學(xué)習(xí)如何開發(fā)網(wǎng)站頁面)
2.數(shù)據(jù)庫
3.Servlet
Web前端
1.HTML(如何搭建頁面結(jié)構(gòu)和內(nèi)容 類似于蓋房子 毛坯房)
2.CSS(美化頁面 類似裝修)
3.JavaScript(給頁面添加動態(tài)效果)
4.JQuery(JavaScript語言框架,簡化JavaScript代碼)
5.Bootstrap前端頁面的綜合框架,作用:讓前端頁面開發(fā)變得更高效
HTML
●Hyper Text Markup Language: 超文本標(biāo)記語言
●超文本:不僅僅是純文本,還包括字體相關(guān),以及多媒體內(nèi)容(圖片/音頻/視頻)
●XML也是標(biāo)記語言 , 區(qū)別就是 XML是可擴展標(biāo)記語言, HTML里面的標(biāo)簽是預(yù)設(shè)好的,學(xué)習(xí)HTML實際上就是學(xué)習(xí)有哪些HTML標(biāo)簽 以及標(biāo)簽和標(biāo)簽之間的關(guān)系
CSS
●Cascading Style Sheet: 層疊樣式表 , 作用: 美化頁面
●在html頁面中添加樣式代碼(引入方式),總共有三種方式:1.內(nèi)聯(lián)樣式:在標(biāo)簽的style屬性中添加樣式代碼,不能復(fù)用。2.內(nèi)部樣式:在head標(biāo)簽里面添加style,在標(biāo)簽體內(nèi)寫樣式代碼,僅可以在當(dāng)前頁面復(fù)用,不可以多頁面復(fù)用3.外部樣式:在單獨的css樣式文件中寫樣式代碼,在html頁面通過link標(biāo)簽引入,可以實現(xiàn)多頁面復(fù)用,并且可以將html代碼和css樣式代碼分離開
●三種引入方式的優(yōu)先級:內(nèi)聯(lián)優(yōu)先級最高,內(nèi)部和外部優(yōu)先級一樣,后執(zhí)行的覆蓋先執(zhí)行的。
CSS的三大特點
1.繼承性:元素可以繼承上級元素的文本和字體相關(guān)樣式,部分標(biāo)簽自帶效果不受繼承影響,比如:超鏈接的字體顏色,h1-h6字體大小不受繼承影響
2.層疊性:多個選擇器有可能選擇到同一個元素,如果添加的樣式不同則全部層疊生效,如果樣式相同則由優(yōu)先級決定哪個生效
3.優(yōu)先級:選擇器作用范圍越小優(yōu)先級越高。
JavaScript
作用:給頁面添加動態(tài)效果
語言特點:
●屬性腳本語言,不需要編譯直接執(zhí)行
●基于面向?qū)ο?span id="s0sssss00s" class="ne-viewer-b-filler">
●屬于弱類型語言強類型:int x=10;String name="張三";int y;弱類型:var x=10; var name="張三";
●安全性高:js語言只能訪問瀏覽器內(nèi)部的數(shù)據(jù),不能訪問瀏覽器以外的數(shù)據(jù)。
●交互性高:js語言可以直接嵌入到html頁面中,可以讓用戶脫離后端服務(wù)器只在前段頁面和頁面內(nèi)容進行交互。
在html頁面中引入JavaScript代碼
●內(nèi)聯(lián):在標(biāo)簽的事件屬性中添加js代碼,當(dāng)事件觸發(fā)時執(zhí)行事件:就是系統(tǒng)提供的一些特定時間點,點擊事件:就是元素被點擊時的時間點
●內(nèi)部:在html頁面中任意位置寫Script標(biāo)簽,在標(biāo)簽體內(nèi)寫js代碼
●外部:在單獨的js文件中寫js代碼,在HTML頁面中通過Script標(biāo)簽的src屬性引入,使用最多的。好處是可以多個頁面復(fù)用同一個文件,可以將html代碼和js代碼分離便于維護和升級。
JavaScript對象分類
1.內(nèi)置對象:number/string/boolean等
2.瀏覽器相關(guān)對象BOM:Browser Object Model 瀏覽器對象模型
3.頁面相關(guān)對象DOM: Document Object MOdel 文檔對象模型
JQuery框架
●作用:一個JavaScript框架,輕量級的JS庫,封裝了JS,CSS,DOM,提供了一致的,簡潔的API。js:var d=document.getElementById("id");jQuery:$("#id")
●引入方式:由于JQuery就是通過JavaScript語言所寫,框架本身就是一個js文件,所以和引入普通的js文件一樣通過Script標(biāo)簽的src屬性引入到HTML頁面即可。
●通過id獲取元素對象,此時獲取到的是jQuery對象和js對象不一樣 $("#id")
js對象和jq對象互相轉(zhuǎn)換
●js對象和jq對象不是一種對象,各自的方法不能混著調(diào)用1.js轉(zhuǎn)jq:var jq=$(js);2.jq轉(zhuǎn)js:var js=jq[0]; jq對象實際上就是一個數(shù)組,里面裝著js對象
BootStrap
●此框架是目前比較流行的前端框架,基于HTML/css/JavaScript/jQuery實現(xiàn), 由Twitter公司研發(fā), 框架作用: 提高前端頁面的開發(fā)效率
●工作原理: boostrap框架提供了n種常見的樣式(提前寫好了市面上常見的樣式代碼), 在開發(fā)頁面的時候如果需要使用框架中所提供的效果只需要給元素添加相應(yīng)的class,樣式會自動添加到元素上,文檔中提供了各種樣式對應(yīng)的class值.
響應(yīng)式布局
●響應(yīng)式布局就是不同的設(shè)備顯示不同的樣式
●媒體查詢:這是Bootstrap中實現(xiàn)響應(yīng)式布局的實現(xiàn)方式.、
MySql
數(shù)據(jù)庫分類
1.關(guān)系型數(shù)據(jù)庫:MySQL
●格式一致,都是表數(shù)據(jù)
2.非關(guān)系數(shù)據(jù)庫:Redis
●格式靈活,可以是key,value形式,文檔形式,圖片形式
事務(wù)的四大特性
事務(wù)是指對系統(tǒng)進行的一組操作,為了保證系統(tǒng)的完整性,事務(wù)需要具有ACID特性,具體如下:
●原子性:事務(wù)的最小執(zhí)行單位,不允許分割。事務(wù)的原子性確保動作要么全部完成,要么全都不完成。
●一致性:執(zhí)行事務(wù)前后,數(shù)據(jù)保持一致,多個事務(wù)對同一個數(shù)據(jù)讀取的結(jié)果是相同的;
●隔離性:并發(fā)訪問數(shù)據(jù)庫時,一個用戶的事務(wù)不被其他事務(wù)所干擾,各并發(fā)事務(wù)之間數(shù)據(jù)庫是獨立的
●持久性:一個事務(wù)被提交之后,它對數(shù)據(jù)庫中數(shù)據(jù)的改變是持久的,即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對其有任何影響。
SQL分類
●DDL : 數(shù)據(jù)定義語言, 負責(zé)數(shù)據(jù)庫和表相關(guān)的操作
●DML: 數(shù)據(jù)操作語言, 負責(zé)數(shù)據(jù)增刪改查
●DQL: 數(shù)據(jù)查詢語言, 只包括查詢
●TCL: 事務(wù)控制語言,處理事務(wù)相關(guān)
●DCL: 數(shù)據(jù)控制語言, 負責(zé)控制用戶權(quán)限相關(guān)
基礎(chǔ)語法
1.數(shù)據(jù)庫相關(guān)
●創(chuàng)建數(shù)據(jù)庫:格式: create database 數(shù)據(jù)庫名;
●查詢所有數(shù)據(jù)庫:show databases;
●查看數(shù)據(jù)庫詳情:show create database 數(shù)據(jù)庫名;
●刪除數(shù)據(jù)庫:drop database 數(shù)據(jù)庫名;
●使用數(shù)據(jù)庫:use 數(shù)據(jù)庫名;
2.表相關(guān)
●創(chuàng)建表:created table 表名(字段1名 類型,字段2名 類型);
●查詢所有表:show tables;
●查詢表詳情:show create table 表名;
●查詢表字段:desc 表名;
●刪除表:drop table 表名;
●修改表名:rename table 原名 to 新名;
●添加表字段:最后面添加 alter table 表名 add 字段名 類型; 最前面添加 alter table 表名 add 字段名 類型 first; 在某字段后添加 alter table 表名 add 字段名 類型 after 字段名;
●刪除表字段:alter table 表名 drop 字段名;
●修改表字段:alter table 表名 change 原名 新名 新類型;
3.DML數(shù)據(jù)操作語言(增刪查改)
●插入數(shù)據(jù)
全表插入格式: insert into 表名 values(值1,值2);
值的數(shù)量和順序必須和表字段數(shù)量和順序一致
insert into person values('Tom',18);
指定字段插入格式: insert into 表名(字段1名,字段2名) values(值1,值2);
值的數(shù)量和順序必須和指定的字段一致
insert into person (name) values('Jerry');
批量插入格式: insert into 表名 values(值1,值2),(值1,值2);
insert into person values('Lucy',20),('Lily',21);
insert into person(name) values('AAA'),('BBB');
插入中文問題
insert into person values('劉德華',20);
●查詢數(shù)據(jù):select 字段信息 from 表名 where條件;
●修改數(shù)據(jù):update 表名set字段1名=值,字段2名=值 where條件;
●刪除數(shù)據(jù):delete from 表名 where條件;
主鍵約束 primary key
●主鍵:表示數(shù)據(jù)唯一性的字段稱為主鍵
●主鍵約束:唯一且非空
●create table t1(id int primary key,name varchar(10));
主鍵約束+自增
●給字段添加自增后,賦值為null則觸發(fā)自增
●自增規(guī)則:從歷史最大值+1
●create table t2(id int primary key auto_increment,name varchar(10));
is null 和is not null
●如果查詢字段的值為null,是is null 不為null 則使用 is not null
去重distinct
●select distinct job from emp;
and和or
●and類似java中的&&,查詢多個條件同時滿足使用and
●or類似java中的||,查詢多個條件滿足一個即可使用or
in關(guān)鍵字
●當(dāng)查詢的某個字段的值為多個值的時候使用in關(guān)鍵字
●select ename,sal from emp where sal in(3000,5000,8000);
●select*from emp where sal not in (3000,5000);
between x and y 關(guān)鍵字
●當(dāng)查詢某個字段的值在兩者之間時使用
●select*from emp where sal between 2000 and 3000;
模糊查詢
●% :代表0或多個未知字符
●_ :代表1個未知字符
●舉例:
a以x開頭 x%
b以x結(jié)尾 %x
c包含x %x%
d第二個字符是x _x%
e倒數(shù)第三個字符是x %x__
f第二個是x最后一個是y _x%y
g查詢姓孫的員工信息select * from emp where ename like '孫%';
h查詢工作中包含銷售的員工姓名和工作select ename,job from emp where job like '%銷售%';
i查詢名字中以精結(jié)尾的員工姓名select ename from emp where ename like '%精';
j查詢工作名稱第二個字是序的員工姓名和工作名稱.select ename,job from emp where job like '_序%';
排序
●讓查詢結(jié)果按照某個字段升序或者降序排序
●格式:order by 字段名 asc(默認,升序)/desc(降序)
分頁查詢
●如果查詢數(shù)據(jù)只查詢滿足條件的一部分而不是全部的時候,使用limit分頁查詢
●格式:limit 跳過的條數(shù),請求的條數(shù)(每頁條數(shù))
1查詢所有員工中工資升序,只查詢前3條數(shù)據(jù)(請求第一頁數(shù)據(jù) 每頁3條)select * from emp order by sal limit 0,3;
2查詢所有員工中工資升序,查詢第三頁的3條數(shù)據(jù)(第三頁就是跳過去2頁 跳過去2*3條數(shù)據(jù))select * from emp order by sal limit 6,3;
3查詢員工表第四頁的2條數(shù)據(jù)select * from emp limit 6,2;
4查詢員工表中工資最高的員工信息select * from emp order by sal desc limit 0,1;
5查詢3號部門工資最低的員工信息select * from emp where deptno=3 order by sal limit 0,1;
別名
●給查詢的字段起一個別名
●select ename as '名字' from emp;
●select ename '名字' from emp;
●select ename 名字 from emp;
字段的數(shù)值計算
1查詢每個員工的姓名,工資和年終獎(年終獎=5*工資)select ename,sal,5*sal 年終獎 from emp;
2查詢每個員工的姓名,工資和漲薪5塊錢之后的工資select ename,sal,sal+5 from emp;
聚合函數(shù)
●聚合函數(shù)就是對查詢的多條數(shù)據(jù)進行統(tǒng)計查詢
●統(tǒng)計的方式:1.平均值 2.最大值 3.最小值 4.求和 5.計數(shù)
1平均值avg(字段名)
○查詢2號部門的平均工資select avg(sal) from emp where deptno=2;
○查詢程序員的平均工資select avg(sal) from emp where job='程序員';
2最大值max(字段名)
○查詢1號部門的最高工資select max(sal) from emp where deptno=1;
3最小值min(字段名)
○查詢有領(lǐng)導(dǎo)的員工中的最低工資select min(sal) from emp where mgr is not null;
4求和sum(字段名)
○查詢3號部門的工資總和select sum(sal) from emp where deptno=3;
5計數(shù)count(字段名) count(*)
○查詢3號部門的人數(shù)select count(*) from emp where deptno=3;
○查詢1號部門工資在2000到3000之間的員工人數(shù)select count(*) from emp where deptno=1 and sal between 2000 and 3000;
分組查詢
●分組查詢可以將某個字段相同數(shù)值的劃分為一組,以每組為單位進行統(tǒng)計查詢(聚合函數(shù))
●在需求中出現(xiàn)每個xxx或每種xxx時,以xxx作為分組的字段 group by 字段查詢每個部門的平均工資:select deptno,avg(sal)from emp group by deptno;
having
●where后面只能寫普通字段的條件,不能寫聚合函數(shù)的條件
●having:如果條件是聚合函數(shù)的條件使用having關(guān)鍵字,此關(guān)鍵字和分組查詢結(jié)合使用,寫在group by后面1.查詢每個部門的平均工資,只查詢平均工資大于2000的信息select deptno,avg(sal)from emp group by deptno having avg(sal)>2000;2.查詢每個部門的平均工資,只查詢工資在1000到3000之間的,并過濾掉平均工資低于2000的部門select deptno,avg(sal) from emp where sal between 1000 and 3000 group by deptno having avg(sal)>=2000;
各個關(guān)鍵字的位置
select 字段信息 from表名 where 普通字段條件 group by 分組字段 having 聚合函數(shù)條件
order by 排序字段 limit 跳過的條數(shù),請求的條數(shù);
子查詢(嵌套查詢)
●把一條SQL語句嵌入到另外一條SQL語句中,把查詢語句的結(jié)果作為另一條SQL查詢條件的值1.查詢工資高于1號部門平均工資的員工信息select avg(sal) from emp where deptno=1;select*from emp where sal>( select avg(sal) from emp where deptno=1);
關(guān)聯(lián)關(guān)系
創(chuàng)建表時,表與表之間存在的業(yè)務(wù)關(guān)系
●一對一:有AB兩張表,A表中一條數(shù)據(jù)對應(yīng)B表的一條數(shù)據(jù),同時B表的一條數(shù)據(jù)也對應(yīng)A表的一條數(shù)據(jù)
●一對多:有AB兩張表,A表中一條數(shù)據(jù)對應(yīng)B表的多條數(shù)據(jù),同時B表的一條數(shù)據(jù)也對應(yīng)A表的一條數(shù)據(jù)
●多對多:有AB兩張表,A表中一條數(shù)據(jù)對應(yīng)B表的多條數(shù)據(jù),同時B表的一條數(shù)據(jù)也對應(yīng)A表的多條數(shù)據(jù)
表與表之間建立關(guān)系
●通過一個單獨的字段建立關(guān)系,這種建立關(guān)系的字段稱為外鍵,外鍵的值通常指向另外一張表的主鍵值。
關(guān)聯(lián)查詢
●同時查詢多張表數(shù)據(jù)的查詢方式稱為關(guān)聯(lián)查詢
●關(guān)聯(lián)查詢的查詢方式:1.等值連接 2.內(nèi)連接 3.外連接
1.等值連接
●格式:select*from A,B where 關(guān)聯(lián)關(guān)系 and 其他條件;查詢工資高于2000的員工姓名和對應(yīng)的部門名select e.ename,d.dnamefrom emp e,dept dwhere e.deptno=d.deptno and e.sal>2000;
2.內(nèi)連接
●內(nèi)連接和等值連接查詢到的結(jié)果試一樣的,都是查詢兩張表的交集數(shù)據(jù)
●內(nèi)連接格式:select*from A join B on 關(guān)聯(lián)關(guān)系 where 其他條件查詢工資高于2000的員工的姓名和對應(yīng)的部門名select e.ename,d.dnamefrom emp e join dept don e.deptno=d.deptnowhere e.deptno in(1,2);
3.外連接
●查詢一張表的全部數(shù)據(jù)和另外一張表的交集數(shù)據(jù)
●外連接分為左外連接和右外連接
●格式:select*from A left/right join B on 關(guān)聯(lián)關(guān)系 where 條件;查詢所有員工的姓名和對應(yīng)的部門名select e.name,d.dnamefrom emp e right join dept don e.deptno=d.deptno;
關(guān)聯(lián)查詢總結(jié)
如果查詢的是兩張表的交集數(shù)據(jù)則使用等值連接或內(nèi)連接(推薦),如果查詢的是一張表的全部數(shù)據(jù)和另外一張表的交集數(shù)據(jù)則使用外連接。
JDBC
●Java DataBase Connectivity:Java數(shù)據(jù)庫連接,
●學(xué)習(xí)JDBC主要學(xué)習(xí)的就是如何在Java代碼中執(zhí)行SQL語句
●JDBC實際上是Sun公司所提供的一套連接數(shù)據(jù)庫的API(應(yīng)用程序編程接口),JDBC接口中封裝了一堆和數(shù)據(jù)庫鏈接相關(guān)的抽象方法(只有方法聲明沒有方法實現(xiàn))
●JDBC定義一套標(biāo)準(zhǔn)接口,即訪問數(shù)據(jù)庫的通用API,不同的數(shù)據(jù)庫廠商根據(jù)各自數(shù)據(jù)庫特點去實現(xiàn)這些接口。
連接數(shù)據(jù)庫步驟
1.加載JDBC驅(qū)動程序
2.提供JDBC連接的URL
3.創(chuàng)建數(shù)據(jù)庫連接
4.創(chuàng)建一個Statement
5.執(zhí)行SQL語句
6.處理結(jié)果
7.關(guān)閉JDBC對象
Servlet
●Servlet是用于擴展web服務(wù)端軟件業(yè)務(wù)功能的組件,每一種業(yè)務(wù)都需要對應(yīng)的一個單獨的Servlet
Web服務(wù)軟件做了哪些事
1.負責(zé)建立底層的網(wǎng)絡(luò)連接
2.負責(zé)將客戶端請求的文件返回給客戶端
3.web服務(wù)器又稱為web容器,web容器負責(zé)裝組件(Servlet),web服務(wù)軟件通過解析請求路徑,找到對應(yīng)的Servlet做出響應(yīng)
Servlet生命周期
加載類(加載階段)--實例化階段(為對象分配空間)--初始化階段(為對象的屬性賦值)--請求處理(服務(wù)階段)--銷毀
Servlet響應(yīng)流程
●瀏覽器發(fā)出http://localhost:8080/servlet_1_1/HelloServlet請求,請求先有Tomcat攔截,并且獲取地址中的/HelloServlet,然后拿著此路徑去web.xml配置文件中找到對應(yīng)的Servlet的完整類名(cn.tedu.HelloServlet),找到完整類名后通過反射技術(shù),將該Servlet類實例化,然后Tomcat會調(diào)用Servlet的service方法.
瀏覽器發(fā)出請求的幾種方式
1、在瀏覽器地址欄輸入請求路徑發(fā)出請求 Get
2、在超鏈接中寫請求路徑,點擊超鏈接時發(fā)出請求 Get
3、通過頁面中的form表單發(fā)出請求 Get/Post
Get:當(dāng)瀏覽器地址欄/超鏈接/form表單指定get請求方式,這幾種方式發(fā)出的請求都是Get請求
●請求參數(shù)在請求地址的后面,不建議傳遞敏感數(shù)據(jù)(密碼)
●請求參數(shù)大小有限制,只能傳遞4k以內(nèi)的數(shù)據(jù)
Post:只有在form表單中添加了method=post發(fā)出的請求才是post請求
●請求參數(shù)在請求體里面(用戶不可見),相對get請求安全性更高
●請求參數(shù)沒有大小限制
一般情況都是使用Get請求,只有涉及敏感信息或上傳文件請求時,才是用Post請求
靜態(tài)頁面和動態(tài)頁面
●靜態(tài)頁面:任何客戶端,任何時間訪問頁面顯示的內(nèi)容都是一樣的,稱為靜態(tài)頁面
●動態(tài)頁面:顯示的內(nèi)容會受某些因素的影響而改變,動態(tài)頁面=從數(shù)據(jù)庫中查詢的數(shù)據(jù)+標(biāo)簽。
Thymeleaf框架作用
如果不使用此框架,我們服務(wù)器需要給客戶端返回動態(tài)頁面時,處理動態(tài)頁面的代碼需要全部寫在Servlet中,動態(tài)頁面部分包含很多頁面標(biāo)簽,如果把標(biāo)簽代碼寫在Servlet中,首先代碼書寫效率低,而且Servlet中的代碼量會暴增,不利于代碼的維護,使用Thymeleaf框架可以將動態(tài)頁面中的數(shù)據(jù)和頁面分離開,在html頁面中寫一個模板頁面,通過該框架可以將數(shù)據(jù)庫里面查詢到的數(shù)據(jù)和模板頁面整合到一起,整合到一起后再把數(shù)據(jù)返回給瀏覽器,最終目的就是將頁面相關(guān)代碼從Servlet中分離寫到單獨的html頁面中,提高開發(fā)效率,使Servlet類更易維護。
重定向
●寫法:response.sendRedirect(request.getContextPath()+"/ListServlet");
●作用:通知瀏覽器往指定的路徑發(fā)出請求
●執(zhí)行過程:當(dāng)執(zhí)行此代碼時,服務(wù)器會給瀏覽器返回一個302狀態(tài)碼和一個請求路徑,當(dāng)瀏覽器收到302狀態(tài)碼時,會立即向指定的路徑再次發(fā)出請求。
轉(zhuǎn)發(fā)和重定向的區(qū)別
轉(zhuǎn)發(fā)是服務(wù)器行為,重定向是客戶端行為。
●轉(zhuǎn)發(fā)(RequestDispatcher):一個請求,一個響應(yīng)1.轉(zhuǎn)發(fā)不會改變?yōu)g覽器的地址欄2.轉(zhuǎn)發(fā)共享一個request3.轉(zhuǎn)發(fā)只能在同一個web應(yīng)用中使用
●重定向(sendRedirect):兩個請求,兩個響應(yīng)1.重定向會改變?yōu)g覽器的地址欄2.重定向不共享request3.可以重定向到任何URL
Cookie和Session
●為什么要使用Session和Cookie瀏覽器和服務(wù)器之間進行數(shù)據(jù)傳輸遵循的時HTTP數(shù)據(jù)傳輸協(xié)議,此協(xié)議屬于無狀態(tài)協(xié)議(一次請求對應(yīng)一次響應(yīng),服務(wù)無法跟蹤客戶端的請求),通過cookie服務(wù)器可以給客戶端設(shè)置一個標(biāo)識,設(shè)置完之后客戶端每次發(fā)出請求都會帶著這個標(biāo)識,從而識別客戶端。但是Cookie是明文保存在客戶端瀏覽器中,可以被客戶端偽造造成完全隱患,這時Session的出現(xiàn)解決了此問題,Session是基于Cookie實現(xiàn),但是數(shù)據(jù)保存在了服務(wù)器端,這樣數(shù)據(jù)就不能像Cookie一樣被偽造,從而提高了安全性。
●作用:Cookie和Session都是為了實現(xiàn)多個Servlet之間的數(shù)據(jù)共享而存在的
●Cookie:數(shù)據(jù)保存在客戶端(瀏覽器),類似打孔式的會員卡1.保存時間:默認保存在瀏覽器內(nèi)存中,瀏覽器關(guān)閉則數(shù)據(jù)刪除,如果單獨設(shè)置了時間,數(shù)據(jù)則保存到磁盤中,時間到之后再刪除2.保存數(shù)據(jù)大?。好總€cookie數(shù)據(jù)不能超過4K,而且只能保存字符串?dāng)?shù)據(jù)3.應(yīng)用場景:需要長時間保存的數(shù)據(jù)使用cookie,如:記住用戶名和密碼
●Session:數(shù)據(jù)保存在服務(wù)器,類似銀行卡1.保存時間:默認為半個小時左右,這個時間可以修改但是不建議,因為Session數(shù)據(jù)保存在服務(wù)器,如果用戶量比較大非常占用服務(wù)器資源,Session只適合短時間的數(shù)據(jù)保存2.保存數(shù)據(jù)大?。簺]有大小限制,而且可以保存任意對象類型3.應(yīng)用場景:短時間的數(shù)據(jù)存儲和安全性要求高的數(shù)據(jù),如:記住登錄狀態(tài)
同步請求和異步請求
1.同步請求:從服務(wù)器返回的內(nèi)容包括html頁面+數(shù)據(jù),實現(xiàn)頁面整體刷新
2.異步請求:從服務(wù)器返回的內(nèi)容只有數(shù)據(jù),實現(xiàn)頁面局部刷新,異步請求通過Ajax發(fā)出
●前后端分離:整個網(wǎng)站都是使用的異步請求沒有同步請求,服務(wù)端程序員不需要關(guān)心請求是瀏覽器發(fā)出的還是各種客戶端發(fā)出的,不管是什么客戶端一視同仁只給客戶端返回數(shù)據(jù),客戶端接收到數(shù)據(jù)后自己處理顯示相關(guān)內(nèi)容,而目前通過Thymeleaf框架把數(shù)據(jù)和頁面整合一起返回給瀏覽器的做法,在前后端分離則不再使用
Ajax
●Ajax即"Asynchronous Javascript And XML"(異步 JavaScript 和 XML),是指一種創(chuàng)建交互式,快速動態(tài)網(wǎng)頁應(yīng)用的網(wǎng)頁開發(fā)技術(shù)。通過在后臺與服務(wù)器進行少量數(shù)據(jù)交換,Ajac可以使用網(wǎng)頁實現(xiàn)異步更新。在不不重新加載整個網(wǎng)頁的情況下,對網(wǎng)頁的某部分進行更新。
JSON
●輕量級數(shù)據(jù)封裝格式,類似于XML
Vue
●用于構(gòu)建用戶界面的漸進式框架。頻繁刷新頁面數(shù)據(jù)時使用。
●優(yōu)勢1.輕量級,運行高效2.易上手,文檔豐富3.不需要頻繁的操作dom元素,它本身都是虛擬dom跟數(shù)據(jù)進行捆綁,降低了性能消耗4.提供豐富的組件支持5.雙向數(shù)據(jù)綁定:變量的值改變影響頁面的顯示效果,頁面中的值改變會影響元素的值
●在頁面中引入vue.js框架文件即可使用
●主要應(yīng)用在異步請求,得到數(shù)據(jù)后把數(shù)據(jù)顯示在頁面中,作用和Thymeleaf類似,是把數(shù)據(jù)填充到頁面中,只不過Thymeleaf是服務(wù)端技術(shù),而vue是客戶端技術(shù)
Spring
1.Spring概述
Spring是個輕量級Java應(yīng)用的開源開發(fā)框架。使用Spring開發(fā)可以將Bean對象,Dao組件對象,Service組件對象等交給Spring容器來處理,有效降低代碼的耦合度,方便項目后期維護,升級,拓展。
缺點:Spring依賴反射,反射影響性能
2.Spring框架核心
●IOC控制反轉(zhuǎn):把創(chuàng)建對象的控制權(quán)交給Spring配置文件管理
●DI依賴注入:在需要對象時,由外部環(huán)境將依賴對象注入到組件中。
優(yōu)點就是把應(yīng)用的代碼量降到最低,達到松散耦合度
注入方式:1.構(gòu)造注入 2.Set注入 3.接口注入
3.AOP編程
面向切面,用于將那些與業(yè)務(wù)無關(guān),但是卻對多個對象產(chǎn)生影響的公共行為和邏輯,抽取并封裝為一個可重用的模塊。這個模塊就稱為切面。減少系統(tǒng)中的重復(fù)代碼,降低模塊間的耦合度,同時提高了系統(tǒng)的可維護性。
AOP實現(xiàn)關(guān)鍵在于代理模式,AOP主要分為靜態(tài)代理和動態(tài)代理。
4.Spring框架設(shè)計模式
●工廠模式:BeanFactory就是簡單工廠模式的體現(xiàn),用來創(chuàng)建對象的實例
●單例模式:Bean默認為單例模式
●代理模式:Spring AOP
●模板模式
5.BeanFactory和ApplicationContext
BeanFactory和ApplicationContext是Spring兩大核心接口,都可以當(dāng)做Spring的容器。其中A是B的子接口。
BeanFactory:采用的是延遲加載行駛來注入Bean,使用某個Bean時,才對Bean進行加載實例化。
ApplicationContext:在容器啟動時,一次性創(chuàng)建所有的Bean
6.Sping處理并發(fā)安全
采用ThreadLocal為每一個線程提供一個獨立的變量副本,從而隔離多個線程對數(shù)據(jù)訪問的沖突
@Configuration
Configuration是Spring提供的注解,標(biāo)注@Configuration注解的類是配置文件,告訴Spring在運行期間創(chuàng)建哪些對象
@Bean
告訴Spring啟動時候創(chuàng)建的具體的對象,返回值就是創(chuàng)建好的對象,這個對象是被Spring管理的對象,方法名是Bean的ID
getBeaan方法
●.getBean(DemoBean.class)按照類型獲取對象,如果在Spring中只有一個DemoBean類型的對象,就會按照類型匹配找到,如果按照類型沒有匹配到唯一的一個對象,就會報錯!
●.getBean("BeanID",DemoBean.class)重載的getBean方法根據(jù)Bean的ID查找對象,如果找到就返回對象,否則拋出異常!
組件掃描方式創(chuàng)建Bean對象
在類上使用注解,Spring啟動會自動根據(jù)注解創(chuàng)建Bean對象
●Component組件,在類上標(biāo)注,在Spring配置類上開啟組件掃描ComponentScan后,Spring會自動創(chuàng)建其類型的對象
●使用時候可以按照類型或者ID獲得對象
關(guān)于組件掃描,Spring提供了功能相同的一組注解,方便標(biāo)注不同功能的組件:
●@Component 標(biāo)注通用組件
●@Service 標(biāo)注業(yè)務(wù)層組件
●@Controller 標(biāo)注控制器組件
●@Repository 標(biāo)注持久層組件
Spring Bean對象的管理策略
單例:只有一個,立即初始化。類似冰箱,電視機,有家的時候立即買一個
原型:多個實例,按需要初始化,每次都是新的。類似吃西紅柿雞蛋
Bean對象的Scope(范圍):單列原型(多個實例)
對象懶惰初始化:懶惰(按需初始化)和非懶惰(立即初始化)
Spring默認的對象管理策略是:單例非懶惰方式,也就是在Spring啟動期間立即創(chuàng)建對象,并且在使用期間,始終使用同一個對象。
@Scope("prototype")開啟"原型范圍",會創(chuàng)建多個實例,每次調(diào)用getBean方法都會創(chuàng)建一個bean對象
@Lazy開啟懶惰初始化方式,單例時候,默認規(guī)則是Spring啟動時候,立即初始化。設(shè)置了@Lazy以后,就會在getBean時候初始化,如果不getBean,就不初始化
依賴注入
一個組件在運行期間需要使用另外一個組件,稱為依賴,將被依賴的組件賦值給使用方稱為依賴注入。
Spring在IoC的基礎(chǔ)之上,實現(xiàn)了DI,也就是在管理對象的基礎(chǔ)之上,可以按照依賴關(guān)系將對象適當(dāng)組裝(注入)
@Resource
●Spring根據(jù)Bean的ID和類型尋找合適Bean對象,如果找到ID一致,類型一樣的對象就注入;
●如果ID沒有匹配到就根據(jù)類型匹配唯一的Bean對象,如果匹配到就注入;
●如果ID,類型都沒有匹配到,就拋出異常
set方法注入
@Resource不僅支持屬性注入,還支持Set方法注入
●可以標(biāo)注在屬性上,對屬性進行注入
●可以標(biāo)注在setXXX方法,調(diào)用set方法注入屬性
提供更多靈活性,可以執(zhí)行Set方法中的邏輯算法,如果需Spring注入時候,執(zhí)行set方法中算法,就將@Resource標(biāo)注在set方法上,如果set方法中沒有邏輯算法,經(jīng)常標(biāo)注在屬性上。
@Autowired和@Resource
●@Resource是java提供的注解,Spring支持
●@Autowired Spring提供的注解
●這兩個注解功能基本相同
●@Resource:Spring 5推薦使用先尋找Bean ID相同的組件,如果找到再比較類型,匹配就注入如果沒有Bean ID匹配,則按照類型進行匹配,如果找到類型唯一的Bean,則注入,否則拋出異常
●@Autowired:Spring 5不推薦使用先尋找類型相同的唯一Bean組件,如果按照類型匹配到唯一的Bean組件就注入;如果按照類型匹配到多個Bean組件,則再按照Bean ID匹配ID,如果匹配上就注入,否則拋出異常
●這兩個注解都采用了盡可能匹配成功的策略進行匹配注入屬性
解耦
IoC/DI好處之一就是可以實現(xiàn)軟件組件的解耦
解耦:將緊密耦合關(guān)系,變化為可配置的松散耦合關(guān)系,稱為解耦
Spring MVC
MVC=Model(數(shù)據(jù)模型)+View(視圖)+Controller(控制器)
●M-Model模型的職責(zé)是負責(zé)業(yè)務(wù)邏輯。包含兩層:業(yè)務(wù)數(shù)據(jù)和業(yè)務(wù)處理邏輯。實體類,DAO,Service都屬于模型層
●V-View視圖的職責(zé)是負責(zé)顯示界面和用戶交互(收集用戶信息)
●C-Controller控制器是模型層M和視圖層V之間的橋梁,用于控制流程
概述
Spring MVC是一個輕量級的Web框架,通過模型-視圖-控制器分離,將web層進行解耦,簡化開發(fā)。
核心執(zhí)行流程
DispatcherServlet:前端控制器 用來處理所有HTTP請求和響應(yīng)
HandlerMapping:處理器映射器
Controller:控制器
ModelAndView
ViewServlet:視圖解析器
●瀏覽器發(fā)出請求,交給前端控制器DispatcherServlet處理
●控制器通過HandlerMapping找到相應(yīng)的Controller組件處理請求
●執(zhí)行Controller組件約定方法處理請求,約定方法調(diào)用模型組件完成業(yè)務(wù)處理,之后返回一個MondelAndView對象,封裝了處理結(jié)果數(shù)據(jù)和視圖名稱信息。
●控制器接收ModelAndView之后,調(diào)用ViewResolver組件,定位View并傳遞數(shù)據(jù)信息,生成響應(yīng)界面結(jié)果。
常用注解
●@RequestMapping:用于處理請求url映射的注解,可用于類或方法上
●@RequestBody:注解實現(xiàn)接收hhtp請求的json數(shù)據(jù),將json轉(zhuǎn)換為java對象
●ResponseBody:注解實現(xiàn)將Controller方法返回對象轉(zhuǎn)化為json對象響應(yīng)給客戶
MyBatis
概念
MyBatis是一個可以自定義SQL,存儲過程和高級映射的持久層框架。一個半ORM(對象關(guān)系映射)框架。
ORM(Object Relational Mapping)
對象關(guān)系映射,是一種為了解決關(guān)系型數(shù)據(jù)庫數(shù)據(jù)與簡單Java對象映射關(guān)系的技術(shù)。
因為MyBaits在查詢對象或關(guān)聯(lián)集合對象時,需要手動編寫SQL。所以稱為半自動ORM映射工具。
全自動Hibernate
優(yōu)點:
●SQL可寫在XML里,解除SQL與程序代碼的耦合,便于統(tǒng)一管理;提供XML標(biāo)簽,支持編寫動態(tài)SQL,并可重用
●消除JDBC大量冗余的代碼,不需要手動開關(guān)連接
●很好的與各種數(shù)據(jù)庫兼容(因為MyBaits使用JDBC來連接數(shù)據(jù)庫,所以只要JDBC支持的數(shù)據(jù)庫,MyBaits都支持)
●能夠與Spring很好的集成
缺點:
●SQL語句依賴于數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫移植性差,不能隨意更換數(shù)據(jù)庫。
關(guān)于#{ }和${ }格式的占位符
●#{} 用于設(shè)置參數(shù). 占位符,預(yù)編譯處理,可防止SQL注入,提供系統(tǒng)安全性
●${} 用于SQL拼接. 拼接符,字符串替換,沒有預(yù)編譯處理,不能防止SQL注入。
SpringBoot
SpringBoot:Spring為了解決其框架繁瑣的配置工作,而提供的一鍵配置,一次啟動的整合工具
在IDEA創(chuàng)建SpringBoot項目,需要通過網(wǎng)站進行初始化
1https://start.spring.io主要網(wǎng)站
2https://start.aliyun.com備選網(wǎng)站
3https://start.springboot.io
若有收獲,就點個贊吧