欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java在運(yùn)行時(shí)識(shí)別類(lèi)型信息的方法詳解

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

前言

在日常的學(xué)習(xí)工作當(dāng)中,有一些知識(shí)是我們?cè)谧x書(shū)的時(shí)候就能夠習(xí)得;但有一些知識(shí)不是的,需要在實(shí)踐的時(shí)候才能得到真知——這或許就是王陽(yáng)明提倡的“知行合一”。

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

01 Class類(lèi)

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

package com.cmower.java_demo.fifteen;

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

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

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
 }
}

當(dāng)我們創(chuàng)建了作者對(duì)象wanger后,就可以通過(guò)wanger.getClass()獲取wanger的Class對(duì)象,通過(guò)c1.getName()可獲得wanger對(duì)象的類(lèi)名。

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

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的對(duì)象引用wanger向上轉(zhuǎn)型為Author,wanger的Class對(duì)象類(lèi)型依然是Writer(通過(guò)輸出結(jié)果可以判定)。這也就是說(shuō),Java能夠在運(yùn)行時(shí)自動(dòng)識(shí)別類(lèi)型的信息,它不會(huì)因?yàn)閣anger的引用類(lèi)型是Author而丟失wanger真正的類(lèi)型信息(Writer)。Java是怎么做到這一點(diǎn)呢?

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

一旦Class對(duì)象加載成功,就可以用它來(lái)創(chuàng)建這種類(lèi)型的所有對(duì)象。這也就是說(shuō),每個(gè)對(duì)象在運(yùn)行時(shí)都會(huì)有對(duì)應(yīng)的Class對(duì)象,這個(gè)Class對(duì)象包含了這個(gè)對(duì)象的類(lèi)型信息。因此,我們能夠通過(guò)Class對(duì)象知道某個(gè)對(duì)象“真正”的類(lèi)型,并不會(huì)因?yàn)橄蛏限D(zhuǎn)型而丟失。

02 獲取Class對(duì)象的其他方式

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

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)當(dāng)使用.class來(lái)獲取Class對(duì)象時(shí),不會(huì)自動(dòng)地初始化該Class對(duì)象,初始化被延遲到了對(duì)靜態(tài)方法或者非final靜態(tài)域進(jìn)行首次引用時(shí)才執(zhí)行。這樣做不僅更簡(jiǎn)單,而且更安全,因?yàn)樗诰幾g時(shí)就會(huì)受到檢查(因此不需要置于try語(yǔ)句塊中)。

2)Class.forName會(huì)自動(dòng)地初始化該Class對(duì)象,但需要指定類(lèi)名,并且需要置于try語(yǔ)句塊中。

03 Class類(lèi)提供的常用方法

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

我們還可以利用Class類(lèi)提供的newInstance()方法來(lái)創(chuàng)建相應(yīng)類(lèi)的對(duì)象,比如:

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();
}

由于我們?cè)趧?chuàng)建Class對(duì)象c2時(shí)沒(méi)有使用泛型,所以newInstance()返回的對(duì)象類(lèi)型需要強(qiáng)轉(zhuǎn)為Writer。我們可以在此基礎(chǔ)上進(jìn)行改進(jìn),示例如下:

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 反射

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

甚至,我們還可以通過(guò)getDeclaredFields()獲取更多字段,包括公共、受保護(hù)、默認(rèn)(包)訪問(wèn)和私有字段,但不包括繼承字段。對(duì)應(yīng)的,getDeclaredMethods()用來(lái)獲取更多方法。示例如下:

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("很多很多錢(qián)");
 }
}

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();
  }

 }
}

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

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

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

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ù)專家聊了聊,問(wèn)他了幾個(gè)很傻的問(wèn)題:“‘運(yùn)行時(shí)’是什么意思?是站在Java虛擬機(jī)的角度,還是程序員的角度?”

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

但寫(xiě)作的好處就在于此,在向讀者解釋“Java如何在運(yùn)行時(shí)識(shí)別類(lèi)型信息”的過(guò)程中,我的思路逐漸地清晰了起來(lái)——這真是一個(gè)自我提升的好辦法!

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

相關(guān)文章

  • Java中LinkedHashSet的源碼剖析

    Java中LinkedHashSet的源碼剖析

    這篇文章主要介紹了Java中LinkedHashSet的源碼剖析,LinkedHashSet是HashSet的子類(lèi),LinkedHashSet底層是一個(gè)LinkedHashMap,底層維護(hù)了一個(gè)數(shù)組+雙向鏈表,需要的朋友可以參考下
    2023-09-09
  • SpringAOP中的通知Advice解析

    SpringAOP中的通知Advice解析

    這篇文章主要介紹了SpringAOP中的通知Advice解析,AOP 中的通知是基于連接點(diǎn)業(yè)務(wù)邏輯的一種增強(qiáng),Spring AOP 可以基于 XML 方式和基于注解方式定義,只是寫(xiě)法不同,這里只使用注解的方式來(lái)講解通知的詳細(xì)用法,需要的朋友可以參考下
    2023-09-09
  • 基于Java編寫(xiě)emoji表情處理工具類(lèi)

    基于Java編寫(xiě)emoji表情處理工具類(lèi)

    這篇文章主要為大家詳細(xì)介紹了如何基于Java編寫(xiě)一個(gè)emoji表情處理工具類(lèi),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • Java中BigDecimal類(lèi)的add()的使用詳解

    Java中BigDecimal類(lèi)的add()的使用詳解

    這篇文章主要介紹了Java中BigDecimal類(lèi)的add()的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java 使用poi把數(shù)據(jù)庫(kù)中數(shù)據(jù)導(dǎo)入Excel的解決方法

    Java 使用poi把數(shù)據(jù)庫(kù)中數(shù)據(jù)導(dǎo)入Excel的解決方法

    本篇文章介紹了,Java 使用poi把數(shù)據(jù)庫(kù)中數(shù)據(jù)導(dǎo)入Excel的解決方法。需要的朋友參考下
    2013-05-05
  • Java創(chuàng)建線程三種方式的優(yōu)缺點(diǎn)

    Java創(chuàng)建線程三種方式的優(yōu)缺點(diǎn)

    今天小編就為大家分享一篇關(guān)于Java創(chuàng)建線程三種方式的優(yōu)缺點(diǎn),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • java實(shí)現(xiàn)獲取安卓設(shè)備里已安裝的軟件包

    java實(shí)現(xiàn)獲取安卓設(shè)備里已安裝的軟件包

    本文給大家介紹的是如何獲取設(shè)備中已經(jīng)安裝的應(yīng)用軟件包的代碼,其核心方法原理很簡(jiǎn)單,我們通過(guò)Android中提供的PackageManager類(lèi),來(lái)獲取手機(jī)中安裝的應(yīng)用程序信息
    2015-10-10
  • JAVA JNI函數(shù)的注冊(cè)過(guò)程詳細(xì)介紹

    JAVA JNI函數(shù)的注冊(cè)過(guò)程詳細(xì)介紹

    這篇文章主要介紹了JAVA JNI函數(shù)的注冊(cè)過(guò)程詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • idea2020最新版配置maven的方法

    idea2020最新版配置maven的方法

    這篇文章主要介紹了idea2020最新版配置maven的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java Testcontainers庫(kù)實(shí)現(xiàn)測(cè)試功能

    Java Testcontainers庫(kù)實(shí)現(xiàn)測(cè)試功能

    這篇文章主要介紹了Java Testcontainers庫(kù)實(shí)現(xiàn)測(cè)試功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09

最新評(píng)論