1..获取Class实例的方式
1 @Test
2 public void test3() throws ClassNotFoundException {
3 //方式一:调用运行时类的属性:.class
4 Class clazz1 = Person.class;
5 System.out.println(clazz1);
6 //方式二:通过运行时类的对象,调用getClass()
7 Person p1 = new Person();
8 Class clazz2 = p1.getClass();
9 System.out.println(clazz2);
10
11 //方式三:调用Class的静态方法:forName(String classPath)
12 Class clazz3 = Class.forName("com.atguigu.java.Person");
13 // clazz3 = Class.forName("java.lang.String");
14 System.out.println(clazz3);
15
16 System.out.println(clazz1 == clazz2);
17 System.out.println(clazz1 == clazz3);
18
19 //方式四:使用类的加载器:ClassLoader (了解)
20 ClassLoader classLoader = ReflectionTest.class.getClassLoader();
21 Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
22 System.out.println(clazz4);
23
24 System.out.println(clazz1 == clazz4);
25
26 }
2.Class类的常用方法
(1)forName():返回指定类名name的Class对象
(2)getName():以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
(3)newInstance():调用缺省的构造函数,返回该Class对象的一个实例
(4)getClassLoader():返回该类的类加载器
(5)getSuperclass():返回此Class所表示的实体的超类的Class
(6)Constructor[] getConstructors():返回一个包含某些Constructor对象的数组
(7)Field[] getDeclaredFields():返回Field对象的一个数组
(8)Method getMethod(String name,Class … paramTypes):返回一个Method对象,此对象的形参类型为paramType
3.哪些类型可以有Class对象?
(1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void
三.反射应用
1.创建运行时类的对象
创建类的对象:调用Class对象的newInstance()方法
要求:类必须有一个无参构造器,且类的构造器的访问权限需要足够
或者调用有参构造器:
通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
代码显示:
1 @Test
2 public void testField() throws Exception {
3 Class clazz = Person.class;
4
5 //创建运行时类的对象
6 Person p = (Person) clazz.newInstance();
1 //1.根据全类名获取对应的Class对象
2 String name = "atguigu.java.Person";
3 Class clazz = null;
4 clazz = Class.forName(name);
5 //2.调用指定参数结构的构造器,生成Constructor的实例
6 Constructor con = clazz.getConstructor(String.class,Integer.class);
7 //3.通过Constructor的实例创建对应类的对象,并初始化类属性
8 Person p2 = (Person) con.newInstance("Peter",20);
9 System.out.println(p2);
2.获取运行时类的完整结构
我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等。。。。
获取属性结构:
1 @Test
2 public void test1(){
3
4 Class clazz = Person.class;
5
6 //获取属性结构
7 //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
8 Field[] fields = clazz.getFields();
9 for(Field f : fields){
10 System.out.println(f);
11 }
12 System.out.println();
13
14 //getDeclaredFields():获取当前运行时类中声明的所属性。(不包含父类中声明的属性
15 Field[] declaredFields = clazz.getDeclaredFields();
16 for(Field f : declaredFields){
17 System.out.println(f);
18 }
19 }
获取方法:
1 @Test
2 public void test1(){
3
4 Class clazz = Person.class;
5
6 //getMethods():获取当前运行时类及其所父类中声明为public权限的方法
7 Method[] methods = clazz.getMethods();
8 for(Method m : methods){
9 System.out.println(m);
10 }
11 System.out.println();
12 //getDeclaredMethods():获取当前运行时类中声明的所方法。(不包含父类中声明的方法
13 Method[] declaredMethods = clazz.getDeclaredMethods();
14 for(Method m : declaredMethods){
15 System.out.println(m);
16 }
17 }
获取构造器结构:
1 @Test
2 public void test1(){
3
4 Class clazz = Person.class;
5 //getConstructors():获取当前运行时类中声明为public的构造器
6 Constructor[] constructors = clazz.getConstructors();
7 for(Constructor c : constructors){
8 System.out.println(c);
9 }
10
11 System.out.println();
12 //getDeclaredConstructors():获取当前运行时类中声明的所的构造器
13 Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
14 for(Constructor c : declaredConstructors){
15 System.out.println(c);
16 }
17
18 }
3.获取运行时类的指定结构
调用指定方法:
通过反射,调用类中的方法,通过Method类完成。步骤:
1.通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
2.之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
Object invoke(Object obj, Object … args)方法说明:
- Object 对应原方法的返回值,若原方法无返回值,此时返回null
- 若原方法若为静态方法,此时形参Object obj可为null
- 若原方法形参列表为空,则Object[] args为null
- 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
代码显示:
调用指定的属性:
1 调用指定的属性:
2 @Test
3 public void testField1() throws Exception {
4 Class clazz = Person.class;
5
6 //创建运行时类的对象
7 Person p = (Person) clazz.newInstance();
8
9 //1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
10 Field name = clazz.getDeclaredField("name");
11
12 //2.保证当前属性是可访问的
13 name.setAccessible(true);
14 //3.获取、设置指定对象的此属性值
15 name.set(p,"Tom");
16
17 System.out.println(name.get(p));
18 }
调用指定的方法:
1 @Test
2 public void testMethod() throws Exception {
3
4 Class clazz = Person.class;
5
6 //创建运行时类的对象
7 Person p = (Person) clazz.newInstance();
8
9 /*
10 1.获取指定的某个方法
11 getDeclaredMethod():参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
12 */
13 Method show = clazz.getDeclaredMethod("show", String.class);
14 //2.保证当前方法是可访问的
15 show.setAccessible(true);
16
17 /*
18 3. 调用方法的invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参
19 invoke()的返回值即为对应类中调用的方法的返回值。
20 */
21 Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");
22 System.out.println(returnValue);
23
24 System.out.println("*************如何调用静态方法*****************");
25
26 // private static void showDesc()
27
28 Method showDesc = clazz.getDeclaredMethod("showDesc");
29 showDesc.setAccessible(true);
30 //如果调用的运行时类中的方法没返回值,则此invoke()返回null
31 // Object returnVal = showDesc.invoke(null);
32 Object returnVal = showDesc.invoke(Person.class);
33 System.out.println(returnVal);//null
34
35 }
调用指定构造器:
1 @Test
2 public void testConstructor() throws Exception {
3 Class clazz = Person.class;
4
5 //private Person(String name)
6 /*
7 1.获取指定的构造器
8 getDeclaredConstructor():参数:指明构造器的参数列表
9 */
10
11 Constructor constructor = clazz.getDeclaredConstructor(String.class);
12
13 //2.保证此构造器是可访问的
14 constructor.setAccessible(true);
15
16 //3.调用此构造器创建运行时类的对象
17 Person per = (Person) constructor.newInstance("Tom");
18 System.out.println(per);
19
20 }
关于setAccessible方法的使用:
- Method和Field、Constructor对象都有setAccessible()方法。
- setAccessible启动和禁用访问安全检查的开关。
- 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。使得原本无法访问的私有成员也可以访问
- 参数值为false则指示反射的对象应该实施Java语言访问检查。
Original: https://www.cnblogs.com/xiuercui/p/13432174.html
Author: 程序界第一佳丽
Title: java反射机制
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/577547/
转载文章受原作者版权保护。转载请注明原作者出处!