java基礎一點也不基礎

(新建的羣1039047324,歡迎對技術感興趣的朋友加入,羣內只聊技術,分享工作中容易踩的坑,以及如何避免踩坑,分享最新架構視頻)

1 創建對象的有哪幾種方式
創建對象是否一定要通過構造器,當然不是。

1)  通過new 創建對象。這種方法需要用到構造器

    Demo demo1=new Demo();Java String類爲什麼是final的
    Demo demo2=new Demo(1,"有參構造器");

2) 通過反射 newInstance()創建對象。這種方法用到構造器

  Demo demo2=(Demo) Class.forName("Demo").newInstance();

3) 通過object類的clone方法。需要實現Cloneable接口,重寫object類的clone方法。無論何時我們調用一個對象的clone方法,jvm就會創建一個新的對象,將前面對象的內容全部拷貝進去。用clone方法創建對象並不會調用任何構造函數。

  Demo demo4=(Demo) demo2.clone();

4) 反序列化。java 中常常進行 JSON 數據跟 Java 對象之間的轉換,即序列化和反序列化。
當我們序列化和反序列化一個對象,JVM會給我們創建一個單獨的對象,在反序列化時,JVM創建對象並不會調用任何構造函數。爲了反序列化一個對象,我們需要讓我們的類實現Serializable接口,雖然該接口沒有任何方法。不會調用任何構造函數。

2 Java String類爲什麼是final的 

  1. 爲了實現字符串池
  2. 爲了線程安全
  3. 爲了實現String可以創建HashCode不可變性

    首先你要理解final的用途,在分析String爲什麼要用final修飾,final可以修飾類,方法和變量,並且被修飾的類或方法,被final修飾的類不能被繼承,即它不能擁有自己的子類,被final修飾的方法不能被重寫, final修飾的變量,無論是類屬性、對象屬性、形參還是局部變量,都需要進行初始化操作。

在瞭解final的用途後,在看String爲什麼要被final修飾:主要是爲了”安全性“和”效率“的緣故。

final修飾的String,代表了String的不可繼承性,final修飾的char[]代表了被存儲的數據不可更改性。但是:雖然final代表了不可變,但僅僅是引用地址不可變,並不代表了數組本身不會變,請看下面圖片。

 

如果字符串是可變的,那麼會引起很嚴重的安全問題。譬如,數據庫的用戶名、密碼都是以字符串的形式傳入來獲得數據庫的連接,或者在socket編程中,主機名和端口都是以字符串的形式傳入。因爲字符串是不可變的,所以它的值是不可改變的,否則黑客們可以鑽到空子,改變字符串指向的對象的值,造成安全漏洞。


    因爲字符串是不可變的,所以是多線程安全的,同一個字符串實例可以被多個線程共享。這樣便不用因爲線程安全問題而使用同步。字符串自己便是線程安全的。


    因爲字符串是不可變的,所以在它創建的時候HashCode就被緩存了,不需要重新計算。這就使得字符串很適合作爲Map中的鍵,字符串的處理速度要快過其它的鍵對象。這就是HashMap中的鍵往往都使用字符串。


   字符串常量池,在大量使用字符串的情況下,可以節省內存空間,提高效率,String不可變性是最基本的一個前置條件。

 

3 反射中,Class.forName和classloader的區別?

Java中class是如何加載到JVM中的:
1.class加載到JVM中有三個步驟
    裝載:(loading)找到class對應的字節碼文件。
    連接:(linking)將對應的字節碼文件讀入到JVM中。
    初始化:(initializing)對class做相應的初始化動作。
2.Java中兩種加載class到JVM中的方式
    1:Class.forName(“className”);
        其實這種方法調運的是:Class.forName(className, true, ClassLoader.getCallerClassLoader())方法
        參數一:className,需要加載的類的名稱。
        參數二:true,是否對class進行初始化(需要initialize)
        參數三:classLoader,對應的類加載器
    2:ClassLoader.laodClass(“className”);
        其實這種方法調運的是:ClassLoader.loadClass(name, false)方法
        參數一:name,需要加載的類的名稱
        參數二:false,這個類加載以後是否需要去連接(不需要linking)
        
    兩種方式的區別
        forName("")得到的class是已經初始化完成的
        loadClass("")得到的class是還沒有連接的
        一般情況下,這兩個方法效果一樣,都能裝載Class。
        但如果程序依賴於Class是否被初始化,就必須用Class.forName(name)了。

比如:連接數據庫

    java使用JDBC連接數據庫時候,我們首先需要加載數據庫驅動。
    Class.forName(“com.mysql.jdbc.Driver”);//通過這種方式將驅動註冊到驅動管理器上
    Connection conn = DriverManager.getConnection(“url”,“userName”,“password”);//通過驅動管理器獲得相應的連接
    查看com.mysql.jdbc.Driver源碼:

public class Driver extends NonRegisteringDriver
  implements java.sql.Driver
{
    //注意,這裏有一個static的代碼塊,這個代碼塊將會在class初始化的時候執行
  static
  {
    try
    {
        //將這個驅動Driver註冊到驅動管理器上
      DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
      throw new RuntimeException(“Can’t register driver!”);
    }
  }
}

Class.forName(“com.mysql.jdbc.Driver”)方法以後,他會進行class的初始化,執行static代碼塊。
    也就是說class初始化以後,就會將驅註冊到DriverManageer上,之後才能通過DriverManager去獲取相應的連接。
    但是要是我們使用ClassLoader.loadClass(com.mysql.jdbc.Driver)的話,不會link,更也不會初始化class。
    相應的就不會回將Driver註冊到DriverManager上面,所以肯定不能通過DriverManager獲取相應的連接。

4 java反射原理 (反射是框架設計的靈魂)

1 ) JAVA反射機制是在運行狀態中

對於任意一個類,都能夠知道這個類的所有屬性和方法;

對於任意一個對象,都能夠調用它的任意一個方法和屬性;

這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

2) 反射提供的功能:

在運行時判斷任意一個對象所屬的類
    在運行時構造任意一個類的對象
    在運行時判斷任意一個類所具有的成員變量和方法
    在運行時調用任意一個對象的方法
(要想解剖一個類,必須先要獲取到該類的字節碼文件對象(class)。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節碼文件對應的Class類型的對象.)

3) 關於class對象和這個class類

Class對象的由來是將class文件讀入內存,併爲之創建一個Class對象

4) class類 :代表一個類,是Java反射機制的起源和入口
用於獲取與類相關的各種信息, 提供了獲取類信息的相關方法
    Class類繼承自Object類
    Class類是所有類的共同的圖紙
    每個類有自己的對象,同時每個類也看做是一個對象,有共同的圖紙Class,存放類的結構信息,能夠通過相應方法取出相應的信息:類的名字、屬性、方法、構造方法、父類和接口。

Class 類的實例表示正在運行的 Java 應用程序中的類和接口。也就是jvm中有N多的實例每個類都有該Class對象。(包括基本數據類型)
Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理創建,JVM已經幫我們創建好了。

沒有公共的構造方法,方法共有64個太多了。

5) 反射的使用場景
    Java編碼時知道類和對象的具體信息,此時直接對類和對象進行操作即可,無需反射。如果編碼時不知道類或者對象的具體信息,此時應該使用反射來實現。比如類的名稱放在XML文件中,屬性和屬性值放在XML文件中,需要在運行時讀取XML文件,動態獲取類的信息。在編譯時根本無法知道該對象或類可能屬於哪些類,程序只依靠運行時信息來發現該對象和類的真實信息。

6) 獲取反射入口(class對象)的三種方法

要想操作反射,必須先拿到反射的入口

1,通過通過Class.forName("全類名")

 2,對象.getClass()

3,類名.class (任何數據類型(包括基本數據類型)都有一個“靜態”的class屬性)

注意:在運行期間,一個類,只有一個Class對象產生。

3種方式常用第1種,第2種對象都有了還要反射干什麼。第3種需要導入類的包,依賴太強,不導包就拋編譯錯誤。一般都第1種,一個字符串可以傳入也可寫在配置文件中等多種方法。

 

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