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

Java使用MethodHandle來(lái)替代反射,提高性能問(wèn)題

 更新時(shí)間:2025年05月29日 16:59:34   作者:禿了也弱了。  
這篇文章主要介紹了Java使用MethodHandle來(lái)替代反射,提高性能問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、認(rèn)識(shí)MethodHandle

1、簡(jiǎn)介

Java從最初發(fā)布時(shí)就支持反射,通過(guò)反射可以在運(yùn)行時(shí)獲取類(lèi)型信息,但其有個(gè)缺點(diǎn)就是執(zhí)行速度較慢。

于是從Java 7開(kāi)始提供了另一套API MethodHandle 。其與反射的作用類(lèi)似,可以在運(yùn)行時(shí)訪問(wèn)類(lèi)型信息,但是其執(zhí)行效率比反射更高(性能幾乎接近方法調(diào)用)

MethodHandle:是java.lang.invoke.MethodHandle的一個(gè)實(shí)例,它是對(duì)Java中某個(gè)方法(包括實(shí)例方法、靜態(tài)方法、構(gòu)造函數(shù)等)的直接可執(zhí)行引用。

  • 與傳統(tǒng)的Java反射相比,MethodHandle更加輕量級(jí)和高效,因?yàn)樗@過(guò)了許多反射的額外開(kāi)銷(xiāo),如訪問(wèn)控制檢查等。
  • MethodHandle是對(duì)方法的直接引用,可以直接通過(guò)MethodHandle對(duì)象調(diào)用目標(biāo)方法,無(wú)需像反射那樣先獲取Method對(duì)象。
  • MethodHandle具有類(lèi)型檢查的特性,在編譯時(shí)會(huì)檢查MethodHandle的類(lèi)型與目標(biāo)方法的類(lèi)型是否匹配。

2、使用方式

1、創(chuàng)建MethodHandle對(duì)象:

  • 使用MethodHandles.Lookup類(lèi)的lookup()方法獲取一個(gè)MethodHandles.Lookup對(duì)象。
  • 使用MethodHandles.Lookup對(duì)象的findStatic(), findVirtual(), findSpecial(), findConstructor()等方法來(lái)查找并獲取目標(biāo)方法的MethodHandle對(duì)象。

2、綁定MethodHandle到目標(biāo)方法(如果需要):

  • 如果MethodHandle指向的是實(shí)例方法,可以使用MethodHandle對(duì)象的bindTo()方法將其綁定到目標(biāo)實(shí)例上。

3、調(diào)用目標(biāo)方法:

  • 使用MethodHandle對(duì)象的invoke()、invokeExact()、invokeWithArguments()等方法來(lái)調(diào)用目標(biāo)方法。

3、與反射的區(qū)別

  • 性能:MethodHandle通常比反射更快,因?yàn)樗@過(guò)了許多反射的額外開(kāi)銷(xiāo)。
  • 類(lèi)型安全:MethodHandle在編譯時(shí)會(huì)進(jìn)行類(lèi)型檢查,而反射在運(yùn)行時(shí)進(jìn)行類(lèi)型檢查,可能導(dǎo)致ClassCastException等異常。
  • 用法:反射需要先獲取Method對(duì)象,而MethodHandle直接對(duì)方法進(jìn)行引用。

Method Handles比反射更難用,因?yàn)闆](méi)有列舉類(lèi)中成員,獲取屬性訪問(wèn)標(biāo)志之類(lèi)的機(jī)制。

二、示例

1、基本使用

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

class Calculator {
    public String add(int a, int b) {
        return String.valueOf(a + b);
    }
}

public class MethodHandleExample {

    public static void main(String[] args) throws Throwable {
        try {
            // 獲取Calculator類(lèi)的方法句柄
            // 注意:由于我們是在Class內(nèi)部查找,所以可以使用MethodHandles.lookup()
            // 在實(shí)際應(yīng)用中,如果Class是其他包中的類(lèi),你可能需要不同的Lookup實(shí)例
            MethodHandles.Lookup lookup = MethodHandles.lookup();
            // 獲取方法,第一個(gè)參數(shù)為返回值,剩余的參數(shù)為方法參數(shù)
            MethodType methodType = MethodType.methodType(String.class, int.class, int.class);
            // 通過(guò)方法名 查找某個(gè)類(lèi)的某個(gè)方法
            MethodHandle addHandle = lookup.findVirtual(Calculator.class, "add", methodType);

            // 創(chuàng)建Calculator的實(shí)例
            Calculator calculator = new Calculator();
            // 直接調(diào)用方法,第一個(gè)參數(shù)為對(duì)象實(shí)例,剩余的參數(shù)為方法
            String result = (String) addHandle.invoke(calculator, 1, 2);
            System.out.println(result);
        } catch (NoSuchMethodException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }
}

2、(重要)提升性能的關(guān)鍵

使用MethodHandle來(lái)提升性能,一般是定義static final在啟動(dòng)時(shí)就加載好了,這樣不用在運(yùn)行時(shí)重新查找。

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

public class MethodHandleExample {
    // 要static final類(lèi)型的才能提升效率
    private static final MethodHandle ADD_HANDLE;

    static {
        // static final 修飾的 MethodHandle 可以在類(lèi)加載時(shí)就完成初始化,避免了每次調(diào)用時(shí)的查找開(kāi)銷(xiāo)。
        try {
            MethodHandles.Lookup lookup = MethodHandles.lookup();
            MethodType methodType = MethodType.methodType(int.class, int.class, int.class);
            ADD_HANDLE = lookup.findVirtual(Calculator.class, "add", methodType);
        } catch (NoSuchMethodException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Throwable {
        Calculator calculator = new Calculator();
        int result = (int) ADD_HANDLE.invoke(calculator, 1, 2);
        System.out.println(result);
    }
}

3、實(shí)際使用

//無(wú)參數(shù)構(gòu)造器
MethodType con1Mt = MethodType.methodType(void.class);
MethodHandle con1Mh = lookup.findConstructor(HandleTarget.class, con1Mt);
Object target1 = con1Mh.invoke();

//有參數(shù)構(gòu)造器
MethodType con2Mt = MethodType.methodType(void.class, String.class);
MethodHandle con2Mh = lookup.findConstructor(HandleTarget.class, con2Mt);
Object target2 = con2Mh.invoke("ErGouWang");

//調(diào)用非private實(shí)例方法
MethodType getterMt = MethodType.methodType(String.class);
MethodHandle getterMh = lookup.findVirtual(HandleTarget.class, "getName", getterMt);
String name = (String) getterMh.invoke(target2);
System.out.println(name);

//訪問(wèn)private方法
Method learnMethod = HandleTarget.class.getDeclaredMethod("learnPrograming", String.class);
learnMethod.setAccessible(true);
MethodHandle learnProMh = lookup.unreflect(learnMethod);
learnProMh.invoke(target1, "Java");

//訪問(wèn)非private屬性
MethodHandle nameMh= lookup.findGetter(HandleTarget.class,"name", String.class);
System.out.println((String) nameMh.invoke(con1Mh.invoke()));

//訪問(wèn)private的屬性,需要借助反射
Field nameField = HandleTarget.class.getDeclaredField("name");
nameField.setAccessible(true);
MethodHandle nameFromRefMh = lookup.unreflectGetter(nameField);
System.out.println((String) nameFromRefMh.invoke(target1));

//訪問(wèn)private的屬性,需要借助反射
Field nameField = HandleTarget.class.getDeclaredField("name");
nameField.setAccessible(true);
MethodHandle nameFromRefMh = lookup.unreflectGetter(nameField);
System.out.println((String) nameFromRefMh.invoke(target1));

三、源碼分析

1、創(chuàng)建Lookup

// 以這種方式得到的lookup很強(qiáng)大,凡是調(diào)用類(lèi)支持的字節(jié)碼操作,它都支持
MethodHandles.Lookup lookup = MethodHandles.lookup();

// 以此種方式創(chuàng)建的lookup能力是受限的,其只能訪問(wèn)類(lèi)中public的成員。
MethodHandles.Lookup publicLookup=MethodHandles.publicLookup();

2、MethodType

(1)創(chuàng)建MethodType

// MethodType使用其靜態(tài)方法創(chuàng)建
// 獲取方法,第一個(gè)參數(shù)為返回值,剩余的參數(shù)為方法參數(shù)

// 該類(lèi)能夠產(chǎn)生對(duì)方法的描述即 (Ljava/lang/Object;)V 該方法接收一個(gè)Object類(lèi)型的值,沒(méi)有返回值
// 其實(shí)該類(lèi)就是用來(lái)對(duì)方法的描述,描述這個(gè)方法接受什么參數(shù),返回什么類(lèi)型的值
MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes)

MethodType genericMethodType(int objectArgCount, boolean finalArray) 

MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)


想要獲得MethodType對(duì)象,MethodType類(lèi)提供了三個(gè)靜態(tài)方法,如上所述。

// 第一個(gè)參數(shù)代表返回類(lèi)型,如果沒(méi)有則指定void.class即可,后面的參數(shù)都是這個(gè)方法接收的參數(shù)類(lèi)型,可以有多個(gè),也可以沒(méi)有,MethodType.methodType()有多個(gè)重載方法
MethodType.methodType(Class<?>, Class<?>, Class<?>...) 

// 生成一個(gè)MethodType,第一個(gè)參數(shù)表示要生成的參數(shù)個(gè)數(shù),并且都是Object類(lèi)型,第二個(gè)參數(shù)表示是否要在最后再添加一個(gè)Object類(lèi)型的數(shù)組,注意是添加哦
MethodType genericMethodType(int objectArgCount, boolean finalArray) 

// 從方法描述符來(lái)生成一個(gè)MethodType, 第二個(gè)參數(shù)為一個(gè)類(lèi)加載器,如果為null則使用系統(tǒng)類(lèi)加載器
MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader) 

// 生成一個(gè) 接受int、long和String類(lèi)型的參數(shù),返回一個(gè)String類(lèi)型
MethodType.fromMethodDescriptorString("(IJLjava/lang/String;)Ljava/lang/String;", null); 

(2)修改MethodType

獲得一個(gè)具體MethodType實(shí)例后,我們可以對(duì)它進(jìn)行一些修改,比如更改參數(shù)類(lèi)型,添加一個(gè)參數(shù),刪除一個(gè)參數(shù)等等,但是由于MethodType本身是不可變的,所以每對(duì)其進(jìn)行一次更改都會(huì)產(chǎn)生一個(gè)新的MethodType對(duì)象?????

// 在方法后面追加多個(gè)參數(shù)
MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) 
// 在方法后買(mǎi)你追加一個(gè)參數(shù)
MethodType appendParameterTypes(Class<?>... ptypesToInsert)
// 在指定參數(shù)位置插入一個(gè)參數(shù) 從 0開(kāi)始
MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert)
// 在指定參數(shù)位置插入多個(gè)參數(shù) 從 0開(kāi)始
MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert)
// 改變返回值類(lèi)型
MethodType changeReturnType(Class<?> nrtype)
// 改變指定參數(shù)位置的參數(shù)類(lèi)型
MethodType changeParameterType(int num, Class<?> nptype)
// 把基本類(lèi)型變成對(duì)應(yīng)的包裝類(lèi)型 (裝箱)
MethodType wrap()
// 把包裝類(lèi)型變成對(duì)應(yīng)的基本類(lèi)型(拆箱)
MethodType unwrap()
// 把所有引用類(lèi)型的參數(shù)變?yōu)镺bject類(lèi)型
MethodType erase()
// 把所有參數(shù)都變成Object類(lèi)型
MethodType generic()
// 構(gòu)造出一個(gè) (int,long,String)String
MethodType methodType = MethodType.fromMethodDescriptorString("(IJLjava/lang/String;)Ljava/lang/String;", null);
// (double, long, String)String
methodType = methodType.changeParameterType(0, Double.TYPE);
// (double, long, String, Object)String
methodType = methodType.appendParameterTypes(Object.class);
// (boolean, double, long, String, Object)String
methodType = methodType.insertParameterTypes(0, Boolean.TYPE);
// (float, double, long, String, Object)String
methodType = methodType.changeParameterType(0, Float.TYPE);
// (float, double, long, String, Object)Object
methodType = methodType.changeReturnType(Object.class);
// (Float, Double, Long, String, Object)Object
methodType = methodType.wrap();
// (float, double, long, String, Object)Object
methodType = methodType.unwrap();
// (float, double, long, Object, Object)Object
methodType = methodType.erase();
// (Object, Object, Object, Object, Object)Object
methodType = methodType.generic();

List<Class<?>> classList =  methodType.parameterList();
for (Class<?> clazz : classList) {
    System.out.println(clazz.getName());
}

        

3、創(chuàng)建MethodHandle

(1)MethodHandle (方法句柄)

// 所有方法都會(huì)查找指定類(lèi)中的指定方法,如果查找到了
// 則會(huì)返回這個(gè)方法的方法句柄

// 返回指定類(lèi)的指定構(gòu)造函數(shù)
public MethodHandle findConstructor(Class<?> refc,
                                    MethodType type);
 
// 查找虛方法 final修飾的也可找到  
// 可以簡(jiǎn)單理解為虛方法指的是可以被子類(lèi)覆蓋的方法                                
public MethodHandle findVirtual(Class<?> refc,
                                String name,
                                MethodType type);
// 通過(guò)反射獲取方法句柄
public MethodHandle unreflect(Method m);

// 查找靜態(tài)方法
public MethodHandle findStatic(Class<?> refc,
                               String name,
                               MethodType type);

// 查找某個(gè)字段,并生成get方法的方法句柄(類(lèi)中不需要存在這個(gè)字段的get方法)
ublic MethodHandle findGetter(Class<?> refc,
                               String name,
                               Class<?> type)

// 查找某個(gè)字段,并生成set方法的方法句柄(類(lèi)中不需要存在這個(gè)字段的set方法)
public MethodHandle findSetter(Class<?> refc,
                               String name,
                               Class<?> type)

(2)MethodHandles中靜態(tài)工廠方法創(chuàng)建通用的方法句柄

// 1、用來(lái)創(chuàng)建操作數(shù)組的方法句柄
//MethodHandle arrayElementGetter(Class<?> arrayClass)
//MethodHandle arrayElementSetter(Class<?> arrayClass)

int[] arr = new int[]{1, 2, 3, 4, 5, 6};

MethodHandle getter = MethodHandles.arrayElementGetter(int[].class);
MethodHandle setter = MethodHandles.arrayElementSetter(int[].class);
setter.bindTo(arr).invoke(2, 50);
System.out.println(getter.bindTo(arr).invoke(2));
System.out.println(Arrays.toString(arr));

// 2、MethodHandle identity(Class<?> type)
// 該方法總是返回你給定的值,即你傳的參數(shù)是什么就返回什么
MethodHandle identity = MethodHandles.identity(String.class);
System.out.println(identity.invoke("hello world"));
        
// 3、MethodHandle constant(Class<?> type, Object value)
//與上面那個(gè)方法不同的是,該方法在創(chuàng)建方法句柄的時(shí)候就指定一個(gè)值,然后每次調(diào)用這個(gè)方法句柄的時(shí)候都會(huì)返回這個(gè)值
MethodHandle helloWorld = MethodHandles.constant(String.class, "hello world");
System.out.println(helloWorld.invoke());


// 4、MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
// 可以簡(jiǎn)單理解為在調(diào)用的時(shí)候忽略掉哪些位置上的參數(shù)

public static void main(String[] args) throws Throwable {
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle methodHandle = lookup.findStatic(TestMain.class, "test", MethodType.methodType(int.class, int.class));
    // 忽略第0個(gè)參數(shù)并且類(lèi)型為int類(lèi)型的參數(shù)
    methodHandle = MethodHandles.dropArguments(methodHandle, 0, int.class);
    // 實(shí)際傳遞的只有3 
    methodHandle.invoke(2, 3);
}


public static int test(int i) {
    System.out.println(i);
    return 3;
}

// 5、MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)
// 可以在方法調(diào)用的時(shí)候?qū)?shù)進(jìn)行處理
// 下面這個(gè)例子,test方法接收的是一個(gè)int類(lèi)型的參數(shù),但是我們傳遞的是一個(gè)字符串。因此我們把參數(shù)進(jìn)行了一個(gè)處理 test = MethodHandles.filterArguments(test, 0, length);這行代碼就是表示,test方法句柄調(diào)用的時(shí)候調(diào)用length方法句柄進(jìn)行處理。

public static void main(String[] args) throws Throwable {

    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle length = lookup.findVirtual(String.class, "length", MethodType.methodType(int.class));
    MethodHandle test = lookup.findStatic(TestMain.class, "test", MethodType.methodType(int.class, int.class));
    test = MethodHandles.filterArguments(test, 0, length);
    // test()方法實(shí)際接收到的參數(shù)是5
    test.invoke("sdfsd");
}


public static int test(int i) {
    System.out.println(i);
    return 3;
}

// 6、MethodHandle insertArguments(MethodHandle target, int pos, Object... values)
// 給指定位置上的參數(shù)預(yù)先綁定一個(gè)值,這樣在調(diào)用的時(shí)候就不能傳了
public static void main(String[] args) throws Throwable {
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle methodHandle = lookup.findStatic(TestMain.class, "test", MethodType.methodType(int.class, int.class));
    // 預(yù)先給指定位置的參數(shù)綁定一個(gè)值 
    methodHandle = MethodHandles.insertArguments(methodHandle, 0, 22);
    // 由于參數(shù)i已經(jīng)綁定值了,在這里調(diào)用的時(shí)候就不能傳遞參數(shù)了
    methodHandle.invoke();
}

public static int test(int i) {
    System.out.println(i);
    return 3;


// 7、MethodHandle foldArguments(MethodHandle target, MethodHandle combiner)
// 與上面的方法類(lèi)似,不同的是該方法不是在指定位置綁定值,而是通過(guò)一個(gè)方法句柄的返回值,將該返回值放到最終在調(diào)用方法的前面

public static void main(String[] args) throws Throwable {

    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle methodHandle = lookup.findStatic(TestMain.class, "test", MethodType.methodType(int.class, int.class, int.class, int.class, int.class));
    MethodHandle max = lookup.findStatic(Math.class, "max", MethodType.methodType(int.class, int.class, int.class));
    methodHandle = MethodHandles.foldArguments(methodHandle, max);
    methodHandle.invoke(4, 5, 6);
}


public static int test(int i, int i2, int i3, int i4) {
    // 打印5
    System.out.println(i);
    return 3;
}


// 8、MethodHandle catchException(MethodHandle target, Class<? extends Throwable> exType, MethodHandle handler)
// 如果terget方法句柄出現(xiàn)了指定的異?;蚱渲付ǖ淖宇?lèi)異常,則調(diào)用handler方法
public static void main(String[] args) throws Throwable {

    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle methodHandle = lookup.findStatic(TestMain.class, "test", MethodType.methodType(int.class, int.class, int.class, int.class, int.class));
    MethodHandle exceptionHandle = lookup.findStatic(TestMain.class, "handleException", MethodType.methodType(int.class, Exception.class, int.class, int.class, int.class, int.class));
    methodHandle = MethodHandles.catchException(methodHandle, Exception.class, exceptionHandle);
    methodHandle.invoke(4, 5, 6, 7);
}


public static int test(int i, int i2, int i3, int i4) {
    System.out.println(i);
    throw new RuntimeException("test出現(xiàn)異常");
}

public static int handleException( Exception e, int i, int i2, int i3, int i4) {
    System.out.println("handleException:\n" + e.getMessage());
    return 2;
}
值得注意的是 handleException方法的 異常類(lèi)型參數(shù)只能在第一個(gè)位置,然后其他參數(shù)必須與出現(xiàn)異常方法的參數(shù)類(lèi)型一致

// 9、MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType)
// 構(gòu)造出一個(gè)只拋出異常的方法句柄
MethodHandle handle = MethodHandles.throwException(String.class, Exception.class);
String invoke = (String) handle.invoke(new RuntimeException("throw"));



4、MethodHandle中的方法

// MethodHandle bindTo(Object x) 把一個(gè)對(duì)象與綁定并返回綁定后的方法句柄
MethodHandle bindTo(Object x)

/**
特點(diǎn):
invoke()方法是MethodHandle的一個(gè)通用方法,它允許在調(diào)用時(shí)執(zhí)行類(lèi)型轉(zhuǎn)換。
如果提供的參數(shù)類(lèi)型與目標(biāo)方法不匹配,invoke()會(huì)嘗試使用MethodHandle的asType()方法進(jìn)行參數(shù)適配。
參數(shù):
invoke()方法接受一個(gè)可變參數(shù)列表(Object... args),其中第一個(gè)參數(shù)(如果目標(biāo)方法是實(shí)例方法)是實(shí)例對(duì)象,后續(xù)參數(shù)是傳遞給目標(biāo)方法的參數(shù)。
*/
Object	invoke(Object... args)

/**
特點(diǎn):
invokeExact()方法提供了嚴(yán)格的類(lèi)型檢查。
如果提供的參數(shù)類(lèi)型與目標(biāo)方法的參數(shù)類(lèi)型不匹配,invokeExact()將拋出WrongMethodTypeException。
參數(shù):
invokeExact()同樣接受一個(gè)可變參數(shù)列表(Object... args),但要求這些參數(shù)的類(lèi)型必須與目標(biāo)方法的參數(shù)類(lèi)型完全匹配。
*/
Object	invokeExact(Object... args)

/**
特點(diǎn):
invokeWithArguments()方法允許使用List<Object>作為參數(shù)列表進(jìn)行調(diào)用。
這為調(diào)用者提供了一種更靈活的方式來(lái)構(gòu)建參數(shù)列表,尤其是當(dāng)參數(shù)數(shù)量不確定或需要?jiǎng)討B(tài)構(gòu)建時(shí)。
參數(shù):
invokeWithArguments()接受一個(gè)List<Object>參數(shù),其中第一個(gè)元素(如果目標(biāo)方法是實(shí)例方法)是實(shí)例對(duì)象,后續(xù)元素是傳遞給目標(biāo)方法的參數(shù)。
*/
Object	invokeWithArguments(Object... arguments)
  • invoke():提供類(lèi)型適配的靈活調(diào)用,允許在運(yùn)行時(shí)轉(zhuǎn)換參數(shù)類(lèi)型。
  • invokeExact():提供嚴(yán)格的類(lèi)型檢查,要求參數(shù)類(lèi)型與目標(biāo)方法完全匹配。
  • invokeWithArguments():允許使用列表作為參數(shù)進(jìn)行調(diào)用,提供了更大的靈活性。

在選擇使用哪種方法時(shí),應(yīng)該根據(jù)具體需求來(lái)決定。如果希望進(jìn)行嚴(yán)格的類(lèi)型檢查,可以使用invokeExact();如果需要更靈活的參數(shù)傳遞方式,可以考慮使用invoke()或invokeWithArguments()。同時(shí),需要注意的是,invokeExact()的性能通常優(yōu)于invoke(),因?yàn)樗苊饬嗽谶\(yùn)行時(shí)進(jìn)行類(lèi)型適配的開(kāi)銷(xiāo)。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • windows命令行中java和javac、javap使用詳解(java編譯命令)

    windows命令行中java和javac、javap使用詳解(java編譯命令)

    最近重新復(fù)習(xí)了一下java基礎(chǔ),這里便講講對(duì)于一個(gè)類(lèi)文件如何編譯、運(yùn)行、反編譯的。也讓自己加深一下印象
    2014-03-03
  • Springboot結(jié)合rabbitmq實(shí)現(xiàn)的死信隊(duì)列

    Springboot結(jié)合rabbitmq實(shí)現(xiàn)的死信隊(duì)列

    為了保證訂單業(yè)務(wù)的消息數(shù)據(jù)不丟失,需要使用到RabbitMQ的死信隊(duì)列機(jī)制,本文主要介紹了Springboot結(jié)合rabbitmq實(shí)現(xiàn)的死信隊(duì)列,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Shell重啟SpringBoot項(xiàng)目腳本的示例代碼(含服務(wù)守護(hù))

    Shell重啟SpringBoot項(xiàng)目腳本的示例代碼(含服務(wù)守護(hù))

    本文介紹了如何使用?Bash?腳本來(lái)管理和守護(hù)運(yùn)行服務(wù),將展示一個(gè)示例腳本,該腳本可以停止、啟動(dòng)和守護(hù)運(yùn)行一個(gè)服務(wù),并提供了相應(yīng)的解釋和用法說(shuō)明,文章通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Kotlin 內(nèi)聯(lián)函數(shù)詳解及實(shí)例

    Kotlin 內(nèi)聯(lián)函數(shù)詳解及實(shí)例

    這篇文章主要介紹了Kotlin 內(nèi)聯(lián)函數(shù)詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • spring aop execution表達(dá)式的用法

    spring aop execution表達(dá)式的用法

    這篇文章主要介紹了spring aop execution表達(dá)式的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java中終止線程的方法詳解

    Java中終止線程的方法詳解

    這篇文章主要介紹了Java中終止線程的方法詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Java項(xiàng)目開(kāi)發(fā)中實(shí)現(xiàn)分頁(yè)的三種方式總結(jié)

    Java項(xiàng)目開(kāi)發(fā)中實(shí)現(xiàn)分頁(yè)的三種方式總結(jié)

    這篇文章主要給大家介紹了關(guān)于Java項(xiàng)目開(kāi)發(fā)中實(shí)現(xiàn)分頁(yè)的三種方式,通過(guò)這一篇文章可以很快的學(xué)會(huì)java分頁(yè)功能,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-02-02
  • ELK搭建線上日志收集系統(tǒng)

    ELK搭建線上日志收集系統(tǒng)

    ELK日志收集系統(tǒng)進(jìn)階使用,本文主要講解如何打造一個(gè)線上環(huán)境真實(shí)可用的日志收集系統(tǒng),有了它,你就可以和去服務(wù)器上撈日志說(shuō)再見(jiàn)了
    2022-07-07
  • java項(xiàng)目中classpath的理解

    java項(xiàng)目中classpath的理解

    這篇文章介紹了java項(xiàng)目中classpath的理解,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • Java Json字符串的雙引號(hào)(

    Java Json字符串的雙引號(hào)("")括號(hào)如何去掉

    這篇文章主要介紹了Java Json字符串的雙引號(hào)("")括號(hào)如何去掉?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09

最新評(píng)論