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

Java安全-ClassLoader

 更新時(shí)間:2022年01月14日 09:36:40   作者:Zh1z3ven  
這篇文章主要介紹了Java安全ClassLoader,Java類(lèi)初始化的時(shí)候會(huì)調(diào)用java.lang.ClassLoader加載字節(jié)碼,ClassLoader就是用來(lái)動(dòng)態(tài)加載class文件到內(nèi)存當(dāng)中用的,下面詳細(xì)內(nèi)容,需要的小伙伴可以參考一下

1.類(lèi)加載機(jī)制

Java中的源碼.java后綴文件會(huì)在運(yùn)行前被編譯成.class后綴文件,文件內(nèi)的字節(jié)碼的本質(zhì)就是一個(gè)字節(jié)數(shù)組 ,它有特定的復(fù)雜的內(nèi)部格式,Java類(lèi)初始化的時(shí)候會(huì)調(diào)用java.lang.ClassLoader加載字節(jié)碼,.class文件中保存著Java代碼經(jīng)轉(zhuǎn)換后的虛擬機(jī)指令,當(dāng)需要使用某個(gè)類(lèi)時(shí),虛擬機(jī)將會(huì)加載它的.class文件,并創(chuàng)建對(duì)應(yīng)的class對(duì)象,將class文件加載到虛擬機(jī)的內(nèi)存,而在JVM中類(lèi)的查找與裝載就是由ClassLoader完成的,而程序在啟動(dòng)的時(shí)候,并不會(huì)一次性加載程序所要用的所有class文件,而是根據(jù)程序的需要,來(lái)動(dòng)態(tài)加載某個(gè)class文件到內(nèi)存當(dāng)中的,從而只有class文件被載入到了內(nèi)存之后,才能被其它c(diǎn)lass所引用。所以ClassLoader就是用來(lái)動(dòng)態(tài)加載class文件到內(nèi)存當(dāng)中用的。

2.類(lèi)加載方式

Java類(lèi)加載方式分為顯式和隱式

顯式:利用反射來(lái)加載一個(gè)類(lèi)

隱式:通過(guò)ClassLoader來(lái)動(dòng)態(tài)加載,new 一個(gè)類(lèi)或者 類(lèi)名.方法名返回一個(gè)類(lèi)

示例代碼:

@Test
public void loadClassTest() throws Exception {
? ? //1、反射加載
? ? Class<?> aClass = Class.forName("java.lang.Runtime");
? ? System.out.println(aClass.getName());

? ? //2、ClassLoader加載
? ? Class<?> aClass1 = ClassLoader.getSystemClassLoader().loadClass("java.lang.ProcessBuilder");
? ? System.out.println(aClass1.getName());

}

那也就是其實(shí)可以通過(guò)ClassLoader.loadClass()代替Class.forName()來(lái)獲取某個(gè)類(lèi)的class對(duì)象。

3.ClassLoader

ClassLoader(類(lèi)加載器)主要作用就是將class文件讀入內(nèi)存,并為之生成對(duì)應(yīng)的java.lang.Class對(duì)象

JVM中存在3個(gè)內(nèi)置ClassLoader:

  • BootstrapClassLoader 啟動(dòng)類(lèi)加載器 負(fù)責(zé)加載 JVM 運(yùn)行時(shí)核心類(lèi),這些類(lèi)位于 JAVA_HOME/lib/rt.jar 文件中,我們常用內(nèi)置庫(kù) java.xxx.* 都在里面,比如 java.util.*、java.io.*、java.nio.*、java.lang.* 等等。
  • ExtensionClassLoader 擴(kuò)展類(lèi)加載器 負(fù)責(zé)加載 JVM 擴(kuò)展類(lèi),比如 swing 系列、內(nèi)置的 js 引擎、xml 解析器 等等,這些庫(kù)名通常以 javax 開(kāi)頭,它們的 jar 包位于 JAVA_HOME/lib/ext/*.jar 中
  • AppClassLoader 系統(tǒng)類(lèi)加載器 才是直接面向我們用戶的加載器,它會(huì)加載 Classpath 環(huán)境變量里定義的路徑中的 jar 包和目錄。我們自己編寫(xiě)的代碼以及使用的第三方 jar 包通常都是由它來(lái)加載的。

除了Java自帶的ClassLoader外,還可以自定義ClassLoader,自定義的ClassLoader都必須繼承自java.lang.ClassLoader類(lèi),也包括Java提供的另外二個(gè)ClassLoader(Extension ClassLoader和App ClassLoader)在內(nèi),但是Bootstrap ClassLoader不繼承自ClassLoader,因?yàn)樗皇且粋€(gè)普通的Java類(lèi),底層由C++編寫(xiě),已嵌入到了JVM內(nèi)核當(dāng)中,當(dāng)JVM啟動(dòng)后,Bootstrap ClassLoader也隨著啟動(dòng),負(fù)責(zé)加載完核心類(lèi)庫(kù)后,并構(gòu)造Extension ClassLoaderApp ClassLoader類(lèi)加載器。

4.類(lèi)加載流程

類(lèi)加載指的是在.java文件編譯成.class字節(jié)碼文件后,當(dāng)需要使用某個(gè)類(lèi)時(shí),虛擬機(jī)將會(huì)加載它的.class文件,將.class文件讀入內(nèi)存,并在內(nèi)存中為之創(chuàng)建一個(gè)java.lang.Class對(duì)象。但是實(shí)現(xiàn)步驟看起來(lái)會(huì)比較空洞和概念化,暫時(shí)不去深入研究,理解類(lèi)加載是做什么的并了解加載過(guò)程即可。后續(xù)有剛需再去深入。

類(lèi)加載大致分為三個(gè)步驟:加載、連接、初始化。

加載

類(lèi)加載指的是將class文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)java.lang.Class對(duì)象,即程序中使用任何類(lèi)時(shí),也就是任何類(lèi)在加載進(jìn)內(nèi)存時(shí),系統(tǒng)都會(huì)為之建立一個(gè)java.lang.Class對(duì)象,這個(gè)Class對(duì)象包含了該類(lèi)的所有信息,如Filed,Method等,系統(tǒng)中所有的類(lèi)都是java.lang.Class的實(shí)例。
類(lèi)的加載由類(lèi)加載器完成,JVM提供的類(lèi)加載器叫做系統(tǒng)類(lèi)加載器,此外還可以通過(guò)自定義類(lèi)加載器加載。
通??梢杂萌缦聨追N方式加載類(lèi)的二進(jìn)制數(shù)據(jù):

從本地文件系統(tǒng)加載class文件。

從JAR包中加載class文件,如JAR包的數(shù)據(jù)庫(kù)啟驅(qū)動(dòng)類(lèi)。

通過(guò)網(wǎng)絡(luò)加載class文件。

把一個(gè)Java源文件動(dòng)態(tài)編譯并執(zhí)行加載。

鏈接

鏈接階段負(fù)責(zé)把類(lèi)的二進(jìn)制數(shù)據(jù)合并到JRE中,其又可分為如下三個(gè)階段:

驗(yàn)證:確保加載的類(lèi)信息符合JVM規(guī)范,無(wú)安全方面的問(wèn)題。
準(zhǔn)備:為類(lèi)的靜態(tài)Field分配內(nèi)存,并設(shè)置初始值。
解析:將類(lèi)的二進(jìn)制數(shù)據(jù)中的符號(hào)引用替換成直接引用。

初始化

類(lèi)加載最后階段,若該類(lèi)具有超類(lèi),則對(duì)其進(jìn)行初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化成員變量(如前面只初始化了默認(rèn)值的static變量將會(huì)在這個(gè)階段賦值,成員變量也將被初始化

5.雙親委派機(jī)制

基本概念

前面提到了Java自帶3個(gè)ClassLoader,包括我們也可以實(shí)現(xiàn)自定義ClassLoader完成類(lèi)加載,但是具體某個(gè)類(lèi)的加載用的是哪個(gè)ClassLoader呢。這里涉及到一個(gè)雙親委派機(jī)制(PS:這個(gè)我看網(wǎng)上有講的是委托也有是委派,個(gè)人覺(jué)得委派好聽(tīng),先這么叫著:D)

這里丟個(gè)圖,基本概述了雙親委派機(jī)制(先走藍(lán)色箭頭再走紅色箭頭)

雙親委派簡(jiǎn)單理解:向上委派,向下加載

當(dāng)一個(gè).class文件要被加載時(shí)。不考慮我們自定義類(lèi)加載器,首先會(huì)在AppClassLoader中檢查是否加載過(guò),如果有那就無(wú)需再加載了。如果沒(méi)有,那么會(huì)拿到父加載器,然后調(diào)用父加載器的loadClass方法。父類(lèi)中同理也會(huì)先檢查自己是否已經(jīng)加載過(guò),如果沒(méi)有再往上。注意這個(gè)類(lèi)似遞歸的過(guò)程,直到到達(dá)Bootstrap classLoader之前,都是在檢查是否加載過(guò),并不會(huì)選擇自己去加載。直到BootstrapClassLoader,已經(jīng)沒(méi)有父加載器了,這時(shí)候開(kāi)始考慮自己是否能加載了(向上委派); 如果自己無(wú)法加載,會(huì)下沉到子加載器去加載,一直到最底層(向下加載)。如果沒(méi)有任何加載器能加載,就會(huì)拋出ClassNotFoundException異常。

為什么呢?

那么為什么加載類(lèi)的時(shí)候需要雙親委派機(jī)制呢?

采用雙親委派模式的是好處是Java類(lèi)隨著它的類(lèi)加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系,通過(guò)這種層級(jí)關(guān)可以避免類(lèi)的重復(fù)加載,當(dāng)父親已經(jīng)加載了該類(lèi)時(shí),就沒(méi)有必要子ClassLoader再加載一次。

其次是,如果有人想替換系統(tǒng)級(jí)別的類(lèi):String.java。篡改它的實(shí)現(xiàn),在這種機(jī)制下這些系統(tǒng)的類(lèi)已經(jīng)被Bootstrap classLoader加載過(guò)了(為什么?因?yàn)楫?dāng)一個(gè)類(lèi)需要加載的時(shí)候,最先去嘗試加載的就是BootstrapClassLoader),所以其他類(lèi)加載器并沒(méi)有機(jī)會(huì)再去加載,從一定程度上防止了危險(xiǎn)代碼的植入。

自定義ClassLoader

先看下ClassLoader這個(gè)類(lèi)中的核心方法

ClassLoader核心方法:

  • loadClass(加載指定的Java類(lèi))

一般實(shí)現(xiàn)這個(gè)方法的步驟是:執(zhí)行findLoadedClass(String)去檢測(cè)這個(gè)class是不是已經(jīng)加載過(guò)了。
執(zhí)行父加載器的loadClass方法。如果父加載器為null則jvm內(nèi)置的加載器去替代,也就是Bootstrap ClassLoader。這也解釋了ExtClassLoader的parent為null,但仍然說(shuō)Bootstrap ClassLoader是它的父加載器。如果向上委托父加載器沒(méi)有加載成功;則通過(guò)findClass(String)查找。
如果class在上面的步驟中找到了,參數(shù)resolve又是true的話那么loadClass()又會(huì)調(diào)用resolveClass(Class)這個(gè)方法來(lái)生成最終的Class對(duì)象。

  • findClass(查找指定的Java類(lèi))
  • findLoadedClass(查找JVM已經(jīng)加載過(guò)的類(lèi))
  • defineClass(定義一個(gè)Java類(lèi))
  • resolveClass(鏈接指定的Java類(lèi))

編寫(xiě)自定義ClassLoader步驟:

  • 1、編寫(xiě)一個(gè)類(lèi)繼承ClassLoader抽象類(lèi);
  • 2、重寫(xiě)findClass()方法;
  • 3、在findClass()方法中調(diào)用defineClass()方法即可實(shí)現(xiàn)自定義ClassLoader;

 編寫(xiě)測(cè)試類(lèi)

package classloader;

public class test {
? ? public String hello(){
? ? ? ? return "hello, CoLoo!";
? ? }
}

編譯為.class文件

class轉(zhuǎn)換bytes

public class ByteClass {
? ? public static void main(String[] args) throws IOException {
? ? ? ? FileInputStream fis = new FileInputStream("test.class");
? ? ? ? byte[] classBytes = IOUtils.readFully(fis, -1, false);
? ? ? ? System.out.println(Arrays.toString(classBytes));
? ? }
}

Output:

[-54, -2, -70, -66, 0, 0, 0, 52, 0, 17, 10, 0, 4, 0, 13, 8, 0, 14, 7, 0, 15, 7, 0, 16, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 5, 104, 101, 108, 108, 111, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 9, 116, 101, 115, 116, 46, 106, 97, 118, 97, 12, 0, 5, 0, 6, 1, 0, 13, 104, 101, 108, 108, 111, 44, 32, 67, 111, 76, 111, 111, 33, 1, 0, 16, 99, 108, 97, 115, 115, 108, 111, 97, 100, 101, 114, 47, 116, 101, 115, 116, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 3, 0, 4, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 3, 0, 1, 0, 9, 0, 10, 0, 1, 0, 7, 0, 0, 0, 27, 0, 1, 0, 1, 0, 0, 0, 3, 18, 2, -80, 0, 0, 0, 1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 5, 0, 1, 0, 11, 0, 0, 0, 2, 0, 12]

自定義ClassLoader

package classloader;

import java.lang.reflect.Method;

public class ClassLoaderTest extends ClassLoader {

? ? private static String className = "classloader.test";
? ? //轉(zhuǎn)換byte后的字節(jié)碼
? ? private static byte[] classBytes = new byte[]{54, -2, -70, -66, 0, 0, 0, 52, 0, 17, 10, 0, 4, 0, 13, 8, 0, 14, 7, 0, 15, 7, 0, 16, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 5, 104, 101, 108, 108, 111, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 9, 116, 101, 115, 116, 46, 106, 97, 118, 97, 12, 0, 5, 0, 6, 1, 0, 13, 104, 101, 108, 108, 111, 44, 32, 67, 111, 76, 111, 111, 33, 1, 0, 16, 99, 108, 97, 115, 115, 108, 111, 97, 100, 101, 114, 47, 116, 101, 115, 116, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 3, 0, 4, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 3, 0, 1, 0, 9, 0, 10, 0, 1, 0, 7, 0, 0, 0, 27, 0, 1, 0, 1, 0, 0, 0, 3, 18, 2, -80, 0, 0, 0, 1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 5, 0, 1, 0, 11, 0, 0, 0, 2, 0, 12};


? ? @Override
? ? protected Class<?> findClass(String name) throws ClassNotFoundException {
? ? ? ? //只處理classloader.test類(lèi)
? ? ? ? if (name.equals(className)) {
? ? ? ? ? ? //調(diào)用definClass將一個(gè)字節(jié)流定義為一個(gè)類(lèi)。
? ? ? ? ? ? return defineClass(className, classBytes, 0, classBytes.length);
? ? ? ? }
? ? ? ? return super.findClass(name);
? ? }

? ? public static void main(String[] args) throws Exception {
? ? ? ? //創(chuàng)建加載器
? ? ? ? ClassLoaderTest clt = new ClassLoaderTest();
? ? ? ? //使用我們自定義的類(lèi)去加載className
? ? ? ? Class clazz = clt.loadClass(className);
? ? ? ? //反射創(chuàng)建test類(lèi)對(duì)象
? ? ? ? Object test = clazz.newInstance();
? ? ? ? //反射獲取方法
? ? ? ? Method method = test.getClass().getMethod("hello");
? ? ? ? //反射去調(diào)用執(zhí)行方法
? ? ? ? String str = (String) method.invoke(test);
? ? ? ? System.out.println(str);

? ? }
}

執(zhí)行了test類(lèi)的hello方法:

一些思考

上面自定義ClassLoader流程也可以小結(jié)一下:

  1. 準(zhǔn)備自定義類(lèi),編譯為.class文件
  2. 將.class文件內(nèi)容專(zhuān)為bytes數(shù)組
  3. 自定義ClassLoader,繼承ClassLoader類(lèi),重寫(xiě)findClass()方法,在方法中定義對(duì)指定類(lèi)的處理流程
  4. 主函數(shù)創(chuàng)建自定義ClassLoader對(duì)象并loadClass()指定類(lèi),如果自定義的ClassLoader完成了加載則會(huì)獲得該類(lèi)的class對(duì)象,后續(xù)可通過(guò)反射來(lái)深入利用(如執(zhí)行某個(gè)方法)。

那ClassLoader對(duì)于安全來(lái)說(shuō)能做什么?

1、個(gè)人這里目前想到的是代替Class.forName(),通過(guò)ClassLoader.loadClass()獲取class對(duì)象

@Test
public void classLoaderRuntime() throws Exception {
? ? Class<?> aClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime");
? ? Runtime runtime = (Runtime) aClass.getMethod("getRuntime").invoke(aClass);
? ? runtime.exec("open -a Calculator");

}

2、加載惡意類(lèi)

webshell中(之前有次攻防捕捉到一個(gè)webshell里面用到了classloader)或者內(nèi)存馬中應(yīng)該也可以用到。

惡意類(lèi)加載還是有必要深入學(xué)習(xí)一下,給后續(xù)學(xué)習(xí)內(nèi)存馬和反序列化payload打個(gè)基礎(chǔ)。

首先上面提到了,關(guān)于顯隱式加載類(lèi)是有些區(qū)別的,顯示加載時(shí)(反射)可以觸發(fā)該類(lèi)的初始化從而調(diào)用靜態(tài)代碼塊執(zhí)行,主要是因?yàn)槭褂胘ava.lang.reflect對(duì)類(lèi)進(jìn)行反射調(diào)用時(shí),如果該類(lèi)沒(méi)有初始化會(huì)先進(jìn)行類(lèi)的初始化;而隱式加載,如new,ClassLoader.getSystemClassLoader.loadClass(),不會(huì)初始化類(lèi)也就不執(zhí)行靜態(tài)代碼塊中的內(nèi)容。

下面簡(jiǎn)單測(cè)試了幾個(gè)可能會(huì)用到的觸發(fā)類(lèi)初始化的類(lèi)加載方式,

簡(jiǎn)單列舉下:

  • 默認(rèn)java.lang.ClassLoader
  1. loadClass() + newInstance()
  2. Class.forName()
  3. Class.forName(ClassName, true, ClassLoaderName) + newInstance()
  • org.apache.bcel.util.ClassLoader 也是fj經(jīng)常用到的,需要注意的是在JDK8u251之后就沒(méi)有ClassLoader這個(gè)類(lèi)了
  • URLClassLoader
  • new

Classloader

package classloader;
import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.ClassLoader;


public class ClassLoaderBaseClass {
? ? public static void main(String[] args) throws Exception {
? ? ? ? // 1、ClassLoader.getSystemClassLoader().loadClass() + 反射newInstance() [+]
? ? ? ? ClassLoader.getSystemClassLoader().loadClass("classloader.CalcBaseClass2").newInstance();

? ? ? ? // 0x02 new [+]
? ? ? ? CalcBaseClass2 calcBaseClass2 = new CalcBaseClass2();

? ? ? ? // 0x03 Class.forName() [+]
? ? ? ? Class.forName("classloader.CalcBaseClass2");

? ? ? ? // 0x04 ClassLoader.getSystemClassLoader().loadClass() [-]
? ? ? ? ClassLoaderTest.getSystemClassLoader().loadClass("classloader.CalcBaseClass2");

? ? ? ? // 0x05 Class.forName(className, true, ClassLoaderName)
? ? ? ? Class.forName("classloader.CalcBaseClass", true, java.lang.ClassLoader.getSystemClassLoader());

? ? ? ? // 0x06 bcel
? ? ? ? JavaClass clazz = Repository.lookupClass(CalcBaseClass2.class);
? ? ? ? String code = Utility.encode(clazz.getBytes(), true);
? ? ? ? System.out.println(code);

? ? ? ? new ClassLoader().loadClass("$$BCEL$$" + code).newInstance();

? ? }
}

calc

package classloader;

import java.io.IOException;

public class CalcBaseClass2 {
? ? static {
? ? ? ? try {
? ? ? ? ? ? Runtime.getRuntime().exec("open -a Calculator");
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }

}

到此這篇關(guān)于Java安全-ClassLoader的文章就介紹到這了,更多相關(guān)Java ClassLoader內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

參考:

https://www.cnblogs.com/nice0e3/p/13719903.html

http://code2sec.com/javafan-xu-lie-hua-lou-dong-xue-xi-shi-jian-liu-lei-de-jia-zai-ji-zhi-he-e-yi-lei-gou-zao.html

https://blog.csdn.net/javazejian/article/details/73413292

https://blog.csdn.net/CNAHYZ/article/details/82219210

https://blog.csdn.net/briblue/article/details/54973413

https://blog.csdn.net/codeyanbao/article/details/82875064

相關(guān)文章

  • Spring整合多數(shù)據(jù)源實(shí)現(xiàn)動(dòng)態(tài)切換的實(shí)例講解

    Spring整合多數(shù)據(jù)源實(shí)現(xiàn)動(dòng)態(tài)切換的實(shí)例講解

    下面小編就為大家?guī)?lái)一篇Spring整合多數(shù)據(jù)源實(shí)現(xiàn)動(dòng)態(tài)切換的實(shí)例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Java?EasyExcel實(shí)現(xiàn)合并相同內(nèi)容單元格與動(dòng)態(tài)標(biāo)題功能

    Java?EasyExcel實(shí)現(xiàn)合并相同內(nèi)容單元格與動(dòng)態(tài)標(biāo)題功能

    這篇文章主要為大家詳細(xì)介紹了Java?EasyExcel如何實(shí)現(xiàn)合并相同內(nèi)容單元格與動(dòng)態(tài)標(biāo)題功能,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考下
    2023-12-12
  • 使用Java設(shè)置字型和顏色的方法詳解

    使用Java設(shè)置字型和顏色的方法詳解

    這篇文章主要介紹了使用Java設(shè)置字型和顏色的方法,在Java的繪圖等圖形化編程中較常用到,需要的朋友可以參考下
    2015-10-10
  • JDK1.8、JDK1.7、JDK1.6區(qū)別看這里

    JDK1.8、JDK1.7、JDK1.6區(qū)別看這里

    這篇文章主要為大家詳細(xì)介紹了JDK1.8、JDK1.7、JDK1.6中的源碼,對(duì)比閱讀,發(fā)現(xiàn)修改問(wèn)題以及改進(jìn)點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • SpringCloud 如何使用feign時(shí)的復(fù)雜參數(shù)傳遞

    SpringCloud 如何使用feign時(shí)的復(fù)雜參數(shù)傳遞

    這篇文章主要介紹了SpringCloud 如何使用feign時(shí)的復(fù)雜參數(shù)傳遞方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java詳細(xì)講解包的作用以及修飾符的介紹

    Java詳細(xì)講解包的作用以及修飾符的介紹

    本文主要講述的是包的使用和注意事項(xiàng)和四種訪問(wèn)修飾符public,protected,默認(rèn)的,private的訪問(wèn)范圍及實(shí)例,感興趣的朋友一起來(lái)看看
    2022-05-05
  • Java中Lambda表達(dá)式基礎(chǔ)及使用

    Java中Lambda表達(dá)式基礎(chǔ)及使用

    這篇文章主要介紹了Lambda 是JDK 8 的重要新特性。它允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中),使用 Lambda 表達(dá)式可以使代碼變的更加簡(jiǎn)潔緊湊,使Java代碼更加優(yōu)雅,感興趣的小伙伴一起來(lái)學(xué)習(xí)吧
    2021-08-08
  • SpringBoot整合Elasticsearch實(shí)現(xiàn)索引和文檔的操作方法

    SpringBoot整合Elasticsearch實(shí)現(xiàn)索引和文檔的操作方法

    Elasticsearch 基于 Apache Lucene 構(gòu)建,采用 Java 編寫(xiě),并使用 Lucene 構(gòu)建索引、提供搜索功能,本文分步驟通過(guò)綜合案例給大家分享SpringBoot整合Elasticsearch的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法

    Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法

    下面小編就為大家?guī)?lái)一篇Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-10-10
  • 淺談Java安全編碼之文件和共享目錄的安全性

    淺談Java安全編碼之文件和共享目錄的安全性

    Java程序是跨平臺(tái)的,可以運(yùn)行在windows也可以運(yùn)行在linux。但是平臺(tái)不同,平臺(tái)中的文件權(quán)限也是不同的。windows大家經(jīng)常使用,并且是可視化的權(quán)限管理,這里就不多講了。本文主要講講linux下面的文件的權(quán)限和安全性問(wèn)題,并且探討一下如何在java程序中考慮文件的安全性
    2021-06-06

最新評(píng)論