反射机制概述(Reflection)
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可 以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看 到类的结构,所以,我们形象的称之为:反射。
正常的对象获取流程
通过反射获取
静态语言和动态语言
静态语言
程序在运行和时候其结构不能被改变的语言称之为 "静态语言" 例如:C、C++、Java
动态语言
程序在运行的过程中其结构可以被改变的语言称之为 "动态语言" 例如:python、PhP
通过反射获取class实例的几种方法
方式一:通过class的方式
Class<String> aClass = String.class;
System.out.println(aClass);
方式二:通过getClass()方式
Class<? extends String> aClass1 = "hello Java".getClass();
System.out.println(aClass1);
方式三:通过Class.forName()
try {
Class<?> hello_java = Class.forName("java.lang.String");
System.out.println(hello_java);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
方式四:通过类的加载器
ClassLoader classLoader = ReflectionDemo.class.getClassLoader();
Class<?> aClass2 = classLoader.loadClass("java.lang.String");
System.out.println(aClass2);
读取配置文件
方式1 Properties + FileInputStream 的方式
@Test
public void reflectionTest2() throws IOException {
Properties pros = new Properties();
FileInputStream fis = new FileInputStream("prop.properties");
pros.load(fis);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
System.out.println("user = " + user + " password = " + password);
}
方式2:通过类名.classLoader的方式,默认配置文件识别在module 的src下
@Test
public void reflectionTest3() throws IOException {
Properties pros = new Properties();
ClassLoader classLoader = ReflectionDemo.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("prop1.properties");
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
System.out.println("user = " + user + " password = " + password);
}
通过反射获取实例对象
方式1:通过newInstance的方式
在这里要注意,使用newInstance的方式调用的是空参的构造器,如果没有空参构造,会报异常 在空参构造器权限为private 的时候也会报异常
@Test
public void reflectionTest4() throws IllegalAccessException, InstantiationException {
Class<Person> clazz = Person.class;
Person person = clazz.newInstance();
System.out.println(person);
}
获取运行时类的属性结构
测试的Bean
public class Creature<T> implements Serializable {
private char gender;
public double weight;
private void breath(){
System.out.println("生物呼吸");
}
public void eat(){
System.out.println("生物吃东西");
}
}
public interface MyInterface {
void info();
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotition {
String value() default "hello";
}
@MyAnnotition("hi")
public class Person extends Creature<String> implements Comparable<String>,MyInterface{
private String name;
int age;
public int id;
public Person() {
}
private Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
@MyAnnotition()
public String show(String nation){
System.out.println("我的国籍是:" + nation);
return nation;
}
public String display(String insterests){
return insterests;
}
@Override
public int compareTo(String o) {
return 0;
}
@Override
public void info() {
System.out.println("我是一个人");
}
}
获取属性
- getFields()
Class<Person> clazz = Person.class;
Field[] fields = clazz.getFields();
for (Field item : fields){
System.out.println(item);
}
执行结果
可以看到他只是打印了类型为public的属性。所以通过getFieIds获取属性他只会获取到子类和父类中属性为public的属性
- getDeclaredFields()
Class<Person> clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field item : declaredFields){
System.out.println(item);
}
获取到它自身的属性但是不包含它父类中的属性,任何权限的都可以获取的到
获取权限修饰、数据类型、变量名
- getModifiers()
- getType()
- getName()
Class<Person> clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field item : declaredFields){
//获取权限修饰符
int modifiers = item.getModifiers();
System.out.print(Modifier.toString(modifiers) + "\t");
//获取数据类型
Class type = item.getType();
System.out.print(type.getName() + "\t");
//获取变量名
String fname = item.getName();
System.out.print(fname);
System.out.println();
}
获取方法
- getMethods
Class<Person> clazz = Person.class;
Method[] methods = clazz.getMethods();
for (Method mItem : methods){
System.out.println(mItem);
}
获取当前运行时类及其所有父类中声明为public权限的方法
- getDeclaredMethods()
Class<Person> clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method mItem : declaredMethods){
System.out.println(mItem);
}
获取到运行时类中的所有的方法(不包含父类中声明的方法)
获取方法的内部结构
-
获取方法声明的注解 getAnnotations()
-
获取权限的修饰符 getModifiers()
-
获取到方法的权限 getReturnType().getName()
-
获取到方法名 getName()
Class<Person> clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method mItem : declaredMethods){
//1.获取到声明方法的注解
Annotation[] annotations = mItem.getAnnotations();
for (Annotation aItem:annotations){
System.out.print(aItem);
}
//2.权限修饰符
System.out.print(Modifier.toString(mItem.getModifiers()) + "\t");
//3.方法的返回值类型
System.out.print(mItem.getReturnType().getName() + "\t");
//4.获取到方法名
System.out.print(mItem.getName() + "\t");
System.out.println(mItem);
获取到运行时类的构造器
- 获取到当前运行时类中声明为public的构造器 getConstructors()
Class<Person> clazz = Person.class;
Constructor[] constructors = clazz.getConstructors();
for (Constructor cItem:constructors){
System.out.println(cItem);
}
- 获取到当前类中的构造器 getDeclaredConstructors()
Class<Person> clazz = Person.class;
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor cItem : declaredConstructors){
System.out.println(cItem);
}
获取运行时类的指定属性
Class<Person> clazz = Person.class;
Person person = clazz.newInstance();
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(person,"tom");
System.out.println(person);
获取指定的构造器
Class<Person> clazz = Person.class;
Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Person per = constructor.newInstance("Tom");
System.out.println(per);