Java高级——反射
- Class类与获取Class实例
- 1、关于java.long.Class的理解
- 2、获取Class实例的四种方法
- 创建运行时类的对象
- 获取运行时类的结构
- 1、获取运行时类的属性
- 2、获取运行时类的方法结构
- 3、获取运行时类的构造器结构
- 调用运行时类的指定结构
- 1、调用运行时类的属性
- 2、调用运行时类的方法
- 3、调用运行时类的构造方法
Class类与获取Class实例
一般来说,Class类是反射的源头,在进行反射操作之前,都要获取Class实例。
Person.java
package com.atguigu.java;public class Person {private int id;int age;public String name;} //省略构造方法、get、set、toString
1、关于java.long.Class的理解
1)类的加载过程:
程序经过javac.exe命令以后,会生成一个或多个字节码文件(.cLass结尾)。
接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为CLass的一个实例。
2)换句话说,CLass的实例就对应着一个运行时类(Class的实例不能主动创建new一个出来)。
万事万物皆对象对象.xxx, File, URL,反射,前端、数据库操作等都是对象
3)加载到内存中的运行时类,会缓存一定时间。此时我们可以通过不同方法获取此运行时类。
2、获取Class实例的四种方法
ReflectionTest.java
package com.atguigu.java;import org.junit.Test;public class ReflectionTest {@Testpublic void test3() throws ClassNotFoundException {//方式一 调用运行时类的属性: .class//Class<Person> clazz1 = Person.class;Class clazz1 = Person.class;//方式二 调用class的静态方法 forName(String classpath)Class clazz2 = Class.forName("com.atguigu.java.Person");//方式三 通过运行时类的对象Person p1 = new Person();Class clazz3 = p1.getClass();//方式四 使用类的加载器ClassLoaderClassLoader classLoader = ReflectionTest.class.getClassLoader();Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");System.out.println(clazz4 == clazz1);//不同方式获取的运行时的类是一样的。输出结果为True}
}
创建运行时类的对象
通过newInstance() 方法创建运行时类的对象。
NewInstanceTest.java
package com.atguigu.java;import org.junit.Test;public class NewInstanceTest {@Testpublic void test() throws IllegalAccessException, InstantiationException {Class clazz = Person.class;//Object obj = clazz.newInstance(); 输出是一个Person对象,可强转为PersonPerson obj = (Person) clazz.newInstance();}
}
newInstance() 方法内部通过Person的无参构造方法(空参构造器)创建对象,可以理解为一切创建对象的方法都要去调用无参构造。
通过上面test方法抛出的两个异常,可以了解,如果想通过newInstance() 创建对象,必须满足两个要求:
- 运行时类必须提供无参构造器
- 无参构造器的访问权限要足够(public)
从而得知,在javabean中要求提供一个public的空参构造器。原因: 1.便于通过反射,创建运行时类的对象。2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器。
获取运行时类的结构
1、获取运行时类的属性
Class实例的getFields() 方法,
getFields(): 获取当前运行时类及其父类中声明为public访问权限的属性
getDeclaredFields(): 获取当前运行时类中声明的所有属性(不包含父类中声明的属性)。
FieldTest.java
public class FieldTest {@Testpublic void test1(){Class<Person> clazz = Person.class;//获取属性结构//getFields():获取当前运行时类及其父类中声明为public访问权限的属性Field[] fields = clazz.getFields( );for(Field f : fields){System.out.println(f);}System.out.println();//getDecLaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)Field[ ] declaredFields = clazz.getDeclaredFields();for(Field f : declaredFields) {System.out.println(f);}}
}
2、获取运行时类的方法结构
getMethods()
public class MethodTest {@Testpublic void test1() {Class<Person> clazz = Person.class;// getMethods():获取当前运行时类及其所有父类中声明为public权限的方法Method[] methods = clazz.getMethods();for (Method m : methods) {System.out.println(m);}System.out.println();// getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)Method[] declaredMethods = clazz.getDeclaredMethods();for (Method m : declaredMethods) {System.out.println(m);}}
}
3、获取运行时类的构造器结构
getConstructors()
public class ConstructorTest {public void test1() {Class clazz = Person.class;//getconstructors():获取当前运行时类中声明为public的构造器Constructor[ ] constructors = clazz.getConstructors();for(Constructor c : constructors) {System.out.println(c);}System.out.println();//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器Constructor[] declaredConstructors = clazz.getDeclaredConstructors();for( Constructor c : declaredConstructors){System.out.println(c);}}
}
调用运行时类的指定结构
1、调用运行时类的属性
getField() 和 getDeclaredField()
不常用的方法(获取指定属性:要求运行时类中的属性为public):
public class ReflectionTest {@Testpublic void test() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();//获取指定属性:要求运行时类中的属性为public//通常不采用此方法!Field name = clazz.getField("name");//设置当前属性的值name.set(p,"Tom");//获取String n = (String) name.get(p);System.out.println(n);}
}
常用的方法 getDeclaredField() :
@Testpublic void test2() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();//获取指定属性Field name = clazz.getDeclaredField("name");//保证当前属性是可访问的(例如private时) 很重要!!!!name.setAccessible(true);//设置当前属性的值name.set(p,"Tom");//获取String n = (String) name.get(p);System.out.println(n);}
2、调用运行时类的方法
首先为Person创建一个方法:
public class Person {private int id;int age;public String name;private String showName(String name){System.out.println(name);return name;}}
@Testpublic void test3() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();//获取指定某个方法,clazz.getDeclaredMethod()://参数1:指明获取方法的名称 参数2:指明获取方法的形参列表Method showName = clazz.getDeclaredMethod("showName", String.class);//保证方法是可访问的showName.setAccessible(true);//invoke反过来调用方法。//参数1:方法的调用者(谁的方法) 参数2:给方法形参赋值的实参//invoke方法的返回值就是被调用的方法的返回值showName.invoke(p,"Tom");}
3、调用运行时类的构造方法
@Testpublic void test4() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();//获取指定的构造器Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);//保证可访问declaredConstructor.setAccessible(true);//调用构造器创建对象Person tom = (Person) declaredConstructor.newInstance("Tom");}