java反射随意值_Java反射笔记
Java反射
反射庫提供了一個(gè)豐富且精巧的工具集,可以用來編寫能夠動(dòng)態(tài)操縱Java代碼的程序。能夠分析類能力的程序稱為反射(reflective)。反射機(jī)制的功能極為強(qiáng)大,反射機(jī)制可以用來:
在運(yùn)行時(shí)分析類的能力
在運(yùn)行時(shí)檢查對(duì)象,例如,編寫一個(gè)適用于所有類的toString方法
實(shí)現(xiàn)泛型數(shù)組操作代碼
利用Method對(duì)象
1、Class類
在程序運(yùn)行期間,Java運(yùn)行時(shí)系統(tǒng)始終為所有對(duì)象維護(hù)一個(gè)運(yùn)行時(shí)類型標(biāo)識(shí)。這個(gè)信息會(huì)跟蹤每個(gè)對(duì)象所屬的類。虛擬機(jī)利用運(yùn)行時(shí)類型信息選擇要執(zhí)行的正確的方法。
可以使用一個(gè)特殊的Java類訪問這些信息。保存這些信息的類名為Class。
三種獲得Class類對(duì)象的方法:
class.getClass()
Class.forName(className)
class.class
虛擬機(jī)為每個(gè)類型管理一個(gè)唯一的Class對(duì)象。因此,可以使用==運(yùn)算符實(shí)現(xiàn)兩個(gè)類對(duì)象的比較。例如,
if(Employee.getClass()==Employee.class)//返回結(jié)果為true
如果有一個(gè)Class類型的對(duì)象,可以用它來構(gòu)造類的實(shí)例。調(diào)用getConstructor方法將得到一個(gè)Constructor類型的對(duì)象,然后使用newInstance方法來構(gòu)造一個(gè)實(shí)例。例如:
Class cl = Class.forName("java.util.Random");
Object obj = cl.getConstructor().newInstance;
如果這個(gè)類沒有無參數(shù)的構(gòu)造器,getConstructor方法會(huì)拋出一個(gè)異常。
API
java.lang.Class
static Class forName(String className)
返回一個(gè)Class對(duì)象,表示名為className的類
Constructor getConstructor(Class... paramterTypes)
生成一個(gè)對(duì)象,描述有指定參數(shù)類型的構(gòu)造器
java.lang.reflect.Constructor
Object newInstance(Object... params)
將params傳遞到構(gòu)造器,來構(gòu)造這個(gè)構(gòu)造器聲明類的一個(gè)新實(shí)例
2、資源
類通常有一些關(guān)聯(lián)的數(shù)據(jù)文件,例如
圖像和聲音文件
包含消息字符串和按鈕標(biāo)簽的文本文件。
Class類提供了一個(gè)很有用的服務(wù)可以查找資源文件。下面給出必要的步驟:
獲得擁有資源的類的Class對(duì)象,例如,ResourceTest.class
有些方法,如ImageIcon類的getImage方法,接受描述資源位置URL。則要調(diào)用
URL url = class.getResource("about.gif")
否則,使用getResourceAsStream方法得到一個(gè)輸入流來讀取文件中的數(shù)據(jù)
ResourceTest.java
/**
* 使用反射讀取資源
*/
public class ResourceTest {
public static void main(String[] args) throws IOException {
Class cl = ResourceTest.class;
URL url = cl.getResource("about.jpg");
ImageIcon icon = new ImageIcon(url);
InputStream stream = cl.getResourceAsStream("about.txt");//相對(duì)路徑
byte[] bytes = new byte[1024];
stream.read(bytes);
String about = new String(bytes, "UTF-8");
InputStream stream2 = cl.getResourceAsStream("/com/company/reflection/about.txt");//絕對(duì)路徑
stream2.read(bytes);
String title = new String(bytes, StandardCharsets.UTF_8).trim();
JOptionPane.showMessageDialog(null,about,title,JOptionPane.INFORMATION_MESSAGE,icon);
}
}
API
java.lang.Class
URL getResource(String name)
InputStream getResourceAsStream(String name)
找到與類位于同一位置的資源,返回一個(gè)可以用來加載資源的URL或者輸入流。如果沒有找到資源,則返回null,所以不會(huì)拋出異常或者I/O錯(cuò)誤
3、利用反射分析類的能力
在java.lang.reflect包中有三個(gè)類Field、Method、Constructor分別用來描述類的字段、方法和構(gòu)造器。這三個(gè)類都有一個(gè)叫做getName的方法,用來返回字段、方法或構(gòu)造器的名稱。
Field類有一個(gè)getType方法,用來返回描述字段類型的一個(gè)對(duì)象,這個(gè)對(duì)象的類型同樣是Class。Method和Constructor類有報(bào)告參數(shù)類型的方法,Method類還有一個(gè)報(bào)告返回類型的方法。這三個(gè)類都有一個(gè)名為getModifiers的方法,它將返回一個(gè)整數(shù),用不同的0/1位描述所使用的修飾符,如public和static。另外,還可以利用java.lang.reflect包中的Modifier類的靜態(tài)方法分析getModifiers返回的這個(gè)整數(shù)。例如,可以使用Modifier類中的isPublic、isPrivate或isFinal判斷方法或構(gòu)造器是public、private還是final。我們需要做的就是在getModifiers返回的整數(shù)上調(diào)用Modifier類中適當(dāng)?shù)姆椒?#xff0c;另外,還可以利用Modifier.toString方法將修飾符打印出來。
ReflectionTest.java
/**
* 使用反射分析類的能力
*/
public class ReflectionTest {
public static void main(String[] args) throws ClassNotFoundException {
String name;
if(args.length>0) name = args[0];
else
{
Scanner in = new Scanner(System.in);
System.out.println("Enter class name (e.g. java.util.Date): ");
name = in.next();
}
Class cl = Class.forName(name);//使用name獲取Class
Class supercl = cl.getSuperclass();//獲取父類的class
String modifiers = Modifier.toString(cl.getModifiers());//獲取修飾符
if(modifiers.length()>0) System.out.print(modifiers+" ");
System.out.print("class "+name);
if(supercl != null && supercl != Object.class) System.out.print(" extends "+supercl.getName());
System.out.print("\n{\n");
printConstructors(cl);
System.out.println();
printMethods(cl);
System.out.println();
printFields(cl);
System.out.println("}");
}
/**
* prints all constructors of a class
*/
public static void printConstructors(Class cl){
Constructor[] constructors = cl.getDeclaredConstructors();//獲取全部構(gòu)造器的數(shù)組
for(Constructor c : constructors){//遍歷構(gòu)造器數(shù)組
String name = c.getName();//獲取構(gòu)造器的name
System.out.print(" ");
String modifiers = Modifier.toString(c.getModifiers());//獲取構(gòu)造器的修飾符
if(modifiers.length()>0) System.out.print(modifiers+" ");
System.out.print(name+"(");
Class[] parameterTypes = c.getParameterTypes();//獲取構(gòu)造器的參數(shù)數(shù)組
for(int j = 0; j < parameterTypes.length; j++){//遍歷參數(shù)數(shù)組
if(j>0) System.out.print(", ");//逗號(hào)分隔開
System.out.print(parameterTypes[j].getName());//打印參數(shù)name
}
System.out.println(");");
}
}
/**
* prints all methods of a class
*/
public static void printMethods(Class cl){
Method[] methods = cl.getDeclaredMethods();
for(Method m : methods){
Class> returnType = m.getReturnType();
String name = m.getName();
System.out.print(" ");
//print modifiers,return type and method name
String modifiers = Modifier.toString(m.getModifiers());
if(modifiers.length()>0) System.out.print(modifiers + " ");
System.out.print(returnType.getName() + " " + name + "(");
//print parameter types
Class[] parameterTypes = m.getParameterTypes();
for(int j = 0; j
if(j>0) System.out.print(", ");
System.out.print(parameterTypes[j].getName());
}
System.out.println(");");
}
}
/**
* prints all fields of a class
*/
public static void printFields(Class cl){
Field[] fields = cl.getDeclaredFields();
for(Field field : fields){
Class type = field.getType();
String name = field.getName();
System.out.print(" ");
String modifiers = Modifier.toString(field.getModifiers());
if(modifiers.length()>0) System.out.print(modifiers + " ");
System.out.println(type.getName() + " "+ name + ";");
}
}
}
輸入
java.lang.Double
輸出
public final class java.lang.Double extends java.lang.Number
{
public java.lang.Double(double);
public java.lang.Double(java.lang.String);
public boolean equals(java.lang.Object);
public static java.lang.String toString(double);
public java.lang.String toString();
public int hashCode();
public static int hashCode(double);
public static double min(double, double);
public static double max(double, double);
public static native long doubleToRawLongBits(double);
public static long doubleToLongBits(double);
public static native double longBitsToDouble(long);
public volatile int compareTo(java.lang.Object);
public int compareTo(java.lang.Double);
public byte byteValue();
public short shortValue();
public int intValue();
public long longValue();
public float floatValue();
public double doubleValue();
public static java.lang.Double valueOf(java.lang.String);
public static java.lang.Double valueOf(double);
public static java.lang.String toHexString(double);
public static int compare(double, double);
public static boolean isNaN(double);
public boolean isNaN();
public static boolean isFinite(double);
public static boolean isInfinite(double);
public boolean isInfinite();
public static double sum(double, double);
public static double parseDouble(java.lang.String);
public static final double POSITIVE_INFINITY;
public static final double NEGATIVE_INFINITY;
public static final double NaN;
public static final double MAX_VALUE;
public static final double MIN_NORMAL;
public static final double MIN_VALUE;
public static final int MAX_EXPONENT;
public static final int MIN_EXPONENT;
public static final int SIZE;
public static final int BYTES;
public static final java.lang.Class TYPE;
private final double value;
private static final long serialVersionUID;
}
API
java.lang.Class
Field[] getFields()
返回這個(gè)類支持的公共字段
Field[] getDeclaredFields()
返回類中聲明的全部字段
Method[] getMethods()
返回這個(gè)類支持的公共方法
Field[] getDeclaredMethods()
返回類中聲明的全部方法
Constructor[] getConstructors()
返回這個(gè)類支持的公共構(gòu)造器
Constructor[] getDeclaredConstructors()
返回類中聲明的全部構(gòu)造器
java.lang.reflect.Field
java.lang.reflect.Method
java.lang.reflect.Constructor
int getModifiers()
返回一個(gè)整數(shù),描述這個(gè)構(gòu)造器、方法或字段的修飾符。使用Modifier類中的方法來分析這個(gè)返回值
String getName()
返回一個(gè)表示構(gòu)造器名、方法名或字段名的字符串
Class[] getParamterTypes() (在Constructor 和 Method classes 類中)
返回一個(gè)Class對(duì)象數(shù)組,其中各個(gè)對(duì)象表示參數(shù)的類型。
Class getReturnType() (在 Method 類中)
返回一個(gè)用于表示返回類型的Class對(duì)象
java.lang.reflect.Modifier
static String toString(int modifiers)
返回一個(gè)字符串,包含對(duì)應(yīng)modifiers中位設(shè)置的修飾符
4、使用反射在運(yùn)行時(shí)分析對(duì)象
在編寫程序時(shí),如果知道想要查看的字段名和類型,查看對(duì)象中指定字段的內(nèi)容是一件很容易的事情。而利用反射機(jī)制可以查看在編譯時(shí)還不知道的對(duì)象字段。
要做到這一點(diǎn),關(guān)鍵方法時(shí)Field類中的get方法。如果f是一個(gè)Field類型的對(duì)象,obj是某個(gè)包含f字段的類的對(duì)象,f.get(obj)將返回一個(gè)對(duì)象,其值為obj的當(dāng)前字段值。
ObjectAnalyzerTest.java
public class ObjectAnalyzerTest {
public static void main(String[] args) throws IllegalAccessException {
ArrayList squares = new ArrayList<>();
for (int i = 1; i <= 5; i++)
squares.add(i*i);
System.out.println(new ObjectAnalyzer().toString(squares));
}
}
ObjectAnalyzer.java
/**
* 使用反射在運(yùn)行時(shí)分析對(duì)象
*/
public class ObjectAnalyzer {
private ArrayList visted = new ArrayList<>();
/**
* 將對(duì)象轉(zhuǎn)換為列出所有字段的字符串表示形式
*/
public String toString(Object obj) throws IllegalAccessException {
if (obj == null) return null;
if (visted.contains(obj)) return "...";
visted.add(obj);
Class cl = obj.getClass();
if (cl == String.class) return (String)obj;
if (cl.isArray()){
String r = cl.getComponentType() + "[]{";// cl.getComponentType:返回表示數(shù)組的元素類型的Class
for (int i = 0; i< Array.getLength(obj); i++){
if (i > 0) r += ",";
Object val = Array.get(obj, i);
if (cl.getComponentType().isPrimitive()) r += val;// 如果是基本類型直接追加
else r += toString(val);// 如果不是基本類型遞歸調(diào)用toString方法
}
return r + "}";
}
String r = cl.getName();
// 檢查此類和所有超類的字段
do{
r += "[";
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields,true);// 設(shè)置一個(gè)對(duì)象數(shù)組的可訪問標(biāo)志
// 獲取所有字段的名稱和值
for (Field field : fields){
if (!Modifier.isStatic(field.getModifiers())){
if (!r.endsWith("[")) r += ",";
r += field.getName() + "=";
Class type = field.getType();
Object val = field.get(obj);// 返回obj對(duì)象中用這個(gè)Field對(duì)象描述的字段的值
if (type.isPrimitive()) r += val;// 如果是基本類型直接追加
else r += toString(val);// 如果不是基本類型遞歸調(diào)用toString方法
}
}
r += "]";
cl = cl.getSuperclass();
}
while (cl != null);
return r;
}
}
輸出
java.util.ArrayList[elementData=class java.lang.Object[]{java.lang.Integer[value=1][][],java.lang.Integer[value=4][][],java.lang.Integer[value=9][][],java.lang.Integer[value=16][][],java.lang.Integer[value=25][][],null,null,null,null,null},size=5][modCount=5][][]
API
java.lang.reflect.AccessibleObject
void setAccessible(boolean flag)
設(shè)置或取消這個(gè)可訪問對(duì)象的可訪問標(biāo)志,如果拒絕訪問則拋出一個(gè)IllegalAccessException異常
static void setAccessible(AccessibleObject[] array, boolean flag)
這是一個(gè)便利方法,用于設(shè)置一個(gè)對(duì)象數(shù)組的可訪問標(biāo)志。
5、使用反射編寫泛型數(shù)組代碼
CopyOfTest.java
/**
* 使用反射編寫泛型數(shù)組代碼
*/
public class CopyOfTest {
public static void main(String[] args) {
int[] a = {1,2,3};
a = (int[]) goodCopyOf(a,10);
System.out.println(Arrays.toString(a));
String[] b = {"Tom","Dick","Harry"};
b = (String[]) goodCopyOf(b,10);
System.out.println(Arrays.toString(b));
//以下調(diào)用將生成異常
b = (String[]) badCopyOf(b,10);
}
public static Object[] badCopyOf(Object[] a, int newLength){
Object[] newArray = new Object[newLength];
System.arraycopy(a,0,newArray,0,Math.min(a.length,newLength));
return newArray;
}
public static Object goodCopyOf(Object a, int newLength){
Class cl = a.getClass();
if(!cl.isArray()) return null;
Class componentType = cl.getComponentType();// 返回表示數(shù)組的元素類型的Class
int length = Array.getLength(a);
Object newArray = Array.newInstance(componentType, newLength);// 使用反射包里的Array構(gòu)造一個(gè)新數(shù)組,提供兩個(gè)參數(shù),一個(gè)是數(shù)組的元素類型,一個(gè)是數(shù)組的長度
System.arraycopy(a,0,newArray,0,Math.min(length,newLength));
return newArray;
}
}
輸出
[1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
[Tom, Dick, Harry, null, null, null, null, null, null, null]
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
at com.company.reflection.CopyOfTest.main(CopyOfTest.java:20)
API
java.lang.reflect.Array
static Object get(Object array,int index)
static void set(Object array,int index,Object newValue)
static int getLength(Object array)
返回給定數(shù)組的長度
static Object newInstance(Class componentType,int Length)
返回一個(gè)有給定類型、給定大小的新數(shù)組
6、調(diào)用任意方法和構(gòu)造器
Method類中有一個(gè)invoke方法,允許調(diào)用包裝在Method對(duì)象中的方法。invoke方法的簽名是:
Object invoke(Object obj,Object... args)
第一個(gè)參數(shù)是隱式參數(shù),其余的對(duì)象提供了顯示參數(shù)。
對(duì)于靜態(tài)方法,第一個(gè)參數(shù)可以忽略,即可以將它設(shè)置為null。
MethodTableTest.java
/**
* 使用反射調(diào)用任意方法和構(gòu)造器
*/
public class MethodTableTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 獲取指向square和sqrt方法的方法指針
Method square = MethodTableTest.class.getMethod("square", double.class);// 平方
Method sqrt = Math.class.getMethod("sqrt", double.class);// 平方根
// 打印x和y值表
printTable(1,10,10,square);
printTable(1,10,10,sqrt);
}
public static double square(double x){
return x * x;
}
public static void printTable(double from, double to, int n, Method f) throws InvocationTargetException, IllegalAccessException {
// 打印該方法作為表頭
System.out.println(f);
double dx = (to - from) / (n - 1);
for (double x = from; x <= 10; x += dx){
double y = (Double) f.invoke(null,x);
System.out.printf("%10.4f | %10.4f%n",x,y);
}
}
}
輸出
public static double com.company.reflection.MethodTableTest.square(double)
1.0000 | 1.0000
2.0000 | 4.0000
3.0000 | 9.0000
4.0000 | 16.0000
5.0000 | 25.0000
6.0000 | 36.0000
7.0000 | 49.0000
8.0000 | 64.0000
9.0000 | 81.0000
10.0000 | 100.0000
public static double java.lang.Math.sqrt(double)
1.0000 | 1.0000
2.0000 | 1.4142
3.0000 | 1.7321
4.0000 | 2.0000
5.0000 | 2.2361
6.0000 | 2.4495
7.0000 | 2.6458
8.0000 | 2.8284
9.0000 | 3.0000
10.0000 | 3.1623
API
java.lang.reflect.Method
public Object invoke(Object implicitParamter, Object[] explicitParamters)
調(diào)用這個(gè)對(duì)象描述的方法,傳入給定參數(shù),并返回方法的返回值。對(duì)于靜態(tài)方法,傳入null作為隱式參數(shù)。
總結(jié)
以上是生活随笔為你收集整理的java反射随意值_Java反射笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果新专利扩展 Apple Watch“
- 下一篇: 新版标普 500 科技股指数将于本周五收