-
描述一下JVM加載class文件的原理機制
答:JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現的,Java中的類加載器是一個重要的Java運行時系統組件,它負責在運行時查找和裝入類文件中的類。
由於Java的跨平臺性,經過編譯的Java源程序並不是一個可執行程序,而是一個或多個類文件。當Java程序需要使用某個類時,JVM會確保這個類已經被加載、連接(驗證、準備和解析)和初始化。類的加載是指把類的.class文件中的數據讀入到內存中,通常是創建一個字節數組讀入.class文件,然後產生與所加載類對應的Class對象。加載完成後,Class對象還不完整,所以此時的類還不可用。當類被加載後就進入連接階段,這一階段包括驗證、準備(爲靜態變量分配內存並設置默認的初始值)和解析(將符號引用替換爲直接引用)三個步驟。最後JVM對類進行初始化,包括: 1) 如果類存在直接的父類並且這個類還沒有被初始化,那麼就先初始化父類; 2) 如果類中存在初始化語句,就依次執行這些初始化語句。
類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)、系統加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始,類加載過程採取了父親委託機制(PDM)。PDM更好的保證了Java平臺的安全性,在該機制中,JVM自帶的Bootstrap是根加載器,其他的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載,父類加載器無能爲力時才由其子類加載器自行加載。JVM不會向Java程序提供對Bootstrap的引用。下面是關於幾個類加載器的說明:
Bootstrap:一般用本地代碼實現,負責加載JVM基礎核心類庫(rt.jar);
Extension:從java.ext.dirs系統屬性所指定的目錄中加載類庫,它的父加載器是Bootstrap;
System:又叫應用類加載器,其父類是Extension。它是應用最廣泛的類加載器。它從環境變量classpath或者系統屬性java.class.path所指定的目錄中記載類,是用戶自定義加載器的默認父加載器。 -
byte a=5; byte b; b=b+a;
能編譯通過嗎?
答:不能,因爲int轉byte會精度損失,所以需要強制類型轉換。 -
byte a=5; byte b; b=(byte)(b+a);
能編譯通過嗎?
答:不能,因爲b沒有給初始化值 -
整型的數值默認爲
int
類型,小數的數據默認爲double
類型;小數據類型
與大數據類型
運算,結果自動轉向大數據類型
大數據類型值
賦值給小數據類型值
需要強制轉換
,否則報錯從大到小可能會有損失
,如byte b = (byte)200;
-
byte
數據類型範圍爲-128~127
,如果超過這個區間則需要強轉賦值,如byte b = (byte)-129;
或byte b = (byte)128
,不強轉賦值則會報錯不兼容的類型: 從int轉換到byte可能會有損失
。
同理:byte、short、int、long
只要不超過int
的範圍就可以直接賦值,否則需要強制轉換
,long
類型的數據只需要在最後加L
或l
-
float
數據類型賦值小數
時需要在數值後面加F
或f
-
數字
與字符串
類型相+時,如果有數字運算
在字符串
之前,則先計算
數字運算,然後以字符串形式
與後面的字符串合併 -
什麼是java虛擬機,什麼是java的虛擬機實例?
答:java虛擬機相當於我們的一個java類,而java虛擬機實例相當於我們new一個java類,不過java虛擬機不是通過new這個關鍵字而是通過java.exe或者javaw.exe來啓動一個虛擬機實例。 -
JVM的生命週期是怎樣的?
答:當一個java應用的main函數啓動時虛擬機也同時被啓動,而只有當在虛擬機實例中的所有非守護線程都結束時,java虛擬機實例才結束生命。 -
JVM虛擬機的內部體系結構
-
一張圖看懂JVM:https://www.cnblogs.com/bigben0123/p/9685474.html,挺詳細
-
JVM基本結構:https://blog.csdn.net/yfqnihao/article/details/8289363,理解深入易懂
-
爲什麼在建表時不能使用外鍵和級聯更新?
答:外鍵與級聯更新適用於單機低併發,不適合分佈式、高併發集羣;級聯更新是強阻塞,存在數據庫更新風暴的風險;外鍵影響數據庫的插入速度。 -
數組
學習中的常見問題:第一種:
編譯錯誤,array未初始化變量
int[] array; System.out.println(array); 編譯錯誤,array未初始化變量
第二種:
編譯通過,運行錯誤NullPointerException空指針異常
int[] arr3 = null; System.out.println(arr3); 輸出結果,null System.out.println(arr3[0]); 運行報錯,空指針異常
第三種:
編譯通過,運行錯誤ArrayIndexOutOfBoundsException數組索引越界異常
int[] arr4 = new int[1]; System.out.println(arr4[1]); 數組索引越界ArrayIndexOutOfBoundsException
第四種:
int
、char
和String
的直接輸出名稱結果
和分配空間後的默認值
int[] arr5 = new int[1]; System.out.println(arr5); /輸出結果:數組地址 System.out.println(arr5[0]); /輸出結果:0,數組分配空間後int類型默認是0 char[] arr6 = new char[]{'a','b','c','d'}; System.out.println(arr6); /輸出結果:abcd,出現這種情況的原因: /因爲java中規定數組都是對象,所以println(Object)輸出的都是這個數組對象的哈希值。 而對於char型數組,println()有專門的重載形式---println(char[]), 它輸出的是數組的值。這個是源碼裏已經設置好了的。 char[] arr66 = new char[1]; System.out.println(arr66[0]); /輸出結果:空格 String[] arr7 = new String[1]; System.out.println(arr7); /輸出結果:數組地址 System.out.println(arr7[0]); /輸出結果:null,數組分配空間後String類型默認null char[] arr8 = new char[1]; System.out.println(arr8+"a"); /輸出結果:[C@15db9742a (char數組地址+字符串值) /原因還是由於println()只是對char類型數組重載,對於String類型對象依然是輸出地址 System.out.println(arr8[0]+"a");/輸出結果: a(空格a)
-
下列哪些是方法是public int add (int a)的重載方法?( A C D ) (多選)
A. public int add (long a);
B. public void add (int a); // 叫做方法的重複定義
C. public void add (long a);
D. public int add (float a);
//重載爲定義在同一個類中,方法名字相同,參數列表不同(1. 參數個數不同 2. 參數類型不同 3. 不同類型參數間的排列順序 ),與方法的返回值無關 -
對象的創建內存圖運行過程
class 對象的創建內存圖 { public static void main(String[] args) { C c=new C(10); } } class C { int n=5; public C(){ System.out.println(n); } public C(int n){ System.out.println("1======="+this.n); this.n=n; System.out.println("2=========="+this.n); } }
答:
1.當jvm 加載當前的類到方法區之後,main方法開始壓棧。
2.在棧中 ,創建一個名稱爲c的,數據類型爲C的變量的空間。
3.加載C類的信息到方法區,開始在堆中創建C類的對象。
4.對象的屬性經過三種初始化 :
① 默認初始化:在開闢屬性的空間時。執行。
② 顯式初始化:在構造方法中,但是沒有執行構造方法中的代碼時,執行
③ 構造初始化:在構造方法中修改
5.假設 該對象的地址爲0x15
6.將0x15的值賦給引用變量c。 -
方法與構造方法的區別與聯繫
答:區別:
① 寫法上
1》 構造方法 名稱必須是類名,並且沒有返回值。
2》 方法 名稱可以是任意的標識符,必須有返回值,無論是void或者返回值數據類型。
② 調用:
1》 構造方法 調用 通過new關鍵字來進行調用。
2》 方法 調用 通過對象來進行調用。
③ 對象 :
1》 構造方法 對於同一個對象,只能調用一次。
2》 方法 對於同一個對象,無數次。
④ 功能 :
1》 構造方法 功能 創建對象 和初始化對象
2》 方法 功能 實現了某種功能
聯繫:
① 構造方法也是方法,實現某些功能。
② 構造方法與方法都有重載形式。 -
Java中靜態代碼塊、構造代碼塊、構造方法、普通代碼塊、成員變量初始化順序
答:父類靜態代碼塊(靜態成員變量)>子類靜態代碼塊(靜態成員變量)>父類構造代碼塊(普通成員變量)>父類構造方法>子類構造代碼塊(普通成員變量)>子類構造方法 -
this、super的區別和應用場景
答:super
關鍵字是子類調用父類的成員,它包括父類的public、protected修飾的變量、方法
等等super.父類的方法
子類調用父類的方法1、super從子類中調用父類的構造方法,this在同一類內調用其它方法
2、this和super不能同時出現在一個構造函數裏面
3、this或super調構造器時必須放在第一句,如果不放在第一句則可能對父類的數據多次初始化
4、this和super都指的是對象,所以,均不可以在static環境下使用 -
final、finally和finalize的區別
答:final
:是最終的意思,可以修飾類,成員變量,成員方法。
修飾類,類不能被繼承;修飾方法,方法不能被重寫但是可以繼承;修飾變量,變量就變成了常量,只能被賦值一次,也可以繼承
finally
:是異常處理的一部分,用於釋放資源一般來說,代碼肯定會執行,特殊情況:在執行到finally之前jvm退出了
finalize
:是Object類的一個方法,用於垃圾回收 -
繼承
時需要注意哪些?
答:子類覆蓋父類方法時的要求
:兩同、兩小、一大
1.方法名和參數列表必須相同:子類==父類
2.返回值類型和拋出異常:子類<=父類
3.權限修飾符:子類>=父類
子類無法覆蓋父類的:
(1)構造方法 (2)static聲明的靜態方法 (3)private聲明的私有方法 (4)final聲明的最終方法 -
JAVA 繼承 父類子類 內存分配圖解
https://blog.csdn.net/erica_1230/article/details/76571936 -
子類在繼承父類後,實例化子類時,父類被實例化了嗎?父類的成員變量和方法存在於堆內存中的哪裏?
答:子類在繼承父類後,如果父類中有非靜態非私有
(普通)的成員變量,那麼在堆
裏子類對象內存
中給這些父類的成員變量
再分配一些內存,並且子類對象內存
中存的只是父類
的一個引用
,並沒有
給父類實例化,通過super
來調用子類對象內部
的父類的特徵(屬性和方法
)。(還不懂就看JAVA 繼承 父類子類 內存分配圖解
這一題的網址) -
多態成員訪問的特點?
答:比如有個類B繼承類A,A a = new B()
成員變量
:編譯看左邊
看A類裏的,運行看左邊
看B類裏的,但是如果在B類裏對成員變量賦值
了,那麼更改的也只是堆內存中子類(B類)對象內存
中爲父類(A類)
分配的那一塊內存中的成員變量,對類A沒有影響。例子如下:class test { public static void main(String[] args) { A a = new B(); System.out.println(a.a);//結果爲10,因爲B類中沒有對分配給父類變量的一塊內存賦值 } } class A{ int a =10; } class B extends A{ int a = 30; }
class test { public static void main(String[] args) { A a = new B(); // 運行結果爲20 30 System.out.println(a.a);// 結果爲20 } } class A{ int a =10; } class B extends A{ int a = 30; public B(){ super.a = 20; System.out.println(super.a);// 結果爲20 System.out.println(this.a);// 結果爲30 } }
成員方法
:編譯看左邊,運行看右邊,如25的練習題
構造方法
:創建子類對象時,先訪問父類的構造方法,對父類的數據進行初始化,子類構造器裏面默認有super();
靜態方法
:編譯看左邊,運行看左邊(靜態和類相關
,算不上重寫,還是看左邊) -
多態練習題
// 無結果,有結果的在下面 class A { public String show(D obj){ // D obj=d; return ("A and D"); } public String show(A obj){ return ("A and A"); } } class B extends A { public String show(B obj) { return ("B and B"); } public String show(A obj) { return ("B and A"); } } class C extends B{} class D extends B{} public class Test { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println(a1.show(b)); System.out.println(a1.show(c)); System.out.println(a1.show(d)); System.out.println(a2.show(b)); System.out.println(a2.show(c)); System.out.println(a2.show(d)); System.out.println(b.show(b)); System.out.println(b.show(c)); System.out.println(b.show(d)); } }
class A { public String show(D obj){ // D obj=d; return ("A and D"); } public String show(A obj){ return ("A and A"); } } class B extends A { public String show(B obj) { return ("B and B"); } public String show(A obj) { // A a2 = new B() return ("B and A"); } } class C extends B{} class D extends B{} public class Test { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println(a1.show(b)); // 因爲B類是A類的子類,所以結果爲① A and A System.out.println(a1.show(c)); // 因爲C是B的子類,B是A的子類,所以結果爲② A and A System.out.println(a1.show(d)); // 因爲有直接接收D類的方法,所以結果爲③ A and D System.out.println(a2.show(b)); // 多態的方法編譯看左邊看A類show方法,運行看右邊看B類show方法, // A裏有接收B的方法(原因同1(即①)),B裏也有,走B,所以結果爲④ B and A System.out.println(a2.show(c)); // 原因看2②和4④,所以結果爲⑤ B and A System.out.println(a2.show(d)); // 編譯看左邊看A類show方法,運行看右邊看B類show方法 // A類有接收D的方法,所以結果爲⑥ A and D System.out.println(b.show(b)); // 直接看B類裏的show方法,所以結果爲⑦ B and B System.out.println(b.show(c)); // 因爲C繼承B,B繼承A,並且兩個方法都可以接收C,但是按輩分最近的接收 // 所以結果爲⑧ B and B System.out.println(b.show(d)); // 雖然裏面有個接收B的show方法可以接收 // 但是B繼承A,所以B裏面有直接接收D的show方法 // 所以結果爲⑨ A and D } }
-
String類對象創建內存圖
-
String對象創建的細節問題
答:常量池:jdk1.6時,常量池在方法區;jdk 1.7後,移除了方法區間,運行時常量池和字符串常量池都在堆中。
理解java中String字符串常量池
https://blog.csdn.net/qq_27093465/article/details/52250033
https://www.cnblogs.com/shoshana-kong/p/11249311.html
***(這個帖子詳細)https://www.cnblogs.com/tongkey/p/8587060.html
***https://blog.csdn.net/zzzgd_666/article/details/87999870#commentBox
對於兩個聲明的字符串使用 " + " 拼接, 因爲jvm的優化,會將拼接後的結果放入常量池.但是兩個聲明的字符串不會,(String s = “abc”+ “def”, 會直接生成“abcdef"字符串常量 而不把 “abc” "def"放進常量池)
String ss3 = new String("hello") + new String("hello"); // new + new 或者 "a"+new 都是在堆中分配一塊空間,返回給ss3在堆中新的對象的地址 String ss4 = "hellohello"; // 字符串常量直接從字符串常量池中找hellohello,有的話直接引用,沒有創建再引用 String intern3 = ss3.intern(); // intern():如果常量池中已經存在該字符串,則直接返回常量池中該對象的引用。否則,在常量池中加入該對象,然後 返回引用 // 調用ss3.intern()方法會先檢查字符串池中是否含有該字符串,有的話則直接得到引用地址 // 沒有的話則將堆中ss3對象的引用存放到字符串常量池 System.out.println(ss3.hashCode()); System.out.println(ss4.hashCode()); //hashCode()獲取的是常量池裏的地址,這裏直接找的是hellohello的地址,所以ss3與ss4的hashCode()相同 System.out.println(ss3 == ss4);//false System.out.println(ss4==intern3);//true
String ss = new String("hello")
創建了兩個對象,一個對象是常量池中創建的"hello",另一個對象是堆中分配的內存,ss指向的就是堆中內存的地址。
String ss3 = new String("hello") + new String("hello");
new + new 或者 “a”+new 都是在堆中分配一塊空間並且內存中存入了"hellohello",並沒有在常量池中創建"hellohello"
,返回給ss3的是在堆中新的對象的地址。當調用ss3.intern()
時,jdk1.6之前
的是在常量池中創建一份"hellohello"
,而jdk1.7之後
的是在常量池中創建一份ss3的引用
,我用的是jdk1.8版本,String ss4="hellohello"
中的ss4
獲取的是常量池中存儲的ss3的引用
,所以ss3==ss4爲true
-
String、StringBuffer和StringBuilder的區別?
答:String
是不可變字符串,長度不可改變;StringBuffer
是線程安全的可變字符序列,可以改變該對象的值和長度;StringBuilder
是線程不安全的可變字符序列,但是執行速度快。 -
泛型
在class文件中不存在,只是在編譯器存在。叫可擦除技術 -
ArrayList、LinkedList和Vector的區別?
答:ArrayList
:底層-可變大小的數組;特點-有序、可重複(查詢快、增刪慢、線程不安全)
遍歷的方式:(五種)1、數組:toArray()—>Object[]
2、迭代器:Iterator
3、特有的迭代器ListIterator
4、一般for
5、增強for
LinkedList
:底層-雙向鏈表;特點-有序、可重複(增刪快、查詢慢、線程不安全)
Vector
:底層-數組;特點-有序、可重複(線程安全) -
泛型的使用
- 泛型概念:
①參數化類型
。數據類型不同,數據類型的位置是變量,隨着變量值的不同,數據類型也不同。 - 泛型格式:<標識符>
標識符一般用ETKV來進行表示,其中E通常用來表示Element 元素
,K Key 鍵
,V value 值
,T type 類
,這些沒有實際含義。 - 泛型的分類
泛型類
格式:class 類名<泛型,泛型,泛型> { }public class 泛型類 { public static void main(String[] args) { /*B<String> b=new B(); b.add("1", "2"); B<Integer> b1=new B(); b1.add(1, 2);*/ B<String,Integer> b2=new B(); b2.add("1", 3); } } /泛型類 多個用逗號隔開 class B<M,V>{ public void add(M a,V b) {} }
泛型接口
格式:①泛型具體,子類可以不帶泛型
②泛型不具體,子類也需要帶泛型public class 泛型接口 { public static void main(String[] args) { ZiT1 z=new ZiT1(); z.add("1", "2"); ZiT2<Integer> zt=new ZiT2(); zt.add(1, 2); } } interface T<E>{ public void add( E a, E b); } //泛型接口的兩種實現形式 ,① 泛型具體,子類可以不帶泛型 class ZiT1 implements T<String>{ @Override public void add(String a, String b) { } } //泛型接口的兩種實現形式 ,② 泛型不具體,子類也需要帶泛型 class ZiT2<M> implements T<M>{ @Override public void add(M a, M b) { } }
泛型方法
格式: 權限修飾符 修飾符<泛型>
返回值類型 方法名稱(參數){ }
注意:1、泛型方法是在方法上聲明瞭泛型,而不是使用了泛型的方法。
使用類或者接口的泛型這些方法不算泛型方法。
2、類或者接口的泛型
只能用在非靜態方法中,不能用於靜態方法
,對於靜態方法
,只能使用泛型方法
的形式。public class 泛型方法 { public static void main(String[] args) { K<String> k=new K(); k.add("123", "123"); k.add("123", 123); } } class K<M>{ //V 表示的泛型僅在該方法中使用,該類的其它方法不使用。 //泛型的方法 格式 : 返回值前加 泛型的聲明 public <V>void add(M a, V b) { } //靜態方法 只能使用泛型方法,不能使用類或接口上的泛型。 public static <K>void div(K a) { } }
- 通配符
<? extends E>
: 只能傳入E的子類
<? super E>
:只能傳入E的父類
- 泛型概念:
-
樹的遍歷方式:
- 先序遍歷:根左右
- 中序遍歷:左根右
- 後序遍歷:左右根
-
HashSet集合底層、特點、去重複問題
答:底層
是哈希表(由HashMap實現,是HashMap的key列),特點
是不重複、無序,去重複
:重寫equals()和hashCode() -
HashSet集合的存儲過程
答:(簡答)首先通過hashCode()比較哈希碼值,根據哈希碼值推算出該對象在集合中的存儲位置,如果該位置上有對象,繼續走equals()比較兩個對象是否相等,如果相同不插入,不同就直接在該位置後面插入該元素對象。
(詳細)1、首先通過對象的HashCode方法算出對象的哈希碼值,根據哈希碼值推算出該對象在集合中的存儲位置。2、如果算出來的存儲位置的索引值上有元素對象,這種現象稱爲哈希碰撞。需要存儲的元素對象就與該位置上已經存在的對象進行比較,通過equals判斷是否相等,如果相等不插入,否則在該位置後面插入該元素對象(jdk1.8之後該位置上如果插入的元素個數大於等於8個,則從鏈表形式改爲紅黑樹的形式) -
TreeSet集合底層、特點、去重複問題
答:底層
是紅黑樹(基於TreeMap),特點
是不重複、無序、可排序,去重複
:①實現Comparable< T>接口,重寫compareTo(T o)方法②創建一個類implements Comparator< T>,實現compare(T o1,T o2)方法 -
TreeSet集合的存儲過程
答:
(1) 元素的自然排序:
① Comparable 接口 ,實現該接口的類,可以對該類所對應的集合進行排序,這種排序 稱爲元素的自然順序排序。
② 實現該接口的方法 :compareTo(T o)當這個方法的返回值 大於0 (對象在後) 小於0 (對象在前 ) 等於0 (相等)
(2)TreeSet集合默認無參構造方法
,按照元素的自然順序進行排序,要求存入該集合的元素自定義類的對象的所在類 必須要實現Comparable,實現接口中的方法:compareTo方法,否則會報異常 ClassCastException 類型轉換異常。 -
LinkedHashSet集合
答:該集合由哈希表與雙向鏈表組成,插入與存儲順序相同。一般用於購物車,商品歷史記錄。特點:有序 不重複 -
Map集合的特點
答:Map集合爲雙列集合,(1) 存儲的元素是鍵值對的形式(2)鍵不能重複,值可以重複。(3)一個鍵只對應一個值。 -
通過Map集合來實現統計字符串中每個字符出現的次數
答:public static void main(String[] args) { // 統計一個字符串中每個字符出現的次數 String s = "adadsafqkjhdkjhkasasd"; //創建HashMap集合來存儲字符和次數 Map<Character, Integer> map = new HashMap<>(); // 將字符串轉化成字符數組 char[] charArr = s.toCharArray(); // 遍歷字符數組統計字符個數 for(char ch : charArr) { if (map.containsKey(ch)) { // 如果hashMap集合中包含這個字符,則在原來的次數上加1 map.put(ch, map.get(ch)+1); }else { // 如果hashMap集合中不包含這個字符,則給這個字符一個初始次數 map.put(ch, 1); } } System.out.print(map); }
-
HashMap、TreeMap、LinkedHashMap、HashTable的區別?
答:HashMap底層數據結構是哈希表,線程不安全,效率高,允許有null的鍵和值,輸出是無序的;TreeMap底層數據結構是紅黑樹,線程不安全,允許有null的鍵和值,輸出是有序的,按照Key鍵的自然順序;HashTable底層數據結構是哈希表,線程安全,效率低,不允許有null的鍵和值;LinkedHashMap是Map接口的哈希表和鏈表實現,具有可預知的迭代順序 -
匿名內部類的注意事項
-
TCP、UDP的特點是什麼?
答:UDP:面向無連接的,通過數據報包進行傳輸,每個數據報包的大小不超過64k,傳輸速度快。實時性,不考慮數據的完整性。
TCP:傳輸控制協議,面向連接的、可靠的、基於字節流的傳輸層通信協議。
TCP與UDP區別總結:
1、TCP面向連接(如打電話要先撥號建立連接);UDP是無連接的,即發送數據之前不需要建立連接
2、TCP提供可靠的服務。也就是說,通過TCP連接傳送的數據,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保 證可靠交付
3、TCP面向字節流,實際上是TCP把數據看成一連串無結構的字節流;UDP是面向報文的
UDP沒有擁塞控制,因此網絡出現擁塞不會使源主機的發送速率降低(對實時應用很有用,如IP電話,實時視頻會議等)
4、每一條TCP連接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通信
5、TCP首部開銷20字節;UDP的首部開銷小,只有8個字節
6、TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道
https://blog.csdn.net/q357010621/article/details/80150342
-
反射的方法
答:
Class中的方法:clazz.newInstance()
:利用無參構造創建對象clazz.getConstructor(String.class,int.class)
:獲取有參構造器clazz.getDeclaredConstructor(int.class)
:可以獲取所有修飾符修飾的構造方法clazz.getConstructors()
:只能獲取公共的構造方法clazz.getDeclaredConstructors()
:所有構造方法,包含私有方法等方法.getFields()
:獲取權限爲公共的屬性.getDeclaredFields()
:獲取任意權限屬性.getDeclaredField(String)
:可獲取任意訪問權限的屬性,需要設置可訪問.setAccessible(true).getField(String)
:只獲取公共屬性.getMethod(String methodName,Class parameterTypes)
:獲取父類及自身的所有公共方法.getDeclaredMethod(String methodName,Class parameterTypes)
:獲取自身類的所有方法
Field中的方法:
.set(Obj obj,Obj value)
:設置obj對象的Field值爲value.get(Obj obj)
:獲取obj對象的Field值
Method中的方法:
invoke(Object obj, Object... args)
: 方法的調用
-
lambda表達式的寫法和實現
答:格式
:
有參數無返回的寫法:(參數) -> {方法體;}
;
有返回值的寫法:(參數)->{return 返回值;}
注意:只有返回語句時,省略大括號必須省略return。
實現
:存在函數式接口
lambda表達纔可以使用,抽象類實現匿名內部類不可使用。
函數式接口
:接口中只有一個抽象方法的接口,函數式接口裏面可以有默認方法
和靜態方法
,但是只有一個抽象方法
。
interface TL{
public void fun();
//靜態方法
public static void fun1() {
System.out.println("aaaa");
}
//默認方法
default void fun2() {
System.out.println("接口的默認方法");
}
}
- jdk1.8特性
答:Consumer
消費型接口
例:Consumer consumer = System.out::println;
void accept(T t);Supplier
供給型接口
例:Supplier supplier = () -> {return new Teacher();};
T get();Function
函數型接口
例:Function<String,String> func = (x) -> x.concat(“hello”);
R apply(T t); Function<T,R> 參數爲T類型的,返回值爲R類型的Predicate
斷言型接口
boolean test(T t);- 方法引用:
爲了進一步簡化lambda的書寫 ,如果這些方法已經存在了,lambda表達式實現只是爲了調用這些已有方法,
可以採用方法引用的形式,來簡化lambda表達式的書寫。
格式 :::
方法引用運算符
①對於靜態方法 類名 :: 方法名
注意 方法名後面沒有任何內容。
② 對於實例方法 對象名 :: 方法名
③ 對於對象創建 類名 :: new
// lambda表達式
T t = () ->System.out.println("aa");
t.get();
T t1 = () ->{ System.out.println("aa"); };
t1.get();
//這是lambda表達式返回值簡寫
T2 t2 = (x) -> x;
System.out.println("這是lambda表達式返回值簡寫:"+t2.get(123));
//這是lambda表達式帶方法體和return返回的值
T2 t3 = (x) -> { return x;};
System.out.println("這是lambda表達式帶方法體和return返回的值:"+t3.get(123));
//這是用lambda表達式實現Consumer內置函數式接口
Consumer<String> con =(x) -> System.out.println(x);
con.accept("這是用lambda表達式實現Consumer內置函數式接口");
//這是用方法引用實現Consumer內置函數式接口
Consumer<String> consumer = System.out::println;
consumer.accept("這是用方法引用實現Consumer內置函數式接口");
//這是實現Supplier供給型內置函數接口
Supplier<String> supp = () -> "1";
System.out.println("這是實現Supplier供給型內置函數接口"+supp.get());
//這是實現Supplier供給型內置函數接口
Supplier<Teacher> supplier = () -> {return new Teacher();};
Teacher teacher = supplier.get();
System.out.println("這是實現Supplier供給型內置函數接口"+teacher.name);
// 這是用引用方法實現Supplier供給型內置函數接口
Supplier<Teacher> suppl = Teacher::new;
Teacher teac = suppl.get();
System.out.println(teac.name);
// 這是實現Function函數型內置函數接口
Function<String, String> function = (x) -> {return String.valueOf(x);};
String string = function.apply("asd");
System.out.println(string);
Function<String,String> func = (x) -> x.concat("hello");
String s = func.andThen(function).apply("123");
System.out.println(s);
-
Java中數組和集合的區別:
答:
1、數組的長度不可變,集合的長度可變
2、數組既能存基本數據類型也能存引用數據類型,集合只能存儲引用數據類型
3、數組只能存同一種數據類型(除非是Object []),集合可以存任意數據類型 -
get和post的區別:
答:
更詳細- GET提交的數據放在URL中,POST則不會。這點意味着GET更不安全(POST也不安全,因爲HTTP是明文傳輸抓包就能獲取數據內容,要想安全還得加密)
- GET回退瀏覽器無害,POST會再次提交請求(GET方法回退後瀏覽器再緩存中拿結果,POST每次都會創建新資源)
- GET提交的數據在請求頭,大小有限制(是因爲瀏覽器對URL的長度有限制,GET本身沒有限制),POST提交的數據在請求體,大小沒有限制
-
java的權限修飾符的訪問權限
答:public
是公共的,被public所修飾的成員可以在任何類中都能被訪問到。被public所修飾的成員能被所有的子類繼承下來。
protected
是受保護的,被protected所修飾的成員在同一個package或者不同的package中的子類都能訪問。被protected所修飾的成員也能被該類的所有子類繼承下來。
default
是默認的,即不寫任何修飾符,只有在同一個package中的子類才能訪問到父類中默認修飾的成員。被default所修飾的成員只能被該類所在同一個package中的子類所繼承下來。
private
是私有的,只能在當前類中被訪問到,它的作用域最小。
權限修飾符 | 當前類 | 同包 | 不同包子孫類 | 不同包類 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
默認 | √ | √ | ||
private | √ |
49.