目录
反射机制概述
reflection:java是一门静态语言,但是因为有反射机制,成为了准动态语言,反射机制允许程序在运行期间借助与Reflection API取得任何类的内部信息,并且能够直接操作任意对象内部属性及其方法。
在加载完类之后,在堆内的方法区就会产生一个class类型的对象,这个对象就包含了完整的类结构信息,我们可以通过这个对象看到类的结构。这个对象就是一面镜子,通过这个镜子看到类的结构,所以形象的称为反射。
代码解释:
public class ReflectionTest {
@Test
//正常的方法对对象的属性和方法进行操作
public void test1(){
//创建person类对象
Person p1 = new Person("tom",12);
//调用对象方法和属性
p1.age = 10;
System.out.println(p1);
//在person类外部,不可以通过person类的对象调用其内部私有结构
}
@Test
//反射的方法对对象的属性和方法进行操作
public void test02() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Person person = null;
Person person1 = null;
Class clazz = Person.class;
//通过反射构建person对象
Constructor cons = clazz.getConstructor(String.class,int.class);
Object o = cons.newInstance("tom",12);
if (o instanceof Person){
person = (Person) o;
}
System.out.println(person);
//通过反射,调用对象指定属性和方法
//属性
Field age = clazz.getDeclaredField("age");
age.set(person,10);
System.out.println(person);
//方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(person);
//但是通过反射可以调用person类私有的属性,方法
//方法
Constructor constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object o1 = constructor.newInstance("lizude");
if (o1 instanceof Person){
person1 = (Person)o1;
}
System.out.println(person1);
//属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(person1,"huawei");
System.out.println(person1);
}
}
Class理解
类加载过程
程序经过javac.exe命令后,会生成一个或多个字节码文件(.class)。接着使用java.exe命令对某个字节码文件进行解释运行此过程相当于类加载。加载到内存的类,此过程就称运行时类,此运行类就当作Class的一个实例。对应代码:Class clazz = Person.class。换句话说,class的实例就对应着一个运行时类。在上述代码执行之后,就会在堆中出现一个class对象,这个对象就包含了完整的类结构信息,我们可以通过这个对象看到类的结构。这个对象就是一面镜子,通过这个镜子看到类的结构,所以形象的称为反射。(得到了这个类,我们就可以通过这个类去创建对象,与我们平时创建对象一样,都是通过类创建对象)
Class实例获取的四种方式
public class ReflectionTest {
@Test
public void test3(){//通过反射机制获取运行时类class,通过class来实例化我们的反射对象
//方式一:调用运行时类的属性 .class,也可以认为就是把一个运行时类给了class类,在Class clazz = Person.class;执行之后,在堆内的方法区就会产生一个class类型的对象,
// 这个对象就包含了完整的类结构信息,我们可以通过这个对象看到类的结构。这个对象就是一面镜子,通过这个镜子看到类的结构,所以形象的称为反射。
Class clazz = Person.class;
System.out.println(clazz);
//方式二:通过运行时类对象来获取,调用getclass方法来获取,每一个对象都知道new他出来的是那个类的
Person person1 = new Person();
Class personClass = person1.getClass();
System.out.println(personClass);
//方式三调用class的静态方法:forName(String class)
try {
Class personclass1 = Class.forName("Person");
System.out.println(personclass1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式四 使用类的加载器classloader(了解)
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
try {
Class class4 = classLoader.loadClass("Person");
System.out.println(class4);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
那些类型可以有Class对象。
public class ReflectionTest {
@Test
public void test3(){
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = ElementType.class;
Class c6 = Override.class;
Class c7 = int.class;
Class c8 = void.class;
Class c9 = Class.class;
int[] a = new int[10];
int[] b = new int[100];
Class c10 = a.getClass();
Class c11 = b.getClass();
//只要数组元素类型以及维度一样,就是同一个class,因为通过运行时类对象来获取,调用getclass方法来获取,每一个对象都知道new他出来的是那个类的,因为都是int类型的数组类,
System.out.println(c10 == c11);
System.out.println();
}
}
创建运行时类的对象
public class ReflectionTest {
@Test
//方法一
public void test3() throws InstantiationException, IllegalAccessException {
Class<Person> clazz = Person.class;//有了这个类的Class对象,我们就可以创建这个类的对象
//newInstance();调用此方法创建对应的运行时类的对象,必须提供无参构造器,而且必须访问权限得够
Person obj = clazz.newInstance();//调用person里面的空参构造器,如果调用有参的构造器,就往newInstance()内加参数
System.out.println(obj);
}
@Test
//方法二
public void test1(){
try {
Class clazz = Class.forName("Person");
Constructor cons = clazz.getConstructor(String.class,int.class);
Person person = (Person)cons.newInstance("ll",1);
System.out.println(person);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Test
//体会反射的动态性
public void test02(){
for (int i = 0; i < 100; i++){
int num = new Random().nextInt(3);
String classpath = null;
switch (num){
case 0:
classpath = "java.util.Date";
break;
case 1:
classpath = "java.lang.Object";
break;
case 2:
classpath = "Person";
break;
}
try {
Object obj = getInstance(classpath);
System.out.println(obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
public Object getInstance(String classpath) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class clazz = Class.forName(classpath);
return clazz.newInstance();
}
}
获取运行时类的完整结构
属性及其属性的权限修饰符 数据类型 变量名
public class ReflectionTest {
@Test
public void test(){
Class clazz = null;
try {
clazz = Class.forName("java1.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取属性方法一
Field[] fields = clazz.getFields();
for (Field f : fields){
System.out.println(f);
}
System.out.println("----------------------------------------------");
//获取属性方法二:方法二与方法一之间的区别就是方法一不能获取私有属性和父类中属性,方法二获取当前类所有属性,不包括父类中的属性,但是虽然可以获取,但是如果是私有属性就不能访问。但是可以加一个方法就可以访问了
Field[] fields1 = clazz.getDeclaredFields();
for (Field field : fields1 ){
System.out.println(field);
}
}
//获取属性的权限修饰符 数据类型 变量名
@Test
public void test2(){
Class clazz = Person.class;
Field[] declared = clazz.getDeclaredFields();
for (Field field : declared){
//权限修饰符
int m = field.getModifiers();
System.out.println(Modifier.toString(m));
//数据类型
Class type = field.getType();
System.out.println(type);
//变量名
String name = clazz.getName();
}
}
}
方法及其方法注解返回值类型,权限修饰符
public void test3(){
Class clazz = Person.class;
//获取所有方法
Method[] methods1 = clazz.getMethods();//包括了父类的方法,获取了当前运行时类及其父类中声明为public权限方法
for (Method method : methods1){
System.out.println(method);
}
System.out.println("---------------------");
Method[] methods2 = clazz.getDeclaredMethods();//获取当前运行时类中声明的所有方法,不包含父类的方法
for (Method method : methods2){
System.out.println(method);
}
}
@Test
public void test04(){
Class clazz = Person.class;
Method[] methods = clazz.getDeclaredMethods();
//获取注解
for (Method method : methods){
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation);
}
//获取权限修饰符
System.out.println(Modifier.toString(method.getModifiers()));
//返回值类型
System.out.println(method.getReturnType());
//方法名
System.out.println(method.getName());
//形参列表
Class[] p = method.getParameterTypes();
}
}
获取构造器
@Test
//构造器
public void test05(){
Class clazz = Person.class;
Constructor[] constructors = clazz.getConstructors();//获取当前运行时类中声明为public的构造器
for (Constructor c : constructors){
System.out.println(c);
}
Constructor[] constructors1 = clazz.getDeclaredConstructors();//获取当前运行时类中声明的所有构造器
for (Constructor constructor : constructors1){
System.out.println(constructor);
}
//获取运行时类的父类
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
//获取运行时类带泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
//获取运行时类带泛型的父类的泛型
.构造子类Class对象
2.获取带泛型的父类的ParameterizedType对象
2.获取父类的Type数组(Type数组中保存了父类的泛型的类型)
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(((Class)actualTypeArguments[0]).getName());
}
获取运行时类实现的接口,所在包,注解
public class ReflectionTest {
@Test
public void test06(){
Class clazz = Person.class;
//获取运行时类实现的接口
Class[] classes = clazz.getInterfaces();
for (Class c : classes){
System.out.println(c);
}
//获取运行时类的父类实现的接口
Class[] classes1 = clazz.getSuperclass().getInterfaces();
for (Class c : classes1){
System.out.println(c);
}
//获取运行时类所在的包
Package p = clazz.getPackage();
System.out.println(p);
//获取运行时类声明的注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations){
System.out.println(annotation);
}
}
}
调用运行时类的指定结构(属性,方法,构造器)
public class ReflectionTest {
@Test
//调用指定属性
public void test06() throws NoSuchFieldException, InstantiationException, IllegalAccessException {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();//空参构造器
//获取指定属性
Field id = clazz.getField("id");
//设置当前属性值
id.set(p,1001);
int i = (int)id.get(p);
System.out.println(i);
//另外一种方法调用指定属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);//如果是通用属性就不需要这一步,如果属性是私有属性就有这一步,保证当前属性是可以访问的
name.set(p,"li");
String s = (String)name.get(p);
System.out.println(s);
}
@Test
//调用运行时类的指定方法
public void test1() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class clazz = Person.class;//运行时类的实例,是那个类的实例,而不是类的对象
//创建运行时类的对象
Person p = (Person)clazz.newInstance();//无参构造器
Method show = clazz.getDeclaredMethod("show",String.class);//两个参数,一个是方法名,一个是可变形参:因为可能这个方法名的方法会有很多,所以需要她的形式参数来确定到底是那个方法
show.setAccessible(true);
String s = (String)show.invoke(p,"cnn");
System.out.println(s);
//如何调用静态方法
Method showdesc = clazz.getDeclaredMethod("showdesc");
showdesc.setAccessible(true);
Object re = showdesc.invoke(Person.class);//静态方法知道该方法在那个类中,可以之间调用,也可通过类名
System.out.println(re);
}
@Test
//调用运行时类的指定构造器
public void test2() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class clazz = Person.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
Person p = (Person) constructor.newInstance("lizude",12);
System.out.println(p);
}
}
动态代理(反射应用)