Java的枚舉,注解和反射(二)
反射
什么是反射?
反射是指在程序運(yùn)行期間,可以通過(guò)Reflection Api提供方法可以獲取任何類(lèi)的內(nèi)部的信息,并能直接操作任意類(lèi)的方法和屬性。反射被視為動(dòng)態(tài)語(yǔ)言的關(guān)鍵。
//在反射之前可以做的事情 @Test public void Test1() { //創(chuàng)建Person類(lèi)的對(duì)象 Person person = new Person("name", 78); //通過(guò)對(duì)象調(diào)用其內(nèi)部的方法和屬性 person.setAge(20); System.out.println(person.toString()); person.show(); //在Person類(lèi)的外部,不能通過(guò)對(duì)象調(diào)用其內(nèi)部的私有的結(jié)構(gòu) } //在反射之后可以做的事情 @Test public void Test2() throws Exception { //通過(guò)反射創(chuàng)建Person類(lèi)的對(duì)象 Class classPerson = Person.class; Constructor constructor = classPerson.getConstructor(String.class, int.class); Object object = constructor.newInstance("Tom", 13); Person person = (Person) object; System.out.println(person.toString()); //通過(guò)反射獲取Person內(nèi)部的屬性和方法 Field name = classPerson.getField("name"); name.set(person, "Jack"); System.out.println(person.toString()); //調(diào)方法 Method show = classPerson.getDeclaredMethod("show"); show.invoke(person); //調(diào)用私有的構(gòu)造方法 Constructor constructor1 = classPerson.getDeclaredConstructor(String.class); constructor1.setAccessible(true); Person person1 = (Person) constructor1.newInstance("Marry"); System.out.println(person1); //調(diào)用私有的方法 Method showNation = classPerson.getDeclaredMethod("showNation", String.class); showNation.setAccessible(true); showNation.invoke(person1, "中國(guó)"); }
結(jié)果:
未使用反射
使用反射:
Person類(lèi)
package reflection; /** * user:ypc; * date:2021-06-20; * time: 13:55; */ public class Person { public String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person() { } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { this.age = age; this.name = name; } private Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public void show() { System.out.println("I am a person"); } private String showNation(String nation) { return nation; } }
反射的用途
1、在日常的第三方應(yīng)用開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到某個(gè)類(lèi)的某個(gè)成員變量、方法或是屬性是私有的或是只對(duì)系統(tǒng)應(yīng)用開(kāi)放,這時(shí)候就可以利用Java的反射機(jī)制通過(guò)反射來(lái)獲取所需的私有成員或是方法 。
2、反射最重要的用途就是開(kāi)發(fā)各種通用框架,比如在spring中,我們將所有的類(lèi)Bean交給spring容器管理,無(wú)論是XML配置Bean還是注解配置,當(dāng)我們從容器中獲取Bean來(lái)依賴注入時(shí),容器會(huì)讀取配置,而配置中給的就是類(lèi)的信息,spring根據(jù)這些信息,需要?jiǎng)?chuàng)建那些Bean,spring就動(dòng)態(tài)的創(chuàng)建這些類(lèi)。
Java程序中許多對(duì)象在運(yùn)行時(shí)會(huì)出現(xiàn)兩種類(lèi)型:運(yùn)行時(shí)類(lèi)型(RTTI)和編譯時(shí)類(lèi)型,例如Person p = new Student();這句代碼中p在編譯時(shí)類(lèi)型為Person,運(yùn)行時(shí)類(lèi)型為Student。程序需要在運(yùn)行時(shí)發(fā)現(xiàn)對(duì)象和類(lèi)的真實(shí)信息。而通過(guò)使用反射程序就能判斷出該對(duì)象和類(lèi)屬于哪些類(lèi)。
在類(lèi)被加載完成之后,就會(huì)在堆區(qū),產(chǎn)生一個(gè)Class對(duì)象,這個(gè)對(duì)象就包含了存這個(gè)類(lèi)的全部的結(jié)構(gòu)信息。我們就可以通過(guò)這個(gè)對(duì)象看到這個(gè)類(lèi)的全部的信息。
這個(gè)對(duì)象就像一面鏡子,通過(guò)這個(gè)鏡子可以看到這個(gè)類(lèi)的全部的信息結(jié)構(gòu)。所以稱之為反射。
正常的方式:通過(guò)引入需要導(dǎo)入的包類(lèi)的名稱---->通過(guò)new來(lái)實(shí)例化---->得到實(shí)例化的對(duì)象
反射的方式:實(shí)例化對(duì)象---->通過(guò)getClass()方法---->得到完整的包類(lèi)的名稱
反射的具體作用
- 在運(yùn)行的時(shí)候判斷任意的一個(gè)對(duì)象所屬的類(lèi)
- 在運(yùn)行的時(shí)候構(gòu)造任意一個(gè)類(lèi)的對(duì)象
- 在運(yùn)行 的時(shí)候判斷任意一個(gè)類(lèi)的成員變量和方法
- 在運(yùn)行的時(shí)獲取泛型的信息
- 在運(yùn)行的時(shí)候調(diào)用任意一個(gè)類(lèi)的成員變量和方法
- 在運(yùn)行的時(shí)候處理注解
- 生成動(dòng)態(tài)代理
反射的主要API
類(lèi)名 用途
Class類(lèi)
代表類(lèi)的實(shí)體,在運(yùn)行的Java應(yīng)用程序中表示類(lèi)和接口
Field類(lèi)
代表類(lèi)的成員變量/類(lèi)的屬性
Method類(lèi)
代表類(lèi)的方法
Constructor類(lèi)
代表類(lèi)的構(gòu)造方法
通過(guò)直接new 的方式和反射 都可以直接調(diào)用公共的結(jié)構(gòu),在開(kāi)發(fā)的時(shí)候應(yīng)該使用哪一個(gè)呢?
建議:使用new 的方式來(lái)創(chuàng)建對(duì)象。
什么時(shí)候使用反射呢?
反射的特性:動(dòng)態(tài)性。就是在編譯的時(shí)候不知道要?jiǎng)?chuàng)建什么樣的對(duì)象的時(shí)候,可以使用反射方式來(lái)創(chuàng)建對(duì)象。比如在后端部署的服務(wù)器,前端傳來(lái)的時(shí)登錄的請(qǐng)求的話,就創(chuàng)建登錄對(duì)應(yīng)的對(duì)象。前端傳來(lái)的是注冊(cè)所對(duì)應(yīng)的請(qǐng)求的話,就創(chuàng)建登錄所對(duì)應(yīng)的對(duì)象,這就是反射的動(dòng)態(tài)特性。
反射的機(jī)制和封裝是不矛盾的呢?
封裝是告訴你不要調(diào),反射可以調(diào)。
Class類(lèi)
在Object類(lèi)中定義了以下的方法,此方法將被所有子類(lèi)繼承:
public final Class getClass()
以上的方法返回值的類(lèi)型是一個(gè)Class類(lèi),此類(lèi)是Java反射的源頭,實(shí)際上所謂反射從程序的運(yùn)行結(jié)果來(lái)看也很好理解,即可以通過(guò)對(duì)象反射求出類(lèi)的名稱。
對(duì)象使用反射后可以得到的信息:某個(gè)類(lèi)的屬性、方法和構(gòu)造器、某個(gè)類(lèi)到底實(shí)現(xiàn)了哪些接口。對(duì)于每個(gè)類(lèi)而言,JRE都為其保留一個(gè)不變的Class類(lèi)型的對(duì)象。一個(gè)Class對(duì)象包含了特定某個(gè)結(jié)構(gòu)( class/interface/enum/annotation/primitive type/void/[])的有關(guān)信息。也就是這些類(lèi)型可以有Class對(duì)象:class 成員內(nèi)部類(lèi)、 靜態(tài)內(nèi)部類(lèi)、 局部?jī)?nèi)部類(lèi) 、 匿名內(nèi)部類(lèi)、接口、數(shù)組、枚舉、注解、基本的數(shù)據(jù)類(lèi)型、void等。
注意:
Class本身也是一個(gè)類(lèi)
Class對(duì)象只能由系統(tǒng)建立對(duì)象
一個(gè)加載的類(lèi)在JVM中只會(huì)有一個(gè)Class實(shí)例
一個(gè)Class對(duì)象對(duì)應(yīng)的是一個(gè)加載到JVM中的一個(gè).class文件
每個(gè)類(lèi)的實(shí)例都會(huì)記得自己是由哪個(gè)Class實(shí)例所生成
通過(guò)Class可以完整地得到一個(gè)類(lèi)中的所有被加載的結(jié)構(gòu)
Class類(lèi)是Reflection的根源,針對(duì)任何你想動(dòng)態(tài)加載、運(yùn)行的類(lèi),只有先獲得相應(yīng)的Class對(duì)象,才能繼續(xù)下去。
關(guān)于java.lang.Class的理解:
類(lèi)的加載過(guò)程:
程序通過(guò)javac.exe命令,生成一個(gè)或多個(gè)字節(jié)碼文件。接著使用java.exe命令來(lái)對(duì)某個(gè)字節(jié)碼文件來(lái)解釋運(yùn)行。將字節(jié)碼文件加載到內(nèi)存中,這個(gè)過(guò)程稱為類(lèi)的加載。加載到內(nèi)存中的類(lèi),就被稱為運(yùn)行時(shí)類(lèi),此運(yùn)行使類(lèi)就稱為Class 的一個(gè)實(shí)例。
Class 實(shí)例就對(duì)應(yīng)著一個(gè)運(yùn)行時(shí)類(lèi),加載到內(nèi)存中的運(yùn)行時(shí)類(lèi),會(huì)緩存一段時(shí)間。在此時(shí)間之內(nèi),可以通過(guò)不同的方式來(lái)獲取運(yùn)行時(shí)類(lèi)。
獲取Class實(shí)例的四種方式
// Class 實(shí)例就對(duì)應(yīng)著運(yùn)行時(shí)類(lèi) @Test public void test3() throws ClassNotFoundException { //方式1 調(diào)用運(yùn)行時(shí)類(lèi)的屬性:.class Class clazz1 = Person.class; System.out.println(clazz1); //方式2 通過(guò)運(yùn)行時(shí)類(lèi)的對(duì)象來(lái)調(diào)用 Person person = new Person(); Class clazz2 = person.getClass(); System.out.println(clazz2); //方式3 通過(guò)Class的靜態(tài)方法 forName(類(lèi)的全路徑名稱) Class clazz3 = Class.forName("reflection.Person"); System.out.println(clazz3); //方式4 通過(guò)類(lèi)加載器:ClassLoader ClassLoader classLoader = ReflectionDemo1.class.getClassLoader(); Class clazz4 = classLoader.loadClass("reflection.Person"); System.out.println(clazz4); System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3); System.out.println(clazz1 == clazz4); }
通過(guò)反射創(chuàng)建運(yùn)行時(shí)類(lèi)的對(duì)象
package reflection; import org.junit.Test; import java.util.Random; /** * user:ypc; * date:2021-06-21; * time: 20:36; */ public class NewInstanceDemo { @Test public void test1() throws IllegalAccessException, InstantiationException { Class<Person> personClass = Person.class; /* newInstance()方法可以創(chuàng)建運(yùn)行時(shí)類(lèi)的實(shí)列,其內(nèi)部也時(shí)調(diào)用內(nèi)的無(wú)參的構(gòu)造方法來(lái)創(chuàng)建對(duì)象 */ Person person = personClass.newInstance(); System.out.println(person); } @Test public void test2() throws IllegalAccessException, InstantiationException, ClassNotFoundException { //在編譯的時(shí)候不知道要?jiǎng)?chuàng)建的對(duì)象。只有運(yùn)行的時(shí)候才知道要?jiǎng)?chuàng)建的對(duì)象 for (int i = 0; i < 100; i++) { int num = new Random().nextInt(3); String classPath = ""; switch (num) { case 0: classPath = "java.util.Date"; break; case 1: classPath = "java.lang.Object"; break; case 2: classPath = "reflection.Person"; break; } Object object = getInstance(classPath); System.out.println(object); } } //創(chuàng)建一個(gè)指定類(lèi)的對(duì)象 public Object getInstance(String classPath) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class clazz = Class.forName(classPath); return clazz.newInstance(); } }
通過(guò)反射獲取運(yùn)行類(lèi)的屬性及權(quán)限修飾符、變量名 、數(shù)據(jù)的類(lèi)型
@Test public void test1(){ //getFields()獲取的是運(yùn)行時(shí)類(lèi)及其父類(lèi)中public的屬性 Class clazz = Person.class; Field[] fields = clazz.getFields(); for (Field field: fields) { System.out.println(field); } System.out.println(); //getDeclaredFields():獲取當(dāng)前運(yùn)行類(lèi)的所有屬性 Field[] declaredFields = clazz.getDeclaredFields(); for (Field field:declaredFields) { System.out.println(field); } }
//權(quán)限修飾符 變量名 數(shù)據(jù)的類(lèi)型 @Test public void test2(){ Class clazz = Person.class; Field[] declaredFields = clazz.getDeclaredFields(); for (Field field:declaredFields) { //權(quán)限修飾符 System.out.println(Modifier.toString(field.getModifiers())+"\t"); //變量名 System.out.println(field.getType()+"\t"); //數(shù)據(jù)的類(lèi)型 System.out.println(field.getName()+"\t"); } }
通過(guò)反射獲取運(yùn)行時(shí)類(lèi)的方法結(jié)構(gòu)及其內(nèi)部結(jié)構(gòu)
package reflection2; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** * user:ypc; * date:2021-06-22; * time: 13:32; */ public class MethodDemo { @Test public void test1() { //獲取當(dāng)前運(yùn)行時(shí)類(lèi)及其父類(lèi)中所有聲明為public的方法 Class clazz = Person.class; Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method); } System.out.println(); //獲取當(dāng)前運(yùn)行時(shí)類(lèi)所有的方法 Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println(method); } } //@xxx注解 //權(quán)限修飾符 方法結(jié)構(gòu) 返回值的類(lèi)型 @Test public void test2() { Class clazz = Person.class; Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method method : declaredMethods) { //獲取方法的注解 Annotation[] annotations = method.getDeclaredAnnotations(); for (Annotation annotation : annotations) { System.out.print(annotation); } //獲取權(quán)限的修飾符 System.out.print(Modifier.toString(method.getModifiers()) + "\t"); //獲取返回值的類(lèi)型 System.out.print(method.getReturnType().getName() + "\t"); //方法名 System.out.print(method.getName()); System.out.print("("); //獲取形參的列表 Class[] parameterTypes = method.getParameterTypes(); if (!(parameterTypes == null && parameterTypes.length == 0)) { for (int i = 0; i < parameterTypes.length; i++) { if (i == parameterTypes.length - 1) { System.out.print(parameterTypes[i].getName() + " args__" + i); } else { System.out.print(parameterTypes[i].getName() + " args__" + i + ","); } } } System.out.print(")"); //獲取方法的異常 Class[] exceptionTypes = method.getExceptionTypes(); if (exceptionTypes.length != 0) { System.out.print("throws"); for (int i = 0; i < exceptionTypes.length; i++) { if (i == exceptionTypes.length - 1) { System.out.print(exceptionTypes[i].getName()); } else { System.out.print(exceptionTypes[i].getName() + ","); } } } System.out.println(); } } }
test1():
test2():
通過(guò)反射獲取運(yùn)行時(shí)類(lèi)的構(gòu)造結(jié)構(gòu)
@Test public void test1() { Class clazz = Person.class; //獲取運(yùn)行時(shí)類(lèi)的public構(gòu)造方法 Constructor[] constructors = clazz.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } System.out.println(); //獲取當(dāng)前運(yùn)行時(shí)類(lèi)中的所有的構(gòu)造方法 Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } }
通過(guò)反射獲取運(yùn)行時(shí)類(lèi)的父類(lèi)和父類(lèi)的泛型、注解、接口、所在包
反射所使用到的包、接口、類(lèi)、注釋等👇
package reflection2; /** * user:ypc; * date:2021-06-21; * time: 21:38; */ public interface MyInterface { void info(); } package reflection2; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; @Target({TYPE, FIELD,CONSTRUCTOR,ANNOTATION_TYPE,PARAMETER,LOCAL_VARIABLE,METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value() default "hello"; } package reflection2; import java.io.Serializable; /** * user:ypc; * date:2021-06-21; * time: 21:13; */ public class Creature<T> implements Serializable { private char gender; public double weight; private void breath(){ System.out.println("creature breath"); } public void eat(){ System.out.println("creature eat"); } } package reflection2; @MyAnnotation(value = "hi") public class Person extends Creature<String> implements Comparable, MyInterface { private String name; public int age; int id; Person() { } @MyAnnotation(value = "a") private Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } private String show(String nation) throws NullPointerException,CloneNotSupportedException { System.out.println("I am form" + nation); return nation; } private static void showInterests(){ System.out.println("I like programmer"); } @MyAnnotation(value = "b") public String show2(String publicMethod) { return publicMethod; } @Override public int compareTo(Object o) { return 0; } @Override public void info() { System.out.println("I am a Person"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}'; } }
package reflection2; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.ParameterizedType; import java.util.Arrays; /** * user:ypc; * date:2021-06-22; * time: 15:11; */ public class ConstructorDemo { @Test public void test1() { Class clazz = Person.class; //獲取運(yùn)行時(shí)類(lèi)的public構(gòu)造方法 Constructor[] constructors = clazz.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } System.out.println(); //獲取當(dāng)前運(yùn)行時(shí)類(lèi)中的所有的構(gòu)造方法 Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } } @Test public void test2() { //獲取運(yùn)行時(shí)類(lèi)的父類(lèi) Class clazz = Person.class; System.out.println(clazz.getSuperclass()); //獲取運(yùn)行時(shí)類(lèi)帶泛型的父類(lèi) System.out.println(clazz.getGenericSuperclass()); //獲取父類(lèi)所帶的泛型 System.out.println(((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0]); System.out.println(); //獲取運(yùn)行時(shí)類(lèi)的接口 Class[] interfaces = clazz.getInterfaces(); for (Class intF : interfaces) { System.out.println(intF); } System.out.println(); //獲取運(yùn)行類(lèi)的父類(lèi)的接口 Class[] supInterfaces = clazz.getSuperclass().getInterfaces(); for (Class intF : supInterfaces) { System.out.println(intF); } //獲取運(yùn)行時(shí)類(lèi)的包 System.out.println(clazz.getPackage()); System.out.println(); //獲取運(yùn)行時(shí)類(lèi)的注解 System.out.println(Arrays.toString(clazz.getAnnotations())); ; } }
通過(guò)反射調(diào)用運(yùn)行時(shí)類(lèi)的指定屬性、方法、構(gòu)造方法
package reflection2; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * user:ypc; * date:2021-06-22; * time: 15:57; * 調(diào)用運(yùn)行時(shí)類(lèi)的指定的結(jié)構(gòu):方法、屬性、構(gòu)造方法 */ public class ReflectionDemo { @Test public void test1() throws Exception { Class clazz = Person.class; //創(chuàng)建運(yùn)行時(shí)類(lèi)的實(shí)例 Person person = (Person) clazz.newInstance(); //獲取指定的屬性,要求運(yùn)行時(shí)類(lèi)的屬性為public Field id = clazz.getField("id"); id.set(person, 10001); int fieldId = (int) id.get(person); System.out.println(fieldId); } @Test public void test2() throws Exception { Class clazz = Person.class; //創(chuàng)建運(yùn)行時(shí)類(lèi)的實(shí)例 Person person = (Person) clazz.newInstance(); //getDeclaredField獲取運(yùn)行時(shí)類(lèi)指定的屬性 Field name = clazz.getDeclaredField("name"); //保證當(dāng)前的屬性是可訪問(wèn)的 name.setAccessible(true); //設(shè)置指定對(duì)象的屬性值 name.set(person, "Tom"); System.out.println(name.get(person)); } //操作運(yùn)行時(shí)類(lèi)的方法 @Test public void test3() throws Exception { Class clazz = Person.class; //創(chuàng)建運(yùn)行時(shí)類(lèi)的實(shí)例 Person person = (Person) clazz.newInstance(); //1.獲取某個(gè)指定的方法 getDeclaredMethod()第一個(gè)參數(shù)是指明獲取的方法的名稱,第二個(gè)參數(shù)是指明獲取的方法的參數(shù)列表 Method show = clazz.getDeclaredMethod("show", String.class); //2.保證當(dāng)前的方法是可訪問(wèn)的 show.setAccessible(true); //3.使用invoke()方法 第一個(gè)參數(shù)是方法的調(diào)用者,第二個(gè)參數(shù)是給方法形參賦值的實(shí)參 show.invoke(person, " CHN"); //invoke 方法的返回值就是調(diào)用的方法的返回值 Object returnValue = show.invoke(person, " CHN"); System.out.println(returnValue); //調(diào)用靜態(tài)的方法 Method showInterests = clazz.getDeclaredMethod("showInterests"); showInterests.setAccessible(true); showInterests.invoke(Person.class); //如果運(yùn)行時(shí)類(lèi)地方?jīng)]有返回值的話,那么invoke的返回值就是null System.out.println(showInterests.invoke(Person.class)); } /* 調(diào)用運(yùn)行時(shí)類(lèi)的指定的構(gòu)造方法 */ @Test public void test4() throws Exception { Class clazz = Person.class; //1.參數(shù)是構(gòu)造方法的參數(shù)列表 Constructor constructor = clazz.getDeclaredConstructor(String.class); //2.保證此構(gòu)造方法是可以訪問(wèn)的 constructor.setAccessible(true); //3.調(diào)用次構(gòu)造方法創(chuàng)建運(yùn)行時(shí)類(lèi)的對(duì)象 Person person = (Person) constructor.newInstance("Tom"); System.out.println(person); } }
test1():
test2():
test3():
test4():
總結(jié)
本篇文章的上半部分就到這里了,希望對(duì)你有所幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringCloud Gateway 利用 Mysql 實(shí)現(xiàn)動(dòng)態(tài)路由的方法
這篇文章主要介紹了SpringCloud Gateway 利用 Mysql 實(shí)現(xiàn)動(dòng)態(tài)路由的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02基于jQuery獲取table數(shù)據(jù)發(fā)送到后端
這篇文章主要介紹了基于jQuery獲取table數(shù)據(jù)發(fā)送到后端,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02SpringCloud學(xué)習(xí)筆記之Feign遠(yuǎn)程調(diào)用
Feign是一個(gè)聲明式的http客戶端。其作用就是幫助我們優(yōu)雅的實(shí)現(xiàn)http請(qǐng)求的發(fā)送。本文將具體為大家介紹一下Feign的遠(yuǎn)程調(diào)用,感興趣的可以了解一下2021-12-12Spring?boot詳解fastjson過(guò)濾字段為null值如何解決
這篇文章主要介紹了解決Spring?boot中fastjson過(guò)濾字段為null值的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07詳談java編碼互轉(zhuǎn)(application/x-www-form-urlencoded)
下面小編就為大家?guī)?lái)一篇詳談java編碼互轉(zhuǎn)(application/x-www-form-urlencoded)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07Java入門(mén)基礎(chǔ)之抽象類(lèi)與接口
對(duì)于面向?qū)ο缶幊虂?lái)說(shuō),抽象是它的一大特征之一,在 Java 中可以通過(guò)兩種形式來(lái)體現(xiàn)OOP的抽象:接口和抽象類(lèi),下面這篇文章主要給大家介紹了關(guān)于Java入門(mén)基礎(chǔ)之抽象類(lèi)與接口的相關(guān)資料,需要的朋友可以參考下2022-02-02基于springBoot配置文件properties和yml中數(shù)組的寫(xiě)法
這篇文章主要介紹了springBoot配置文件properties和yml中數(shù)組的寫(xiě)法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11