檢測“不應”與反射一起使用的構造函數

我有以下功能:

@SuppressWarnings("unchecked")
public static <T> T createInstance(String className, Object... args) {
    try {
        Class<?> clazz = Class.forName(className);
        Class<?>[] parameterTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
        return (T) clazz.getDeclaredConstructor(parameterTypes).newInstance(args);
    } catch (Exception e) {
        throw new RuntimeException("Error", e);
    }
}

該函數應該獲得一個類名(如String),加載它,如果找到了與Object... args匹配的構造函數,則創建此類對象的新實例。

這段代碼可以工作,但它可能會在@HotSpotIntrinsicCandidate方法上被調用。例如,如果調用者這樣做:

String str = createInstance("java.lang.String", "Some value");

... 然后函數將調用類java.lang.String的構造函數:

@HotSpotIntrinsicCandidate
public String(String original)

我對@HotSpotIntrinsicCandidate構造函數的理解是,JVM將對這些構造函數進行特殊處理,例如,這就是為什么我可以做String str = "some string";,但我不能做MyObject myObj = "some string"(假設MyObject類有一個在參數中采用String的構造函數)。

同時,我有點理解這些構造函數是“不可靠的”,因為它們嚴格依賴于JVM人員的決定。例如,該代碼也適用于裝箱原語,例如Integer

Integer myInt = createInstance("java.lang.Integer", "3");

... 但是自從Java 9以來,這些構造函數就被棄用了(這些類的新@HotSpotIntrinsicCandidatevalueOf(...)方法,它們不再是構造函數)。

我的感覺是,我應該拒絕對@Deprecated@HotSpotIntrinsicCandidate構造函數的任何請求,以避免調用方在某個可能有一天被棄用的東西上構建積木。

  • 有人能證實(或否認)我的假設嗎?
  • 假設我的直覺是正確的,我可以輕松地getAnnotation(Deprecated.class)在我檢索的Constructor上(因為這個注釋是公共的),但我不能getAnnotation(HotSpotIntrinsicCandidate.class),因為這個注釋是package-private到jdk.internal。如果是這樣的話,我怎樣才能檢測出我應該拒絕構建的所有類?
? 最佳回答:

我對@HotspotIntrinsicAndidate構造函數的理解是

Completely wrong.

HotSpot指的是JVM將以極其愚蠢/緩慢的速度運行所有java代碼,甚至比您想象的還要慢,因為它還做了大量看似毫無意義的簿記工作(這種“如果”分支的頻率是以一種方式還是以另一種方式——讓我們無緣無故地計算一下)。

... 因為有了所有這些簿記,JVM可以很容易地識別出消耗99%資源的1%代碼,然后將花費相當多的時間(并使用它所做的所有簿記)來生成一些經過微調的機器代碼,專門用于您運行的確切硬件,并針對迄今為止觀察到的情況(即簿記)進行優化以最快地運行。現在你有了極快的代碼。考慮到這1%的代碼實際上占用了99%的資源,這就是JVM速度非常快的原因。“重寫”的過程是熱點。這純粹是一件Java-The-Virtual-Machine的事情。Java-The-Language沒有熱點,不知道它是什么,你說的是一種語言功能,因此-不,這根本不是@hospotintrisccandidate的意思。

之所以可以編寫String x = "hello",是因為java語言規范規定了這一點。就這樣。這是唯一的原因。因為它在規范中是硬編碼的(這和為什么你可以寫Integer i = 5;是一樣的,因為'5'在JLS中被寫為一個概念,如果代碼沒有編譯,但是將一個原語轉換成匹配的包裝類型會使它工作,那么假設程序員打算這么做,并編譯它,就像它說Integer.valueOf(5)取而代之的是,這被稱為“自動裝箱”,也寫在JLS中,這使其起作用。同樣,@HotspotIntrinsicCandidate與此無關)。

@HIC指的是一個JVM實現可以自由地擁有一個"pre-written“經過微調的機器代碼版本,可以直接在JVM實現本身中使用,JVM運行人員應該尋找,然后使用這樣的東西,如果它可用的話。這并不能保證(但大多數JVM實現都是這樣工作的;記錄“頻率”并沒有多大意義)j.l.StringhashCode()方法已被調用——只要你在hashmaps中插入字符串,就意味著它將被大量調用。不妨“預編譯”它的機器代碼,并將其直接注入java.exe。為什么要等,對嗎?

考慮到這純粹是一個優化動作,它的存在與否絕對不會對公開該構造函數是否“是個好主意”產生任何影響。

我的感覺是,我應該拒絕對構造函數的任何請求,這些請求要么是@Deprecated,要么是@Deprecated

貶低是一種怪獸。它被用于許多不同的事情。不使用這樣的構造函數沒有什么特別的意義——當然,它們將來可能會消失,但不推薦使用標記還有其他原因(有時只是“這種方法是個壞主意,因為大多數使用它的人都感到困惑”。例如,j.u.DategetYear()方法被不推薦使用。我很樂意以1000比1的幾率打賭,它在10年后仍然存在。它不會有任何用途。使用它只是個壞主意。

這讓我們。。。

這是個壞主意,句號。

班級<?>[]參數類型=Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);

這不管用。

Trivial example:

class Example {
  public Example(Number n) {
    System.out.println("Hello!");
  }
}

...

createInstance("com.foo.Example", 5);

上述方法不起作用!!

那是因為在5上調用.getClass()會得到java.lang.Integer.class。這與Number(它是它的一個子類)完全“兼容”——new Example(5)工作正常。然而,getConstructor()會精確地搜索您所要求的內容,這是一個接受1整數的構造函數。那是不存在的。你有一個構造函數,它接受整數的超類型。

解決這個問題的唯一方法是使用.getDeclaredConstructors(),遍歷所有參數,并在每個參數上使用.isSubclass和友元,如果愿意,還可以添加代碼來處理varargs調用,然后使用它。

這速度太慢了。

更一般地說,這種方法意味著您要考慮laissez-fairecompiler-less語言(通常稱為“腳本語言”)最差的方面,以及java最差的方面,同時忽略最好的部分。這有什么意義?

我打賭你正在尋找以下幾種選擇:

構建和編譯infra比您想象的要好得多

有很多工具非常聰明,可以知道需要編譯哪些java代碼(即只編譯您更改的內容),并且只編譯這些內容。例如,eclipse(編輯器)將自動地、幾乎即時地持續編譯您的所有內容。如果這是為了避免compile-build循環,那么沒有必要這樣做。

您甚至可以運行java foo.java,JVM將自動編譯并運行它,用于普通的one-file項目。

有java-esque種腳本語言

如果你想的話,你可以在java中運行javascript。GraalVM項目有一個只運行javascript的java庫。為什么不用呢?如果您希望語法特別是java-like,可以使用beanshell和groovy。

有模塊系統和動態裝載機

您可以在plain jane java(例如,在javadocs或OSGi項目中查找ClassLoader類)中設置一個系統,該系統可以在運行的JVM中運行'live-reload類。如果目標是啟動JVM,然后在它運行時手動“在其中編程”,那么就可以使用它們。

調試器很棒

調試器可以插入運行的JVM,即使在Internet連接上,如果需要的話,只需在斷點thread中間運行按需鍵入的代碼即可。例如,在eclipse中,只要在任何地方設置一個斷點,運行這個東西(單擊在調試模式下運行它的“bug”按鈕),然后打開調試shell并鍵入任何需要的內容。你甚至可以訪問局部變量,當斷點被擊中時,它們會有任何值。如果愿意,可以對服務器上運行的“實時代碼”執行此操作。

There's JSP

我強烈反對這種做法,但JSP是一種可以在.jsp文件中的HTML中插入java代碼,并讓web服務器運行它的東西。它會處理所有的事情——檢測它的變化,(重新)編譯它,并運行它。您可以簡單地編輯JSP文件,然后重新加載一個頁面,現在就可以看到新的內容了。

有些要求你告訴它:是的,請檢查更改和re-compile。

主站蜘蛛池模板: 少妇人妻精品一区二区三区| 国产精品一区二区电影| 色一情一乱一伦一区二区三欧美| 国产传媒一区二区三区呀| 久久精品黄AA片一区二区三区| 精品人妻一区二区三区四区在线| 国产一区二区中文字幕| 人妻内射一区二区在线视频| 伊人久久精品无码麻豆一区| 福利一区二区三区视频在线观看 | 一区二区三区四区无限乱码| 射精专区一区二区朝鲜| 久久免费精品一区二区| 亚洲高清成人一区二区三区| 午夜视频一区二区三区| 国产日本一区二区三区| 亚洲国产美国国产综合一区二区| 一区二区三区www| AV怡红院一区二区三区| 精品国产日韩亚洲一区| 国产观看精品一区二区三区 | 激情内射亚洲一区二区三区爱妻| 一区二区在线视频免费观看| 国产免费av一区二区三区| 亚洲欧美日韩一区二区三区 | 日本免费一区二区三区最新vr| 无码国产精品一区二区免费式直播 | 亚洲av日韩综合一区二区三区| 91精品一区二区综合在线 | 爆乳熟妇一区二区三区霸乳| 一区二区手机视频| 一区免费在线观看| 久久精品国产一区二区 | 国产成人精品一区二区A片带套| 无码国产精品一区二区免费式直播| 中文字幕日韩一区二区不卡| 日韩成人无码一区二区三区| 精品日韩一区二区三区视频| 国产伦理一区二区三区| 精品视频一区二区三区四区| 相泽南亚洲一区二区在线播放 |