Java反射基础(一)--Class对象获取
Classes
?
??????? Java中,任何一個對象要么是一個引用類型要么是基本數據類型.引用類型指的是那些直接或間接
??? Java.lang.Object的類.Classse,enum,和接口都是應用類型.基本類型是一個固定的集合,它包括:
??? boolean,? byte,short, int, long,char,float, double. java.lang.String和所有的基本類型的
??? 包裹類(Wrapper classes),比如java.lang.Double,接口java.io.Serializabl,和枚舉
??? Jvax.swing.SortOrder都是引用類型.
?????? 對于每種類型的對象,java虛擬機都會為其初始化一個不變的java.lang.Class實例.這個實例提供了可以在運
????行時檢查對象屬性的方法.Class對象還具有創建一個新對象的能力.最重要的是,它是所有java發射的入口.
?
???? 1.獲取Class對象
???????? Java.lang.reflect包下的所有類都沒有公共的構造函數.要得到Class對象,,需要調用Class類中的適當的方法。
???? 有幾種法可以得到一個Class對象:
?
?????a.使用Object.getClass()
???????? 果已經有一個要反射的;類的實例,那么最簡單的方法去獲得該類的Class對象便是使用Object.getClass()方法.
?????然而這個方法只適用于要反射的類是引用類型.給出一些示例進行說明:
?
<span style="font-family:SimHei;font-size:14px;">Class c = "string".getClass(); 返回String類的Class對象 enum E { A, B }Class c = A.getClass(); A是一個枚舉類型,因此getClass(),返回枚舉類型E的Class對象. byte[] bytes = new byte[1024]; Class c = bytes.getClass(); 因為數組也是Objects,因此可以對數組調用getClass(), 該示例返回的是byte的Class對象. import java.util.HashSet; import java.util.Set; Set<String> s = new HashSet<String>(); Class c = s.getClass(); 在這個示例中,java.util.Set是一個接口,而java.util.HashSet實現了這個借口,那么getClass()返回的Class對象是java.util.HashSet的Class對象.</span>
?
? ??? b.使用.class 語法
?????????? 如果你只知道這個類型,但是卻沒辦法得到這個類型的一個實例,那么獲得該類型的Class對象的一種方法便
?????? 是使用.class.同時這也是最簡單的獲得基本類型得Class實例的方法.下面給出一些示例進行說明:
?
<span style="font-size:14px;"><span style="font-family:SimHei;">boolean b; Class c = b.getClass(); // compile-time errorClass c = boolean.class; // correct 語句boolean.getClass()將會產生一個編譯時錯誤,因為Boolean是一個基本數據類型,不能使用該方法獲取Class對象. Class c = java.io.PrintStream.class;Class c = int[][][].class; </span> </span>??????? c.Class.forName()
???????????如果你知道一個class文件的完全名稱,你可以使用Class類中的靜態方法Class.forName()獲取類的Class對象.??????
<span style="font-family:SimHei;font-size:14px;">Class c = Class.forName("com.duke.MyLocaleServiceProvider");這條語句將會創建一個Class實例使用參數中指定的類.Class cDoubleArray = Class.forName("[D");Class cStringArray = Class.forName("[[Ljava.lang.String;"); 變量cDoubleArray將包含一個基本類型Double的Class實例,該語句等價于double[].class 變量CStringArray中包含了一個對應于兩個維度的String數組的Class對象.該語句等價于String[][].class </span>
?
?????? d.基本類型包裹類的TYPE屬性
??????????? .class語法是一個很方便的獲得基本類型的class對象的方法,然而還有另外一種方法可以獲得基本
??????? 類型的Class對象.所有的基本類型和void都有一個包裹類在java.lang包中.這些類將基本類型封裝起來
??????? 形成了一個引用類型.同時每個包裹類都包含了一個屬性叫做TYPE.TYPE等同于基本類型的Class對象.
<span style="font-family:SimHei;font-size:14px;">Class c = Double.TYPE;Class c = Void.TYPE; </span>?
??????? e.返回類型是Class對象的方法
??????????? 有一些反射API方法可以返回Class對象,但是你想要使用這些方法你需要已經直接或者間接的得到了
??????? class對象.給出示例進行說明:
<span style="font-family:SimHei;font-size:14px;">Class.getSuperclass() 返回該類的父類的class對象.Class c = javax.swing.JButton.class.getSuperclass();javax.swing.JButton 的父類是 javax.swing.AbstractButton.</span>
?
?
?
????????????????????? java.lang.reflect.Field.getDeclaringClass()
????????????????????? java.lang.reflect.Method.getDeclaringClass()
????????????????????? java.lang.reflect.Constructor.getDeclaringClass()?????? 返回定義該成員的類的Class實例.
?
<span style="font-family:SimHei;font-size:14px;">import java.lang.reflect.Field;Field f = System.class.getField("out"); Class c = f.getDeclaringClass(); </span>
?
??? 2.獲取類的修飾符和類型?
??? 一個類可以有一個或者多個控制符??????
<span style="font-size:14px;"><span style="font-family:SimHei;"> 訪問控制符:<span>?</span><code style="FONT-FAMILY: Monaco,Courier,'Courier New'">public</code>,<span>?</span><code style="FONT-FAMILY: Monaco,Courier,'Courier New'">protected</code>, and<span>?</span><code style="FONT-FAMILY: Monaco,Courier,'Courier New'">private</code></span></span>- 需要重寫控制符:?abstract
- 限定一個實例控制符:static
- 禁止修改控制符:?final
- 迫使嚴格浮點控制符:?strictfp
- 注解
???ClassDeclarationSpy 演示了如何獲取一個類的聲明的組件,包括該類的修飾符,泛型參數,實現的接口,和繼承路徑.
???如果你實現了?java.lang.reflect.AnnotatedElement?,就可以獲取運行時注解.
<span style="font-family:SimHei;font-size:14px;">import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.Arrays; import java.util.ArrayList; import java.util.List; import static java.lang.System.out;public class ClassDeclarationSpy {public static void main(String... args) {try {Class<?> c = Class.forName(args[0]);out.format("Class:%n %s%n%n", c.getCanonicalName());out.format("Modifiers:%n %s%n%n",Modifier.toString(c.getModifiers()));out.format("Type Parameters:%n");TypeVariable[] tv = c.getTypeParameters();if (tv.length != 0) {out.format(" ");for (TypeVariable t : tv)out.format("%s ", t.getName());out.format("%n%n");} else {out.format(" -- No Type Parameters --%n%n");}out.format("Implemented Interfaces:%n");Type[] intfs = c.getGenericInterfaces();if (intfs.length != 0) {for (Type intf : intfs)out.format(" %s%n", intf.toString());out.format("%n");} else {out.format(" -- No Implemented Interfaces --%n%n");}out.format("Inheritance Path:%n");List<Class> l = new ArrayList<Class>();printAncestor(c, l);if (l.size() != 0) {for (Class<?> cl : l)out.format(" %s%n", cl.getCanonicalName());out.format("%n");} else {out.format(" -- No Super Classes --%n%n");}out.format("Annotations:%n");Annotation[] ann = c.getAnnotations();if (ann.length != 0) {for (Annotation a : ann)out.format(" %s%n", a.toString());out.format("%n");} else {out.format(" -- No Annotations --%n%n");}// production code should handle this exception more gracefully} catch (ClassNotFoundException x) {x.printStackTrace();}}private static void printAncestor(Class<?> c, List<Class> l) {Class<?> ancestor = c.getSuperclass();if (ancestor != null) {l.add(ancestor);printAncestor(ancestor, l);}} }</span>
?
?
它被聲明在java.util.concurrent.ConcurrentNavigableMap?中,聲明如下:
<span style="font-family:SimHei;font-size:14px;">public interface ConcurrentNavigableMap<K,V>extends ConcurrentMap<K,V>, NavigableMap<K,V> <span style="BACKGROUND-COLOR: #ffffff"></span></span> ? 注意,因為它是一個接口,它隱式的是abstract.編譯器會自動的將這個修飾符添加進去. ? <span style="font-family:SimHei;font-size:14px;">$ java ClassDeclarationSpy "[Ljava.lang.String;" Class:java.lang.String[]Modifiers:public abstract finalType Parameters:-- No Type Parameters --Implemented Interfaces:interface java.lang.Cloneableinterface java.io.SerializableInheritance Path:java.lang.ObjectAnnotations:-- No Annotations --</span>?
?? 由于數組是運行時的對象,因此它的所有信息被java虛擬機定義.特別的是,數組實現了?Cloneable和java.io.Serializable?
?? 和它的直接父類是Object.
?
<span style="font-family:SimHei;font-size:14px;">$ java ClassDeclarationSpy java.io.InterruptedIOException Class:java.io.InterruptedIOExceptionModifiers:publicType Parameters:-- No Type Parameters --Implemented Interfaces:-- No Implemented Interfaces --Inheritance Path:java.io.IOExceptionjava.lang.Exceptionjava.lang.Throwablejava.lang.ObjectAnnotations:-- No Annotations --</span>? <span style="font-family:SimHei;font-size:14px;">$ java ClassDeclarationSpy java.security.Identity Class:java.security.IdentityModifiers:public abstractType Parameters:-- No Type Parameters --Implemented Interfaces:interface java.security.Principalinterface java.io.SerializableInheritance Path:java.lang.ObjectAnnotations:@java.lang.Deprecated()</span>
?
?
??? 3.訪問類成員
???? 在Class中有兩類方法可以用來訪問類的字段,方法,構造函數.第一類方法是查找本類中特定的方法,
???? 另一類是查找本類及其父類的方法.
???? 在面的表格是對這些方法的簡單總結.
| getDeclaredField() | no | no | yes |
| getField() | no | yes | no |
| getDeclaredFields() | yes | no | yes |
| getFields() | yes | yes | no |
| getDeclaredMethod() | no | no | yes |
| getMethod() | no | yes | no |
| getDeclaredMethods() | yes | no | yes |
| getMethods() | yes | yes | no |
| getDeclaredConstructor() | no | N/A1 | yes |
| getConstructor() | no | N/A1 | no |
| getDeclaredConstructors() | yes | N/A1 | yes |
| getConstructors() | yes | N/A1 | no |
1?Constructors are not inherited..
??? 給出你感興趣的類的名稱和類成員的類型(CONSTRUCTOR, FIELD, METHOD, CLASS, ALL),ClassSpy 將會使用get*s()?
?? 方法去得到該類型公共成員的列表,包括繼承的成員,
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Member; import static java.lang.System.out;enum ClassMember { CONSTRUCTOR, FIELD, METHOD, CLASS, ALL }public class ClassSpy {public static void main(String... args) {try {Class<?> c = Class.forName(args[0]);out.format("Class:%n %s%n%n", c.getCanonicalName());Package p = c.getPackage();out.format("Package:%n %s%n%n",(p != null ? p.getName() : "-- No Package --"));for (int i = 1; i < args.length; i++) {switch (ClassMember.valueOf(args[i])) {case CONSTRUCTOR:printMembers(c.getConstructors(), "Constructor");break;case FIELD:printMembers(c.getFields(), "Fields");break;case METHOD:printMembers(c.getMethods(), "Methods");break;case CLASS:printClasses(c);break;case ALL:printMembers(c.getConstructors(), "Constuctors");printMembers(c.getFields(), "Fields");printMembers(c.getMethods(), "Methods");printClasses(c);break;default:assert false;}}// production code should handle these exceptions more gracefully} catch (ClassNotFoundException x) {x.printStackTrace();}}private static void printMembers(Member[] mbrs, String s) {out.format("%s:%n", s);for (Member mbr : mbrs) {if (mbr instanceof Field)out.format(" %s%n", ((Field)mbr).toGenericString());else if (mbr instanceof Constructor)out.format(" %s%n", ((Constructor)mbr).toGenericString());else if (mbr instanceof Method)out.format(" %s%n", ((Method)mbr).toGenericString());}if (mbrs.length == 0)out.format(" -- No %s --%n", s);out.format("%n");}private static void printClasses(Class<?> c) {out.format("Classes:%n");Class<?>[] clss = c.getClasses();for (Class<?> cls : clss)out.format(" %s%n", cls.getCanonicalName());if (clss.length == 0)out.format(" -- No member interfaces, classes, or enums --%n");out.format("%n");} }?
?? 給出一個示例,以及相應輸出結果
<span style="font-family:SimHei;font-size:14px;">$ java ClassSpy java.lang.ClassCastException CONSTRUCTOR Class:java.lang.ClassCastExceptionPackage:java.langConstructor:public java.lang.ClassCastException()public java.lang.ClassCastException(java.lang.String</span>
?
?
$ java ClassSpy ClassMember FIELD METHOD Class:ClassMemberPackage:-- No Package --Fields:public static final ClassMember ClassMember.CONSTRUCTORpublic static final ClassMember ClassMember.FIELDpublic static final ClassMember ClassMember.METHODpublic static final ClassMember ClassMember.CLASSpublic static final ClassMember ClassMember.ALLMethods:public static ClassMember ClassMember.valueOf(java.lang.String)public static ClassMember[] ClassMember.values()public final int java.lang.Enum.hashCode()public final int java.lang.Enum.compareTo(E)public int java.lang.Enum.compareTo(java.lang.Object)public final java.lang.String java.lang.Enum.name()public final boolean java.lang.Enum.equals(java.lang.Object)public java.lang.String java.lang.Enum.toString()public static <T> T java.lang.Enum.valueOf(java.lang.Class<T>,java.lang.String)public final java.lang.Class<E> java.lang.Enum.getDeclaringClass()public final int java.lang.Enum.ordinal()public final native java.lang.Class<?> java.lang.Object.getClass()public final native void java.lang.Object.wait(long) throwsjava.lang.InterruptedExceptionpublic final void java.lang.Object.wait(long,int) throwsjava.lang.InterruptedExceptionpublic final void java.lang.Object.wait() hrows java.lang.InterruptedExceptionpublic final native void java.lang.Object.notify()public final native void java.lang.Object.notifyAll()
?
?? 接口?java.nio.channels.ReadableByteChannel?定義了?read(). 其余的方法都是繼承自父類.
???
?? 對于字段結果的字段部分,枚舉常量被列了出來.
?? 對于字段結果的方法部分,發現方法的名稱包括定義這個方法的類的名稱. toString() 方法是被Enum是實現的,而不是
?? 繼承Object的.如果使用Field.getDeclaringClass(),段代碼可以被修改的更加明顯.下面的代碼段展示了一個可行的解決辦法:
<span style="font-family:SimHei;font-size:14px;">if (mbr instanceof Field) {Field f = (Field)mbr;out.format(" %s%n", f.toGenericString());out.format(" -- declared in: %s%n", f.getDeclaringClass()); } </span>?
總結
以上是生活随笔為你收集整理的Java反射基础(一)--Class对象获取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openssl c++实现bouncyc
- 下一篇: java美元兑换,(Java实现) 美元