1.反射的原理

image-20210614230506004

2.反射相关类

  • java.lang.Class
  • java.lang.reflect.Method
  • java.lang.reflect.Field
  • java.lang.reflect.Constructor

2.1 java.lang.Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//通过Properties类 读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("/Users/qixiangyang/Documents/javaCode/leecodePractice/src/hero.properties"));
String classPath = properties.get("classpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classPath = " + classPath);
System.out.println("methodName = " + methodName);

//加载类,生成Class类型的对象
Class cls = Class.forName(classPath);
//通过 cls 得到加载的类的对象实例
Object o = cls.newInstance();
System.out.println(cls); //输出内容:class com.yang.reflection.Hero
}

2.2 java.lang.reflect.Method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Properties properties = new Properties();
properties.load(new FileInputStream("/Users/qixiangyang/Documents/javaCode/leecodePractice/src/hero.properties"));
String classPath = properties.get("classpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classPath = " + classPath);
System.out.println("methodName = " + methodName);

Class cls = Class.forName(classPath);
Object o = cls.newInstance();
//通过cls 得到加载类中的方法对象
//在反射中,将方法视为对象(万物皆对象的理解)
Method method = cls.getMethod(methodName);
//通过反射执行对应的方法
method.invoke(o);
}

2.3 java.lang.reflect.Field

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Properties properties = new Properties();
properties.load(new FileInputStream("/Users/qixiangyang/Documents/javaCode/leecodePractice/src/hero.properties"));
String classPath = properties.get("classpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classPath = " + classPath);
System.out.println("methodName = " + methodName);

Class cls = Class.forName(classPath);
Object o = cls.newInstance();
System.out.println(cls);

//字段的值 字段的修饰符不能是私有的,如果是私有的话,程序会报错
Field fieldName = cls.getField("age");
System.out.println(fieldName.get(o));
}

2.4 java.lang.reflect.Constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Properties properties = new Properties();
properties.load(new FileInputStream("/Users/qixiangyang/Documents/javaCode/leecodePractice/src/hero.properties"));
String classPath = properties.get("classpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classPath = " + classPath);
System.out.println("methodName = " + methodName);

Class cls = Class.forName(classPath);
Object o = cls.newInstance();
System.out.println(cls);

//获取到无参构造器
Constructor constructor01 = cls.getConstructor();
System.out.println(constructor01); // public com.yang.reflection.Hero()

//获取到有参构造器
Constructor constructor02 = cls.getConstructor(String.class);
System.out.println(constructor02); // public com.yang.reflection.Hero(java.lang.String)
}

3. 反射调用优化

传统方式与反射的用时比较

传统方式:

1
2
3
4
5
6
7
8
9
public static void m1(){
Hero hero = new Hero();
long start = System.currentTimeMillis();
for (int i=0;i<90000000;i++){
hero.playHero();
}
long end = System.currentTimeMillis();
System.out.println("m1()耗时:" + (end-start)); // m1()耗时:5
}

反射:

1
2
3
4
5
6
7
8
9
10
11
public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls = Class.forName("com.yang.reflection.Hero");
Object o = cls.newInstance();
long start = System.currentTimeMillis();
for (int i=0;i<90000000;i++){
Method playHero = cls.getMethod("playHero");
playHero.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("m2()耗时:" + (end-start)); // m2()耗时:12364
}

根据两个方法执行的结果可以看出,通过反射的方式调用方法是非常耗时的!

反射调用的优化

关闭访问检查

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls = Class.forName("com.yang.reflection.Hero");
Object o = cls.newInstance();
long start = System.currentTimeMillis();
for (int i=0;i<90000000;i++){
Method playHero = cls.getMethod("playHero");
//关闭访问检查 设为true
playHero.setAccessible(true);
playHero.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("m3()耗时:" + (end-start)); // m3()耗时:11708
}

与m2()方法相比,时间上确实缩短了一些,但是效果其实并不是很明显!

4.Class类常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String classAllPath = "com.yang.reflection.Hero";
//1. 获取到Hero类 对应的 Class对象
// <?> 表示不确定的Java类型
Class<?> cls = Class.forName(classAllPath);

//2. 输出cls
System.out.println(cls); // class com.yang.reflection.Hero
System.out.println(cls.getClass()); // class java.lang.Class

//3. 得到包名
System.out.println(cls.getPackage()); // package com.yang.reflection

//4. 得到全类名
System.out.println(cls.getName()); // com.yang.reflection.Hero

//5. 通过cls创建对象实例
Hero hero = (Hero)cls.newInstance();
System.out.println(hero); // Hero{heroName='鲁班', orientation='射手', skillName='火力压制'}

//6. 通过反射获取属性
Field heroName = cls.getField("heroName");
System.out.println(heroName.get(hero)); // 鲁班

//7. 给属性赋值
heroName.set(hero,"后羿");
System.out.println(heroName.get(hero)); // 后羿

//8. 获取所有属性
Field[] heroFields = cls.getFields();
System.out.println("Hero类所有的属性如下:");
for (Field field:heroFields){
System.out.println(field.getName());
}


}

本篇文章参考韩顺平老师的视频所整理。