反射

反射复习

反射

一.反射是什么?反射是框架设计的灵魂

  • 先了解一下什么是动态语言(是一类在运行时可以改变其结构的语言)。静态语言(运行时结构不可变的语言就是静态语言)
  • Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息。
  • JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。反射就是把java类中的各种成分映射成一个个的Java对象例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象
  • 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
    在这里插入图片描述
    在这里插入图片描述

二.反射的好处:

  • 可以在程序运行过程中,操作这些对象
  • 可以解耦,提高程序的可扩展性

三.Class类的使用

Class类的实例表示正在运行的Java应用程序中的类和接口。枚举是一种类,一个注释是一种界面。每个数组也属于一个类,它被反映为具有相同元素类型和维数的所有数组共享的Class对象。原始Java类型( booleanbytecharshortintlongfloat ,和double ),以及关键字void也表示为Class对象。

Class没有公共建设者。 相反, Class对象由Java虚拟机自动构建,因为类已加载,并通过调用类加载器中的defineClass方法。

<1>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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.company;

public class Main {

public static void main(String[] args) {
// 普通正常方式:
Person student=new Student();
System.out.println(student.getName());
// 反射:通过Class类。
//1.已知具体的类,获取类的class属性获取//多用于对象的获取字节码的方式
Class<Student> c1 = Student.class;
System.out.println(c1);
System.out.println(c1.hashCode());
System.out.println("-------------");
//2.已知某个类的实例,通过实例的getClass()获取Class对象//多用于参数的传递
Class<? extends Person> c2 = student.getClass();
System.out.println(c2);
System.out.println(c2.hashCode());
System.out.println("-------------");
//3.已知一个类的全类名,且在该类的类路径下,可通过Class类的静态方法forName()获取
//*后面用的多:多用于配置文件,将类名定义在配置文件中。读取文件,加载类*
try {
Class<?> c3 = Class.forName("com.company.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
System.out.println(c3);
System.out.println(c3.hashCode());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

class Person{
private String name;

public Person() {
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Person(String name) {
this.name = name;
}
}
class Student extends Person{
private String name;
public String getName() {
this.name="学生";
return name;
}
}
class Teacher extends Person{
private String name;

@Override
public String getName() {
this.name="教师";
return name;
}
}

输出结果如下:

1
2
3
4
5
6
7
8
9
学生
class com.company.Student
356573597
-------------
class com.company.Student
356573597
-------------
class com.company.Student
356573597

==注意:在运行期间,一个字节码文件(.class)只会加载一次,不论使用哪一种方式获取的Class对象都是同一个,只有一个Class对象产生。==

三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。

所有类型的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
package com.company;

import java.lang.annotation.ElementType;

public class Demo01 {
//所有类型的Class
public static void main(String[] args) {
Class c1 = Object.class;//类
Class c2 = Comparable.class;//接口
Class c3 = String[].class;//一维数组
Class c4 = int[][].class;//二维数组
Class c5 = Override.class;//注解
Class c6 = void.class;//void
Class c7 = ElementType.class;//枚举
Class c8 = Integer.class;//包装类
Class c9 = Class.class;//Class

System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
}
}

输出结果:

1
2
3
4
5
6
7
8
9
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
void
class java.lang.annotation.ElementType
class java.lang.Integer
class java.lang.Class

<2>Class类的常用方法

在这里插入图片描述

==获取功能:==

1.获取成员变量们
    • Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段。
      Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段。
    • Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段。
      Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.company;

import java.lang.reflect.Field;

public class Demo01Reflection {
public static void main(String[] args) throws Exception{
Class<?> c1 = Class.forName("com.company.Person2");
//获取成员变量们
//使用getField方法获取 公有的成员变量 可以获取到公有的
Field name = c1.getField("a");
System.out.println(name); //public int com.company.Person2.a
// //使用getField方法获取 私有的成员变量 不可以获取到私有的
// Field name1 = c1.getField("name");
// System.out.println(name1); //报错:NoSuchFieldException: name
// //使用getField方法获取 保护的成员变量 不可以获取到保护的
// Field c = c1.getField("c");
// System.out.println(c); //报错:NoSuchFieldException: c

//使用getFields获取多个成员变量
Field[] fields = c1.getFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
} /*
public int com.company.Person2.a
public int com.company.Person2.b
发现:获取到的都是公有的成员变量,私有的保护的都没有获得
*/


//使用getDeclaredField()方法获取
Field a = c1.getDeclaredField("a");
System.out.println(a); //public int com.company.Person2.a
Field na = c1.getDeclaredField("name");
System.out.println(na);//private java.lang.String com.company.Person2.name
Field c2 = c1.getDeclaredField("c");
System.out.println(c2);//protected int com.company.Person2.c
/*
得出:使用getDeclaredField()方法,可以获取任意的成员变量,不用管是公有的还是私有的还是受保护的
*/
//使用getDeclareFields()方法提取
Field[] declaredFields = c1.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
System.out.println(declaredFields[i]);
}
/*
private java.lang.String com.company.Person2.name
private int com.company.Person2.id
public int com.company.Person2.a
public int com.company.Person2.b
protected int com.company.Person2.c
*/
}
}
class Person2{
private String name;
private int id;
public int a=1;
public int b=2;
protected int c=2;
}

获取到了成员变量,我们能做什么呢?

*设置值set *获取值get

    • void set(Object obj, Object value) 将指定的对象参数中由此 Field对象表示的字段设置为指定的新值。
      Object get(Object obj) 返回由该 Field表示的字段在指定对象上的值。
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.company;

import java.lang.reflect.Field;

public class Demo01Reflection {
public static void main(String[] args) throws Exception{
Class<?> c1 = Class.forName("com.company.Person2");
//获取成员变量之后,我们能做什么?可以get set
Field name = c1.getField("a");
System.out.println(name);
//`Object``get(Object obj)`返回由该 `Field`表示的字段在指定对象上的值。
Person2 person2=new Person2();
Object o = name.get(person2);//Field类的get方法是需要传进去一个对象的
System.out.println(o);
//void set(Object obj, Object value) 将指定的对象参数中由此 Field对象表示的字段设置为指定的新值。
name.set(person2,2);
Object o1 = name.get(person2);
System.out.println(o1);

/*
此时是不是感觉很迷惑?我能直接创建对象,直接使用对象的get,set方法来对成员变量进行读取和改变。
为什么,还要先使用反射先获得Class对象,然后通过Class对象来获得该类的Field对象,然后再使用set,get方法呢???
这个问题就遗留给你了~~~
*/
System.out.println(person2.getName());
}
}
class Person2{
private String name;
private int id;
public int a=1;
public int b=2;
protected int c=2;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public int getA() {
return a;
}

public void setA(int a) {
this.a = a;
}

public int getB() {
return b;
}

public void setB(int b) {
this.b = b;
}

public int getC() {
return c;
}

public void setC(int c) {
this.c = c;
}
}
//上面那个问题你是不是和我一样钻牛角尖了呢?哈哈,反射是干啥的?反射就是把一个类给扒的裤衩都不剩,获取这个类的所有东西,没有东西是不能获取的,对于私有的不能那就暴力反射。当你使用反射的时候肯定对这个类的getset不了解,所以你需要获得Field类,这个类来封装该类的成员变量,用这个类来进行get,set。
2.获取构造方法们
    • Constructor getConstructor(Class... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数。
      Constructor[] getConstructors() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数。
    • Constructor getDeclaredConstructor(Class... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数。
      Constructor[] getDeclaredConstructors() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组。
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
package com.company;

import java.lang.reflect.Constructor;

public class Demo02Reflection {
public static void main(String[] args) throws Exception {
//首先获取Class对象,有异常,抛出去
Class<?> aClass = Class.forName("com.company.Student1");
//使用getConstructor()获取构造方法们
Constructor<?> constructor = aClass.getConstructor();
System.out.println(constructor);
//获得有参构造方法
Constructor<?> constructor1 = aClass.getConstructor(String.class, int.class);
System.out.println(constructor1);
//使用getConstructors()获取构造方法们
Constructor<?>[] constructors = aClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
System.out.println(constructors[i]);
}
//对于getDeclareConstructor()方法是来获取私有构造函数的,这里不再演示
}
}
class Student1{
private String name;
private int id;

public Student1(String name, int id) {
this.name = name;
this.id = id;
}

public Student1() {
}
}

获取完构造函数后能干嘛呢?当然创建对象了!

    • T newInstance(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
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
38
39
40
41
42
43
44
45
46
47
48
49
package com.company;

import java.lang.reflect.Constructor;

public class Demo02Reflection {
public static void main(String[] args) throws Exception {
//首先获取Class对象,有异常,抛出去
Class<?> aClass = Class.forName("com.company.Student1");
//使用getConstructor()获取构造方法们
Constructor<?> constructor = aClass.getConstructor();
System.out.println(constructor);

//使用constructor.newInstance来创建对象,无参构造函数
Object o = constructor.newInstance();
System.out.println(o);
//如果使用空参构造可以使用Class的newInstance()方法
Object o1 = aClass.newInstance();
System.out.println(o1);

//获得有参构造方法
Constructor<?> constructor1 = aClass.getConstructor(String.class, int.class);
System.out.println(constructor1);

//使用constructor1.newInstance来创建对象,有参构造函数
Object instance = constructor1.newInstance("三连", 3);
System.out.println(instance);
}
}
class Student1{
private String name;
private int id;

public Student1(String name, int id) {
this.name = name;
this.id = id;
}

@Override
public String toString() {
return "Student1{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}

public Student1() {
}
}

3.获取成员方法们
    • 方法 getMethod(String name, Class... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法。
      方法[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类。
      方法 getDeclaredMethod(String name, Class... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象。
      方法[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法。
    • Method类的方法

      • Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法。
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
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.company;

import java.lang.reflect.Method;

public class Demo03Reflection {
public static void main(String[] args) {
try {
Class aClass = Class.forName("com.company.Person3");
Method show = aClass.getMethod("show");
System.out.println(show);
//String getName​() 返回由该 方法对象表示的方法的名称,作为 String 。
String name = show.getName();
System.out.println(name);
//Object invoke​(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法。
Person3 person3=new Person3();
show.invoke(person3);
//传递参数的
Method method = aClass.getMethod("show", int.class);
method.invoke(person3,12);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person3{
private String name;
private int id;
public void show(){
System.out.println("调用了show方法~~~");
}
public void show(int i){
System.out.println("重载的show方法");
}
public Person3() {
}

@Override
public String toString() {
return "Person3{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}

public Person3(String name, int id) {
this.name = name;
this.id = id;
}
}

4.获取类名
    • String getName() 返回由该 Class对象表示的实体(类,接口,数组类,原始类型或无效)的 Class ,作为 String
      String getPackageName() 返回完全限定的包名称。
1
2
3
4
5
6
7
8
9
10
11
12
package com.company;
public class Demo04Reflection {
public static void main(String[] args) {
try {
String name = Class.forName("com.company.Person").getName();
System.out.println(name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

点击查看
-------------------本文结束 感谢您的阅读-------------------