第一階段java基礎學習筆記

  1. 描述一下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所指定的目錄中記載類,是用戶自定義加載器的默認父加載器。

  2. byte a=5; byte b; b=b+a;能編譯通過嗎?
    答:不能,因爲int轉byte會精度損失,所以需要強制類型轉換。

  3. byte a=5; byte b; b=(byte)(b+a);能編譯通過嗎?
    答:不能,因爲b沒有給初始化值

  4. 整型的數值默認爲int類型,小數的數據默認爲double類型;小數據類型大數據類型運算,結果自動轉向大數據類型
    大數據類型值賦值給小數據類型值需要強制轉換,否則報錯從大到小可能會有損失,如byte b = (byte)200;

  5. byte數據類型範圍爲-128~127,如果超過這個區間則需要強轉賦值,如byte b = (byte)-129;byte b = (byte)128,不強轉賦值則會報錯不兼容的類型: 從int轉換到byte可能會有損失
    同理:byte、short、int、long只要不超過int的範圍就可以直接賦值,否則需要強制轉換long類型的數據只需要在最後加Ll

  6. float數據類型賦值小數時需要在數值後面加Ff

  7. 數字字符串類型相+時,如果有數字運算字符串之前,則先計算數字運算,然後以字符串形式與後面的字符串合併

  8. 什麼是java虛擬機,什麼是java的虛擬機實例?
    答:java虛擬機相當於我們的一個java類,而java虛擬機實例相當於我們new一個java類,不過java虛擬機不是通過new這個關鍵字而是通過java.exe或者javaw.exe來啓動一個虛擬機實例。

  9. JVM的生命週期是怎樣的?
    答:當一個java應用的main函數啓動時虛擬機也同時被啓動,而只有當在虛擬機實例中的所有非守護線程都結束時,java虛擬機實例才結束生命。

  10. JVM虛擬機的內部體系結構在這裏插入圖片描述

  11. 一張圖看懂JVM:https://www.cnblogs.com/bigben0123/p/9685474.html,挺詳細

  12. JVM基本結構:https://blog.csdn.net/yfqnihao/article/details/8289363,理解深入易懂

  13. 爲什麼在建表時不能使用外鍵和級聯更新?
    答:外鍵與級聯更新適用於單機低併發,不適合分佈式、高併發集羣;級聯更新是強阻塞,存在數據庫更新風暴的風險;外鍵影響數據庫的插入速度。

  14. 數組學習中的常見問題:

    第一種:編譯錯誤,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
    

    第四種:intcharString直接輸出名稱結果分配空間後的默認值

    	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)
    
  15. 下列哪些是方法是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. 不同類型參數間的排列順序 ),與方法的返回值無關

  16. 對象的創建內存圖運行過程

    	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。

  17. 方法與構造方法的區別與聯繫
    答:區別:
    ① 寫法上
    1》 構造方法 名稱必須是類名,並且沒有返回值。
    2》 方法 名稱可以是任意的標識符,必須有返回值,無論是void或者返回值數據類型。
    ② 調用:
    1》 構造方法 調用 通過new關鍵字來進行調用。
    2》 方法 調用 通過對象來進行調用。
    ③ 對象 :
    1》 構造方法 對於同一個對象,只能調用一次。
    2》 方法 對於同一個對象,無數次。
    ④ 功能 :
    1》 構造方法 功能 創建對象 和初始化對象
    2》 方法 功能 實現了某種功能
    聯繫:
    ① 構造方法也是方法,實現某些功能。
    ② 構造方法與方法都有重載形式。

  18. Java中靜態代碼塊、構造代碼塊、構造方法、普通代碼塊、成員變量初始化順序
    答:父類靜態代碼塊(靜態成員變量)>子類靜態代碼塊(靜態成員變量)>父類構造代碼塊(普通成員變量)>父類構造方法>子類構造代碼塊(普通成員變量)>子類構造方法

  19. this、super的區別和應用場景
    答:super關鍵字是子類調用父類的成員,它包括父類的public、protected修飾的變量、方法等等

    super.父類的方法 子類調用父類的方法

    1、super從子類中調用父類的構造方法,this在同一類內調用其它方法
    2、this和super不能同時出現在一個構造函數裏面
    3、this或super調構造器時必須放在第一句,如果不放在第一句則可能對父類的數據多次初始化
    4、this和super都指的是對象,所以,均不可以在static環境下使用

  20. final、finally和finalize的區別
    答:final:是最終的意思,可以修飾類,成員變量,成員方法。
    修飾類,類不能被繼承;修飾方法,方法不能被重寫但是可以繼承;修飾變量,變量就變成了常量,只能被賦值一次,也可以繼承
    finally:是異常處理的一部分,用於釋放資源一般來說,代碼肯定會執行,特殊情況:在執行到finally之前jvm退出了
    finalize:是Object類的一個方法,用於垃圾回收

  21. 繼承時需要注意哪些?
    答:子類覆蓋父類方法時的要求:兩同、兩小、一大
    1.方法名和參數列表必須相同:子類==父類
    2.返回值類型和拋出異常:子類<=父類
    3.權限修飾符:子類>=父類
    子類無法覆蓋父類的:
    (1)構造方法 (2)static聲明的靜態方法 (3)private聲明的私有方法 (4)final聲明的最終方法

  22. JAVA 繼承 父類子類 內存分配圖解https://blog.csdn.net/erica_1230/article/details/76571936

  23. 子類在繼承父類後,實例化子類時,父類被實例化了嗎?父類的成員變量和方法存在於堆內存中的哪裏?
    答:子類在繼承父類後,如果父類中有非靜態非私有(普通)的成員變量,那麼在子類對象內存中給這些父類的成員變量再分配一些內存,並且子類對象內存中存的只是父類的一個引用,並沒有給父類實例化,通過super來調用子類對象內部的父類的特徵(屬性和方法)。(還不懂就看 JAVA 繼承 父類子類 內存分配圖解這一題的網址)

  24. 多態成員訪問的特點?
    答:比如有個類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();
    靜態方法:編譯看左邊,運行看左邊(靜態和類相關,算不上重寫,還是看左邊)

  25. 多態練習題

    // 無結果,有結果的在下面
    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
    	}
    } 
    
  26. String類對象創建內存圖
    在這裏插入圖片描述

  27. 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

  28. String、StringBuffer和StringBuilder的區別?
    答:String是不可變字符串,長度不可改變;StringBuffer是線程安全的可變字符序列,可以改變該對象的值和長度;StringBuilder是線程不安全的可變字符序列,但是執行速度快。

  29. 泛型在class文件中不存在,只是在編譯器存在。叫可擦除技術

  30. ArrayList、LinkedList和Vector的區別?
    答:ArrayList:底層-可變大小的數組;特點-有序、可重複(查詢快、增刪慢、線程不安全)
    遍歷的方式:(五種)1、數組:toArray()—>Object[]
    2、迭代器:Iterator
    3、特有的迭代器ListIterator
    4、一般for
    5、增強for
    LinkedList:底層-雙向鏈表;特點-有序、可重複(增刪快、查詢慢、線程不安全)
    Vector:底層-數組;特點-有序、可重複(線程安全)

  31. 泛型的使用

    1. 泛型概念:
      參數化類型。數據類型不同,數據類型的位置是變量,隨着變量值的不同,數據類型也不同。
    2. 泛型格式:<標識符>
      標識符一般用ETKV來進行表示,其中E通常用來表示Element 元素K Key 鍵V value 值T type 類,這些沒有實際含義。
    3. 泛型的分類
      1. 泛型類
        格式: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) {}
        }
        
      2. 泛型接口
        格式:①泛型具體,子類可以不帶泛型
        ②泛型不具體,子類也需要帶泛型
        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) {
        	}
        }
        
      3. 泛型方法
        格式: 權限修飾符 修飾符 <泛型> 返回值類型 方法名稱(參數){ }
        注意: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) {
        		
        	}
        }
        
      4. 通配符
        <? extends E>: 只能傳入E的子類
        <? super E> :只能傳入E的父類
  32. 樹的遍歷方式:

    1. 先序遍歷:根左右
    2. 中序遍歷:左根右
    3. 後序遍歷:左右根
  33. HashSet集合底層、特點、去重複問題
    答:底層是哈希表(由HashMap實現,是HashMap的key列),特點是不重複、無序,去重複:重寫equals()和hashCode()

  34. HashSet集合的存儲過程
    答:(簡答)首先通過hashCode()比較哈希碼值,根據哈希碼值推算出該對象在集合中的存儲位置,如果該位置上有對象,繼續走equals()比較兩個對象是否相等,如果相同不插入,不同就直接在該位置後面插入該元素對象。
    (詳細)1、首先通過對象的HashCode方法算出對象的哈希碼值,根據哈希碼值推算出該對象在集合中的存儲位置。2、如果算出來的存儲位置的索引值上有元素對象,這種現象稱爲哈希碰撞。需要存儲的元素對象就與該位置上已經存在的對象進行比較,通過equals判斷是否相等,如果相等不插入,否則在該位置後面插入該元素對象(jdk1.8之後該位置上如果插入的元素個數大於等於8個,則從鏈表形式改爲紅黑樹的形式)

  35. TreeSet集合底層、特點、去重複問題
    答:底層是紅黑樹(基於TreeMap),特點是不重複、無序、可排序,去重複:①實現Comparable< T>接口,重寫compareTo(T o)方法②創建一個類implements Comparator< T>,實現compare(T o1,T o2)方法

  36. TreeSet集合的存儲過程
    答:
    (1) 元素的自然排序:
    ① Comparable 接口 ,實現該接口的類,可以對該類所對應的集合進行排序,這種排序 稱爲元素的自然順序排序。
    ② 實現該接口的方法 :compareTo(T o)當這個方法的返回值 大於0 (對象在後) 小於0 (對象在前 ) 等於0 (相等)
    (2)TreeSet集合默認無參構造方法,按照元素的自然順序進行排序,要求存入該集合的元素自定義類的對象的所在類 必須要實現Comparable,實現接口中的方法:compareTo方法,否則會報異常 ClassCastException 類型轉換異常。

  37. LinkedHashSet集合
    答:該集合由哈希表與雙向鏈表組成,插入與存儲順序相同。一般用於購物車,商品歷史記錄。特點:有序 不重複

  38. Map集合的特點
    答:Map集合爲雙列集合,(1) 存儲的元素是鍵值對的形式(2)鍵不能重複,值可以重複。(3)一個鍵只對應一個值。

  39. 通過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);
    }
    
  40. HashMap、TreeMap、LinkedHashMap、HashTable的區別?
    答:HashMap底層數據結構是哈希表,線程不安全,效率高,允許有null的鍵和值,輸出是無序的;TreeMap底層數據結構是紅黑樹,線程不安全,允許有null的鍵和值,輸出是有序的,按照Key鍵的自然順序;HashTable底層數據結構是哈希表,線程安全,效率低,不允許有null的鍵和值;LinkedHashMap是Map接口的哈希表和鏈表實現,具有可預知的迭代順序

  41. 匿名內部類的注意事項
    在這裏插入圖片描述

  42. 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

  43. 反射的方法
    答:
    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): 方法的調用
  44. lambda表達式的寫法和實現
    答:格式
      有參數無返回的寫法:(參數) -> {方法體;} ;
      有返回值的寫法:(參數)->{return 返回值;}注意:只有返回語句時,省略大括號必須省略return。
    實現:存在函數式接口lambda表達纔可以使用,抽象類實現匿名內部類不可使用。
    函數式接口:接口中只有一個抽象方法的接口,函數式接口裏面可以有默認方法靜態方法,但是只有一個抽象方法

	interface  TL{
		public void fun();
		//靜態方法
		public static void fun1() {
			System.out.println("aaaa");
		}
		//默認方法
		default void fun2() {
			System.out.println("接口的默認方法");
		}
	}
  1. jdk1.8特性
    答:
    1. Consumer 消費型接口
      例:Consumer consumer = System.out::println;
      void accept(T t);
    2. Supplier 供給型接口
      例:Supplier supplier = () -> {return new Teacher();};
      T get();
    3. Function 函數型接口
      例:Function<String,String> func = (x) -> x.concat(“hello”);
      R apply(T t); Function<T,R> 參數爲T類型的,返回值爲R類型的
    4. Predicate 斷言型接口
      boolean test(T t);
    5. 方法引用:
      爲了進一步簡化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);
  1. Java中數組和集合的區別:
    答:
    ​1、數組的長度不可變,集合的長度可變
    2、數組既能存基本數據類型也能存引用數據類型,集合只能存儲引用數據類型
    3、數組只能存同一種數據類型(除非是Object []),集合可以存任意數據類型

  2. get和post的區別:
    答:
    更詳細

    1. GET提交的數據放在URL中,POST則不會。這點意味着GET更不安全(POST也不安全,因爲HTTP是明文傳輸抓包就能獲取數據內容,要想安全還得加密
    2. GET回退瀏覽器無害,POST會再次提交請求(GET方法回退後瀏覽器再緩存中拿結果,POST每次都會創建新資源)
    3. GET提交的數據在請求頭,大小有限制(是因爲瀏覽器對URL的長度有限制,GET本身沒有限制),POST提交的數據在請求體,大小沒有限制
  3. java的權限修飾符的訪問權限
    答:public是公共的,被public所修飾的成員可以在任何類中都能被訪問到。被public所修飾的成員能被所有的子類繼承下來。
    protected是受保護的,被protected所修飾的成員在同一個package或者不同的package中的子類都能訪問。被protected所修飾的成員也能被該類的所有子類繼承下來。
    default是默認的,即不寫任何修飾符,只有在同一個package中的子類才能訪問到父類中默認修飾的成員。被default所修飾的成員只能被該類所在同一個package中的子類所繼承下來。
    private是私有的,只能在當前類中被訪問到,它的作用域最小。

權限修飾符 當前類 同包 不同包子孫類 不同包類
public
protected
默認
private

49.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章