5 分钟
Java 反射笔记
1、classLoading
(0)JVM类加载机制
动态加载,用到时再加载。
(1)介绍
类加载器是负责加载类的对象。ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。
每个 Class 对象都包含一个对定义它的 ClassLoader 的引用。
数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建。数组类的类加载器由 Class.getClassLoader() 返回,该加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。
类加载器通常由安全管理器使用,用于指示安全域。
ClassLoader 类使用委托模型来搜索类和资源。每个 ClassLoader 实例都有一个相关的父类加载器。需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。虚拟机的内置类加载器(称为 “bootstrap class loader”)本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。
通常情况下,Java 虚拟机以与平台有关的方式,从本地文件系统中加载类。例如,在 UNIX 系统中,虚拟机从 CLASSPATH 环境变量定义的目录中加载类。
然而,有些类可能并非源自一个文件;它们可能源自其他来源(如网络),也可能是由应用程序构造的。defineClass 方法将一个 byte 数组转换为 Class 类的实例。这种新定义的类的实例可以使用 Class.newInstance 来创建。
类加载器所创建对象的方法和构造方法可以引用其他类。为了确定引用的类,Java 虚拟机将调用最初创建该类的类加载器的 loadClass 方法。
(2)JDK内置的ClassLoader
- bootstrap class loader 通过本地语言实现,加载jdk核心类
java.lang.*等 - extesion class loader java实现,加载来自
jre/lib/ext内的类 - application class loader 加载用户定义的类
- 其他class loader
- SecureClassLoader
- URLClassLoader
(3)Class Loader层次关系
bootstrap class loader <- extesion class loader <- application class loader <- other
为了安全性,在加载新的class将会委托父ClassLoader,询问是否已经加载了
2、反射相关类及方法
java.lang.Class类对象,由classLoader创建,包含类的相关信息(如字段方法等)java.lang.reflect.Array类提供了动态创建和访问 Java 数组的方法。java.lang.reflect.Constructor<T>类的构造函数对象,通过其可以其可以动态创建对象java.lang.reflect.Field类的属性或者说成员,通过其可以访问或者修改对象的Fieldjava.lang.reflect.Method类的方法对象,通过其可以动态调用对象的方法
(1)java.lang.Class
获取Class方法的方法
Class.forName("java.lang.String")String.class对象引用.getClass()
与反射相关的常用方法
- 通过名字获取其他反射对象
getConstructor获取该类的构造器对象(public)getDeclaredConstructor获取该类所有的构造器对象getField获取该类的字段(public)getDeclaredField获取该类所有的字段getMethod获取该类的方法(public)getDeclaredMethod获取该类的所有方法
- 获取所有其他反射对象(数组形式)
getConstructors获取该类的构造器对象(public)getDeclaredConstructors获取该类所有的构造器对象getFields获取该类的字段(public)getDeclaredFields获取该类所有的字段getMethods获取该类的方法(public)getDeclaredMethods获取该类的所有方法
(2)java.lang.reflect.Array
静态方法
get(Object array, int index)返回指定数组对象中索引组件的值。getXxx(Object array, int index)返回以 xxx 形式返回指定数组对象中索引组件的值。set(Object array, int index, Object value)将指定数组对象中索引组件的值设置为指定的新值。setXxx(Object array, int index, Object value)将指定数组对象中索引组件的值设置为指定的 xxx 值。
以上xxx为八种基本数据类型
例子
//提供了对数组的方法
int arr[] = {1,2,3};
String[] arr1 = {"fasdf","fdsafs"};
p(Array.get(arr1,1));
Array.set(arr1,1,"change");
p(arr1[1]);
p(Array.getInt(arr,2));(3)java.lang.reflect.Constructor<T>
常用方法
T newInstance(Object... initargs)动态构造一个对象
例子
package com.rectcircle.javaapi.lang.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ConstructorTest {
public static void p(Object o){System.out.println(o);}
private int i;
private String s;
public ConstructorTest(){}
public ConstructorTest(int i,String s){
this.s = s;
this.i = i;
}
@Override
public String toString() {
return "ConstructorTest{" +
"i=" + i +
", s='" + s + '\'' +
'}';
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Class<ConstructorTest> clazz = ConstructorTest.class;
Constructor<ConstructorTest> c1 = clazz.getConstructor();
Constructor<ConstructorTest> c2 = clazz.getConstructor(int.class,String.class);
//常用方法
ConstructorTest obj1 = c1.newInstance();
p(obj1);
ConstructorTest obj2 = c2.newInstance(1,"string");
p(obj2);
}
}(4)java.lang.reflect.Field
常用方法
void set(Object obj, Object value)将指定对象变量上此 Field 对象表示的字段设置为指定的新值。void setXxx(Object obj, xxx v)将字段的值设置为指定对象上的一个 xxx 值。Object get(Object obj)Object get(Object obj)xxx getBoolean(Object obj)获取一个静态或实例 xxx 字段的值。
以上xxx为八种基本数据类型
例子
package com.rectcircle.javaapi.lang.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;
public class FieldTest {
public static void p(Object o) { System.out.println(o); }
private int i;
private String s;
public Map<Integer,String> map = new HashMap<>();
public FieldTest(){}
public FieldTest(int i,String s){
this.s = s;
this.i = i;
}
@Override
public String toString() {
return "ConstructorTest{" +
"i=" + i +
", s='" + s + '\'' +
'}';
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException {
Class<FieldTest> clazz = FieldTest.class;
Field fi = clazz.getDeclaredField("i");
Field fs = clazz.getDeclaredField("s");
Field fmap = clazz.getField("map");
FieldTest ft = new FieldTest(1,"test");
//常用方法
p(fi.get(ft));
p(fs.get(ft));
fi.set(ft,2);
fs.set(ft,"change");
p(ft);
//获取泛型信息
ParameterizedType mapMainType = (ParameterizedType) fmap.getGenericType();
p(mapMainType.getRawType());
Type[] types = mapMainType.getActualTypeArguments();
for (int i = 0; i < types.length; i++) {
System.out.println("第" + (i + 1) + "个泛型类型是:" + types[i]);
}
}
}(5)java.lang.reflect.Method
常用方法
Object invoke(Object obj, Object... args)对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
例子
package com.rectcircle.javaapi.lang.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author Rectcircle
* createTime 2017/5/17
*/
public class MethodTest {
public static void p(Object o) { System.out.println(o); }
private int i;
private String s;
public boolean sayHello(){
System.out.println("Hello");
return true;
}
public MethodTest(){}
public MethodTest(int i, String s){
this.s = s;
this.i = i;
}
@Override
public String toString() {
return "ConstructorTest{" +
"i=" + i +
", s='" + s + '\'' +
'}';
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Class<MethodTest> clazz = MethodTest.class;
Method say = clazz.getMethod("sayHello");
MethodTest mt = new MethodTest(1,"test");
//常用方法
boolean rt = (boolean) say.invoke(mt);
p(rt);
}
}