文章目錄
-
- 如何理解面向對象編程?
- JDK 和 JRE 有什么區別?
- 如何理解JAVA中封裝,繼承、多態特性?
- 如何理解Java中的字節碼對象?
- 你是如何理解Java中的泛型的?
- 說說泛型應用在什么場景呢?
- 如何理解Java中的泛型通配符?
- 說說什么是泛型類型擦除?
- 我們為什么要學習JVM?
- 市場上有哪些主流的JVM呢?
- JVM的體系結構是怎樣的?
- 你知道JVM有哪些運行模式嗎?
JAVA編程基礎
如何理解面向對象編程?
面向對象編程強調的是一種編程的思想,它是將客觀存在的一切事物都理解為計算機中的對象,當我們通過編寫程序的方式去解決一些業務問題時,應該首先想到的是用什么對象去解決這個問題,其次是才是解決這個問題的步驟。例如將大象放冰箱,不能先想到的是打開門,放大象,關門這個步驟,這只是一種面向過程編程而已。而面向對象編程,強調的是你要放的是一個什么樣的大象,你是否有可以放下這個大象的冰箱,然后由誰將大象放到冰箱。也就是說面向對象的重點是對象。再比如說我要去上海,首先想到的應該是交通工具,然后才是先到哪里,再到哪里??偠灾嫦驅ο缶幊叹幊谈先藗兛创聞盏幕疽幝?,這種思想也非常適合解決一些大型的業務問題,例如讓你做一航母,你應該想到的是這個航母的構成,而不是構建這個航母的基本步驟。讓你去做一個電商項目,你應該想到的是這個項目中系統服務對象的構成,例如商品服務,推薦服務,訂單服務,庫存服務,配送服務,優惠券服務,知識問答服務等等,這就是面向對象編程。
JDK 和 JRE 有什么區別?
JDK: Java Development Kit 的簡稱,Java開發工具包,提供了Java的開發環境和運行環境。
JRE: Java Runtime Environment的簡稱,Java運行環境,為Java的運行提供了所需環境。
實際上我們在安裝JDK時,它會包含一個Jre,同時還包含了編譯Java源碼和運行Java 類文件的一個開發、調試和分析的工具。簡單點說,假如你需要運行Java程序,只需要安裝Jre就可以了,如何你需要編寫,調試Java程序,需要安裝JDK。
如何理解Java中封裝,繼承、多態特性?
封裝特性:
個人認為封裝特性應該是面向對象編程中最難的一個特性。大到一個系統的構成,比方說這個系統應該有多少個服務,每個服務應該有哪些模塊,每個模塊應該有哪些對象,這里其實強調的是一個系統邊界劃分的問題,當然也是封裝問題。還有,小到一個對象應該有哪些屬性,哪些方法,這些對象,屬性和方法分別使用什么樣的訪問修飾符進行定義,它們的可見范圍是怎樣的,這都是封裝特性。生活中大到國家有多個省份,每個省份有多少個地市,每個地市有多少個區縣。小到一個公司有多少個事業部,每個事業部有哪些成員,每個成員都有什么特征(個頭高,帥氣,漂亮),什么行為(做事,說話,跳舞,唱歌),這也都是封裝。在Java編程過程中,我們知道MyBatis實現了對JDBC操作數據庫這個過程的封裝,Spring封裝了對象的創建,依賴注入的過程,SpringBoot封裝了很多的基礎配置,實現了開箱即用的特性,Spring Cloud 封裝了一種服務治理的思想,例如如何實現服務注冊,發現,調用,配置等。當然程序中的每個對象也都有自己的特性和行為,例如線程對象封裝了執行任務的的特性和方法,IO對象封裝了讀寫內存,磁盤,網絡數據方式等等,這些都是封裝特性。
繼承特性:
Java中的繼承特性是程序中實現代碼的復用的一種方式,也是它最大的優勢,實際編程中我們通常將共性寫到父類中,特性寫到子類中,當然子類也可以進行自己的擴展。這種繼承關系可以看成是一種is a的關系,例如class Circle extends Shape{}表示圓形(Circle)是一個圖形(Shape),class Dog extends Animal{}表示狗(Dog)是一個動物(Animal)。在Java中類的繼承可以是多層,但不能是多重,即一個子類不能有多個直接的父類,子類可以繼承父類所有屬性和方法,但私有屬性和方法不能直接訪問。子類可以基于業務重寫父類可見方法,以實現功能拓展。我們也可以在子類構造方法內部通過super(參數列表)調用父類構造方法和super.xxx的方式調用父類的成員。在實際應用中繼承關系是一種強耦合關系,繼承關系層次最好不要多于三層,否則可能難于維護。
多態特性
多態是對對象行為的一種描述,在java中基于封裝和繼承特性,定義了編譯時多態和運行時多態。編譯時的多態就是方法的重載(方法名相同,參數列表不同),運行時的多態是基于繼承特性實現的一種重寫。本質上就是把做什么和具體怎么做分開了,例如我們定義了要做什么,但具體怎么做完全取決于具體的對象。例如睡覺是一種行為,但是有的人睡覺時磨牙,有的人說夢話,有的人打呼嚕,有的人夢游。同樣,吃飯也是一種行為,有的人吃飯細嚼慢咽,有的人狼吞虎咽。在程序中我們通常將多態特性應用在方法的返回值和參數類型上,方法的返回值和參數類型能用抽象則用抽象,便于后于進行多態拓展。
如何理解Java中的字節碼對象?
每個類在加載(將類讀到內存)時都會創建一個字節碼對象,其類型為Class類型,且這個對象在一個JVM內存中是唯一的.此對象中存儲的是類的結構信息(元數據信息),節碼對象的獲取方式常用的有如下三種:
a) 類名.class
b) Class.forName(“包名.類名”)
c) 類的實例對象.getClass();
代碼演示:
package com.java.oop;
//呈現類加載過程(通過配置JVM參數實現)
//-XX:+TraceClassLoading
public class TestClassObject01 {
static public void main(String[] args)throws Exception {
Class<Object> c1=Object.class;
Class<?> c2=Class.forName("java.lang.Object");
System.out.println(c1==c2);
Class<?> c3=new Object().getClass();
System.out.println(c2==c3);
}
}
你是如何理解Java中的泛型的?
泛型是JDK1.5推出的一種參數化的類型,我們可以將定義類型時使用的泛型,理解為形參。例如,List、Map<K,V>接口中的E,K,V都可以看成是泛型,也就是一種特殊的形參,當我們應用這些集合時傳入的具體類型可以看成是實際參數。例如List這里的String可以看成是實際參數。泛型也是是編譯時的一種類型,此類型僅僅在編譯階段有效,運行時無效.例如List在運行時String會被擦除,最終系統會認為都是Object類型。
說說泛型應用在什么場景呢?
泛型是實現通用編程的一種手段,通常應用在類,接口,方法的定義上,例如:
1.泛型類: class 類名<泛型,…>{}
2.泛型接口: interface 接口名<泛型,…>{}
3.泛型方法: 訪問修飾符 <泛型> 方法返回值類型 方法名(形參){}
代碼演示:
泛型接口的定義,例如:
interface Container<T>{
//泛型接口
void add(T t);
T get(int i);
int size();
}
interface Task<Param,Result>{
//思考map中的泛型Map<K,V>
/**
* 此方法用于執行任務
* @param arg 其類型由泛型參數Param決定
* @return 其類型由泛型參數result決定
*/
Result execute(Param arg1);
}
泛型類的定義,例如:
interface Result<T>{
//泛型類
T data;
}
泛型方法定義,例如:
class ObjectFactory{
//泛型方法
public <T>T newInstance(Class<T> cls)
throws Exception{
return cls.newInstance();
}
}
class ContainerUtils{
//泛型方法
//1)靜態方法假如有泛型肯定是泛型方法
//2)泛型類和泛型接口不作用于靜態方法
//3)泛型方法一定是靜態方法嗎?不是
public static <T>void sort(List<T> list) {
}
}
總結:
- 泛型類和泛型接口用于約束類或接口中實例方法參數類型,返回值類型。
- 泛型類或泛型接口中實際泛型類型可以在定義子類或構建其對象時傳入。
- 泛型方法用于約束本方法(實例方法或靜態方法)的參數類型或返回值類型。
- 泛型類上的泛型不能約束類中靜態方法的泛型類型。
如何理解Java中的泛型通配符?
Java中的泛型通配符一般可以理解為一種通用的類型,也可認為不確定性類型。從應用上,它可分為三種類型:
1)無屆通配符:<?>
2)上屆通配符:<? extends 類型>
3)下屆通配符:<類型 extends ?>
代碼演示:
//無屆通配符
Class<?> c2=Class.forName("java.lang.Object");
//上界通配符
static void doPrint(List<? extends CharSequence> list){
System.out.println(list);
}
//下界通配符
static void doPrint(Set<? super Integer> set){
//下屆
System.out.println(list);
}
說說什么是泛型類型擦除?
泛型是編譯時的一種類型,在運行時無效,運行時候都會變成Object類型。
例如基于反射向List list=new ArrayList() 集合中添加整數,關鍵代碼如下:
List<String> list=new ArrayList<>();
list.add("A");
list.add("B");
//list.add(100);
//在運行時將100寫入到list集合
//1.獲取list對象的字節碼對象
Class<?> cls=list.getClass();
//2.獲取list字節碼對象中的add方法對象
Method method=
//cls.getDeclaredMethod("add",Object.class);
cls.getDeclaredMethod("add",int.class,Object.class);
//3.通過反射執行方法對象將100寫入集合。
//執行list對象的method方法
//method.invoke(list, 100);
method.invoke(list, 0,100);
System.out.println(list);
Java 虛擬機分析
你是如何理解JVM的?
JVM(Java Virtual machine)是JAVA平臺的一部分,是一種能夠運行Java bytecode的虛擬機,如圖所示:
JVM是硬件計算機的抽象(虛構)實現,可以解釋執行JAVA字節碼,也是實現JAVA跨平臺運行的基石,如圖所示:
我們為什么要學習JVM?
深入理解JVM可以幫助我們從平臺角度提高解決問題的能力,例如:
- 有效防止內存泄漏(Memory leak)。
- 優化線程鎖的使用 (Thread Lock)。
- 科學進行垃圾回收 (Garbage collection)。
- 提高系統吞吐量 (throughput)。
- 降低延遲(Delay),提高其性能(performance)。
市場上有哪些主流的JVM呢?
JVM是一種規范基于這種規范,不同公司就對此規范做了具體實現,例如市場上的一些主流JVM如下:
- JRockit VM (BEA公司研發,后在2008年由Oracle公司收購)。
- HotSpot VM (Sun公司研發,后在2010年由Oracle公司收購)。
- J9 VM (IBM 內部使用)。
說明:HotSpot目前是甲骨文公司最主要的一款JVM虛擬機,也是我們現在最常用的一種。
JVM的體系結構是怎樣的?
JVM (Java Hotspot Architecture:主要分為三大部分,如圖-6所示:
- 類加載系統 (ClassLoader System) :負責加載類到內存。
- 運行時數據區 (Runtime Data Area):負責存儲數據信息。
- 執行引擎 (Execution Engine):負責調用對象執行業務。
其中:
- ClassLoader作用是什么?(負責將類從磁盤或網絡加載內存)
- ClassLoader 可以自己定義嗎?(可以,參考Tomcat,MyBatis,Spring等,他們都有自定義類加載器)
- JVM 中的方法區(Method Area) 如何理解?(邏輯上的一種定義,不同JVM有不同實現,比方說有JVM中稱元數據區,有的稱持久代)
- HotSpot JDK8虛擬機在創建對象時,所有的對象都會分配在堆中嗎?(不一定,小對象未逃逸,可以直接分配在棧上)
- 如何知道類的加載順序?(可通過配置JVM 參數-XX:+TraceClassLoading 檢查類的加載過程)
JDK8中的Hotspot簡易內存體系結構如下:
你知道JVM有哪些運行模式嗎?
JVM有兩種運行模式Server與Client。兩種模式的區別在于,Client模式啟動速度較快,Server模式啟動較慢;但是啟動進入穩定期之后Server模式的程序運行速度比Client要快很多。這是因為Server模式啟動的JVM采用的是重量級的虛擬機,對程序采用了更多的優化;而Client模式啟動的JVM采用的是輕量級的虛擬機。所以Server啟動慢,但穩定后速度比Client遠遠要快。
現在64位的jdk中默認都是server模式(可通過 java -version進行查看)。當虛擬機運行在-client模式的時候,使用的是一個代號為C1的輕量級編譯器, 而server模式啟動的虛擬機采用相對重量級,代號為C2的編譯器.c1、c2都是JIT編譯器, C2比C1編譯器編譯的相對徹底,服務起來之后,性能更高。