最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java在運行時識別類型信息的方法詳解

 更新時間:2019年01月25日 15:06:02   作者:沉默王二  
這篇文章主要給大家介紹了關(guān)于Java在運行時識別類型信息的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考借鑒,下面來一起看看吧

前言

在日常的學習工作當中,有一些知識是我們在讀書的時候就能夠習得;但有一些知識不是的,需要在實踐的時候才能得到真知——這或許就是王陽明提倡的“知行合一”。

在Java中,并不是所有的類型信息都能在編譯階段明確,有一些類型信息需要在運行時才能確定,這種機制被稱為RTTI,英文全稱為Run-Time Type Identification,即運行時類型識別,有沒有一點“知行合一”的味道?運行時類型識別主要由Class類實現(xiàn)。

01 Class類

在Java中,我們常用“class”(首字母為小寫的c)關(guān)鍵字來定義一個類,說這個類是對某一類對象的抽象。你比如說王二是一個網(wǎng)絡知名作者,我們可以這樣簡單地定義作者類:

package com.cmower.java_demo.fifteen;

class Author {
 private String pen_name;
 private String real_name;
}

現(xiàn)在,我們想知道Writer這個類本身的一些信息(比如說類名),該怎么辦呢?這時候就需要用到“Class”(首字母為大寫的C)類,該類包含了與類有關(guān)的信息。請看以下代碼:

public class Test {
 public static void main (String [] args) {
  Author wanger = new Author();
  Class c1 = wanger.getClass();
  System.out.println(c1.getName());
  //輸出 com.cmower.java_demo.fifteen.Author
 }
}

當我們創(chuàng)建了作者對象wanger后,就可以通過wanger.getClass()獲取wanger的Class對象,通過c1.getName()可獲得wanger對象的類名。

想象一下,經(jīng)過五年的刻意練習,王二從一名寫作者晉升為一名作家了。我們用代碼來假裝一下:

package com.cmower.java_demo.fifteen;

class Author {
 private String pen_name;
 private String real_name;
}

class Writer extends Author {
 private String honour;
}

public class Test {
 public static void main (String [] args) {
  Author wanger = new Writer();
  Class c1 = wanger.getClass();
  System.out.println(c1.getName());
  //輸出 com.cmower.java_demo.fifteen.Writer
 }
}

在上例中,即使我們將Writer的對象引用wanger向上轉(zhuǎn)型為Author,wanger的Class對象類型依然是Writer(通過輸出結(jié)果可以判定)。這也就是說,Java能夠在運行時自動識別類型的信息,它不會因為wanger的引用類型是Author而丟失wanger真正的類型信息(Writer)。Java是怎么做到這一點呢?

當Java創(chuàng)建某個類的對象,比如Writer類對象時,Java會檢查內(nèi)存中是否有相應的Class對象。如果內(nèi)存中沒有相應的Class對象,那么Java會在.class文件中尋找Writer類的定義,并加載Writer類的Class對象。

一旦Class對象加載成功,就可以用它來創(chuàng)建這種類型的所有對象。這也就是說,每個對象在運行時都會有對應的Class對象,這個Class對象包含了這個對象的類型信息。因此,我們能夠通過Class對象知道某個對象“真正”的類型,并不會因為向上轉(zhuǎn)型而丟失。

02 獲取Class對象的其他方式

在使用getClass()方法獲取一個類的Class對象時,我們必須要先獲取這個類的對象,比如上面提到的wanger。如果我們之前沒有獲取這個類的對象,就需要用另外兩種方式來獲取類的Class對象:

Class c2 = Writer.class;
System.out.println(c2.getName());

try {
 Class c3 = Class.forName("com.cmower.java_demo.fifteen.Writer");
 System.out.println(c3.getName());
} catch (ClassNotFoundException e) {
 e.printStackTrace();
}

1)當使用.class來獲取Class對象時,不會自動地初始化該Class對象,初始化被延遲到了對靜態(tài)方法或者非final靜態(tài)域進行首次引用時才執(zhí)行。這樣做不僅更簡單,而且更安全,因為它在編譯時就會受到檢查(因此不需要置于try語句塊中)。

2)Class.forName會自動地初始化該Class對象,但需要指定類名,并且需要置于try語句塊中。

03 Class類提供的常用方法

Class類為我們提供了一些非常有用的方法,比如說getName()用來返回類名,getPackage()返回類所在的包名。

我們還可以利用Class類提供的newInstance()方法來創(chuàng)建相應類的對象,比如:

Class c2 = Writer.class;
System.out.println(c2.getName());

try {
 Writer wangsan = (Writer) c2.newInstance();
 System.out.println(wangsan);
 // 輸出:com.cmower.java_demo.fifteen.Writer@7852e922
} catch (InstantiationException | IllegalAccessException e1) {
 e1.printStackTrace();
}

由于我們在創(chuàng)建Class對象c2時沒有使用泛型,所以newInstance()返回的對象類型需要強轉(zhuǎn)為Writer。我們可以在此基礎(chǔ)上進行改進,示例如下:

Class<Writer> c4 = Writer.class;
System.out.println(c4.getName());

try {
 Writer wangsan = c4.newInstance();
 System.out.println(wangsan);
 // 輸出:com.cmower.java_demo.fifteen.Writer@7852e922
} catch (InstantiationException | IllegalAccessException e1) {
 e1.printStackTrace();
}

04 反射

我們還可以通過getFields()獲取所有public修飾的字段,通過getMethods()返回所有public修飾的方法。

甚至,我們還可以通過getDeclaredFields()獲取更多字段,包括公共、受保護、默認(包)訪問和私有字段,但不包括繼承字段。對應的,getDeclaredMethods()用來獲取更多方法。示例如下:

package com.cmower.java_demo.fifteen;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Author {
 private String pen_name;
 private String real_name;
}

class Writer extends Author {
 private String honour;

 private void makeMoney() {
  System.out.println("很多很多錢");
 }
}

public class Test {
 public static void main(String[] args) {

  Class<Writer> c4 = Writer.class;
  System.out.println(c4.getName());

  try {
   Writer wangsan = c4.newInstance();
   System.out.println(wangsan);

   Field[] fields = c4.getDeclaredFields();
   for (Field field : fields) {
    System.out.println(field.getName());
   }

   Method[] methods = c4.getDeclaredMethods();
   for (Method method : methods) {
    System.out.println(method.getName());
   }
  } catch (InstantiationException | IllegalAccessException e1) {
   e1.printStackTrace();
  }

 }
}

上面的例子其實涉及到了反射,F(xiàn)ield、Method(還有例子中未提到的Constructor)都來自java.lang.reflect類庫。Class類與java.lang.reflect類庫一起對反射的概念進行了支持。

有時候,我們需要從磁盤文件或網(wǎng)絡文件中讀取一串字節(jié)碼,并把它轉(zhuǎn)換成一個類,這時候就需要用到反射。最常見的典型例子就是將一串JSON字符串(在網(wǎng)絡傳輸中最初的形態(tài)可能是字節(jié)數(shù)組)反射為對應類型的對象。

阿里巴巴提供的FastJSON提供了 toJSONString() 和 parseObject() 方法來將 Java 對象與 JSON 相互轉(zhuǎn)換。調(diào)用toJSONString方法即可將對象轉(zhuǎn)換成 JSON 字符串,parseObject 方法則反過來將 JSON 字符串轉(zhuǎn)換成對象。FastJSON的內(nèi)部其實用的就是反射機制。

package com.cmower.common.util;

import java.io.UnsupportedEncodingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.alibaba.fastjson.JSON;

@SuppressWarnings("all")
public class JsonUtil {
 private static Log logger = LogFactory.getLog("json");

 public static byte[] objectToByte(Object obj) throws UnsupportedEncodingException {
  String jsonStr = JSON.toJSONString(obj);
  logger.debug("序列化后數(shù)據(jù):" + jsonStr);
  return jsonStr.getBytes("UTF-8");
 }

 public static <T> T byteToObject(byte[] data, Class<T> obj) throws UnsupportedEncodingException {
  String objectString = new String(data, "UTF-8");
  logger.debug("反序列化后數(shù)據(jù) : " + objectString);
  return JSON.parseObject(objectString, obj);
 }
 
 public static <T> Object stringToObject(String data, Class<T> obj) throws UnsupportedEncodingException {
  logger.debug("反序列化后數(shù)據(jù) : " + data);
  return JSON.parseObject(data, obj);
 }
}

05 總結(jié)

為了完成這篇文章,我特意和青苗谷的一名技術(shù)專家聊了聊,問他了幾個很傻的問題:“‘運行時’是什么意思?是站在Java虛擬機的角度,還是程序員的角度?”

他給了我很好的解釋和啟發(fā),我不由覺得非常的慚愧,作為一名年紀頗長的Java學習者,竟然對理論知識薄弱到令人發(fā)指的地步——不知道你是否也有這樣的困惑?

但寫作的好處就在于此,在向讀者解釋“Java如何在運行時識別類型信息”的過程中,我的思路逐漸地清晰了起來——這真是一個自我提升的好辦法!

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • java開源調(diào)度如何給xxljob加k8s執(zhí)行器

    java開源調(diào)度如何給xxljob加k8s執(zhí)行器

    這篇文章主要介紹了java開源調(diào)度如何給xxljob加一個k8s執(zhí)行器,?xxljob?在設計上,抽象出了執(zhí)行器的接口,所以實現(xiàn)一個語言的執(zhí)行器并不復雜,這里主要探索下,如何利用k8s的pod?的能力,使用?xxljob?調(diào)度?pod?運行,實現(xiàn)一個通用的和語言無關(guān)的執(zhí)行器
    2022-02-02
  • spring cloud 分布式鏈路追蹤的方法

    spring cloud 分布式鏈路追蹤的方法

    這篇文章主要介紹了spring cloud 分布式鏈路追蹤的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • 談談Spring AOP中@Aspect的高級用法示例

    談談Spring AOP中@Aspect的高級用法示例

    在Spring AOP中目前只有執(zhí)行方法這一個連接點,下面這篇文章主要給大家介紹了關(guān)于Spring AOP中@Aspect的高級用法的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧
    2018-08-08
  • Dubbo負載均衡策略介紹

    Dubbo負載均衡策略介紹

    負載均衡改善了跨多個計算資源(例如計算機,計算機集群,網(wǎng)絡鏈接,中央處理單元或磁盤驅(qū)動的的工作負載分布。負載平衡旨在優(yōu)化資源使用,最大化吞吐量,最小化響應時間,并避免任何單個資源的過載
    2022-09-09
  • 實例詳解Java8函數(shù)式接口

    實例詳解Java8函數(shù)式接口

    本文給大家分析了Java8默認方法和函數(shù)式接口實例其它創(chuàng)建方式,需要的朋友跟著學習下吧。
    2017-11-11
  • SpringBoot從配置文件中獲取屬性的四種方法總結(jié)

    SpringBoot從配置文件中獲取屬性的四種方法總結(jié)

    這篇文章主要介紹了SpringBoot從配置文件中獲取屬性的四種方法總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • IntelliJ IDEA之高效代碼插件RainBow Brackets詳解

    IntelliJ IDEA之高效代碼插件RainBow Brackets詳解

    這篇文章主要介紹了IntelliJ IDEA之高效代碼插件RainBow Brackets詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Java中Array、List、ArrayList的區(qū)別及說明

    Java中Array、List、ArrayList的區(qū)別及說明

    這篇文章主要介紹了Java中Array、List、ArrayList的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java實現(xiàn)學生選課管理系統(tǒng)

    Java實現(xiàn)學生選課管理系統(tǒng)

    這篇文章主要為大家詳細介紹了Java實現(xiàn)學生選課管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • springboot中使用redis由淺入深解析

    springboot中使用redis由淺入深解析

    這篇文章主要由淺入深為大家介紹了springboot中使用redis的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11

最新評論

建湖县| 洱源县| 平乡县| 衡阳市| 大同市| 明光市| 互助| 旬阳县| 九龙坡区| 绿春县| 临朐县| 伽师县| 竹北市| 阿克陶县| 惠东县| 岳普湖县| 武功县| 武安市| 乐昌市| 尼勒克县| 玉屏| 田林县| 旺苍县| 军事| 西峡县| 施甸县| 贵德县| 平罗县| 台中市| 陕西省| 凭祥市| 延长县| 深圳市| 通州市| 新疆| 长顺县| 大埔县| 临夏县| 安康市| 阿拉善盟| 阳谷县|