Java 反射编程(下)

Posted _大木_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 反射编程(下)相关的知识,希望对你有一定的参考价值。

文章目录

反射与类操作(反射调用方法)

调用普通方法(核心)

在Class 类中定义有如下两个取得类中普通方法的定义

  1. 取得全部方法
public Method[] getMethods()
                    throws SecurityException
  1. 取得指定的方法(核心)
public Method getMethod(String name,
                        Class<?>... parameterTypes)
                 throws NoSuchMethodException,
                        SecurityException

以上两个方法返回的类型是 java.long.reflect.Method 类的对象. 在此类中提供有一个调用的方法支持,即如下
最重要的方法:

public Object invoke(Object obj, Object... args)
              throws IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException

案例: 取得一个类中的全部方法

package com.beyond.dhl.exercise;

import java.lang.reflect.Method;

class Person
	private String name;
	public void setName(String name) 
		this.name = name;
	
	public String getName() 
		return name;
	


public class Test01 
	public static void main(String[] args) throws Exception 
		Class<?> cls = Person.class;
		Method met[] = cls.getMethods();  // 取得全部方法
		for (int x = 0; x < met.length; x++) 
			System.out.println(met[x]);
			
	


可以取得类中的全部方法, 包括继承的Object类

那么在之前所编写的程序对于类中的 setter, getter 方法 采用的都是明确的对象调用. 而现在有了反射处理机制之后, 这个时候的程序即使你没有明确的Person类型的对象(依然需要实例化对象, Object描述, 所有的普通方法必须在有实例化对象之后才可以进行调用), 就需要通过反射完成.

案例: 通过反射调用 setter和getter(有明确开发要求)

package com.beyond.dhl.exercise;

import java.lang.reflect.Method;

class Person
	private String name;
	public void setName(String name) 
		this.name = name;
	
	public String getName() 
		return name;
	


public class Test01 
	public static void main(String[] args) throws Exception 
		String attribute = "name";  // 明确的告诉你属性名称
		String value = "DHL"; // 明确告诉你要设置的内容
		Class<?> cls = Class.forName("com.beyond.dhl.exercise.Person");  // Class.forName("com.beyond.dhl.exercise.Person") 相当于 Person.class 
		Object obj = cls.newInstance();  // 任何情况下调用类中的普通方法, 都必须有实例化对象
		// 取得setName这个方法是实例化对象, 设置方法名称和参数的类型
		// setName() 是方法名称, 但是这个方法名称是根据给定的属性的信息拼凑得来的, 同时该方法需要接收一个String 类型的参数
		Method setMethod = cls.getMethod("set"+initcap(attribute), String.class);
		// 随后需要通过Method类对象调用指定的方法, 调用方法必须有实例化对象, 同时要传入一个参数
		setMethod.invoke(obj, value); // 相当于: Person对象.setName(value)
		
		Method getMethod = cls.getMethod("get"+initcap(attribute));
		Object ret = getMethod.invoke(obj);  // 相当于 Person对象.getName()
		System.out.println(ret);
		
	
	
	public static String initcap(String str) 
		return str.substring(0,1).toUpperCase() + str.substring(1);
		


此类操作的好处是 : 不再局限于某一具体类型的对象, 而是可以通过 Object 类型进行所有类的方法的调用

反射与类操作(反射调用成员)

在之前已经成功的实现了类的构造调用, 方法调用, 那么除了这两种模式之外还需要有成员调用.
前提: 类中的所有属性一定要在类对象实例化之后才会进行空间的分配, 所有此时如果要想调用类的属性, 必须要有实例化对象, 而通过反射的 newInstence() 方法可以直接取得实例化对象(Object 类型).

在Class 类里面提供了有两组取得属性操作的方法:

1. 取得包括继承类的属性(是public权限)(第一组)

1.1 取得类中的全部属性

public Field[] getFields()
                  throws SecurityException

1.2 取得类中指定名称的属性

public Field getField(String name)
               throws NoSuchFieldException,SecurityException

2. 取得本类属性(第二组)(无权限要求)

2.1 取得本类中的全部属性

public Field[] getDeclaredFields()
                          throws SecurityException

2.2 取得本类中指定名称的属性

public Field getDeclaredField(String name)
                       throws NoSuchFieldException, SecurityException

案例: 取得类中的全部方法

package com.beyond.dhl.exercise;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person
	private String name;  // 此时的类中只是明确提供了一个属性
	protected String nickName;  // 此时的类中只是明确提供了一个属性
	


class Student extends Person  // 做一个继承关系
	private String school;
	public String nameString;


public class Test01 
	public static void main(String[] args) throws Exception 
		Class<?> cls = Class.forName("com.beyond.dhl.exercise.Student");
		 // 普通代码块
			Field fields[] = cls.getFields();  // 取得全部属性
			for (int x = 0; x < fields.length; x++) 
				System.out.println(fields[x]);
			
			
		
		System.out.println("====================");
		 // 普通代码块
			Field fields[] = cls.getDeclaredFields();  // 取得全部属性
			for (int x = 0; x < fields.length; x++) 
				System.out.println(fields[x]);
			
			
		
		
 	


java.lang.reflect.Field 类

现在就需要关注属性的核心描述类: java.lang.reflect.Field, 在这个类有两个重要的方法:

1. 设置属性内容(必须有了实例化对象才能开辟属性的空间):

public void set(Object obj, Object value)
         throws IllegalArgumentException, IllegalAccessException

2. 取得属性内容:

public Object get(Object obj)
           throws IllegalArgumentException, IllegalAccessException

在 AccessibleObject 中提供有一个方法 : 动态设置封装, 也称为 暴力反射

public void setAccessible(boolean flag)
                   throws SecurityException

即使用如下语句可以取消封装:

nameField.setAccessible(true);  // 取消封装

案例: 通过反射操作类属性

package com.beyond.dhl.exercise;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person
	private String name;  // 此时的类中只是明确提供了一个属性
	




public class Test01 
	public static void main(String[] args) throws Exception 
		Class<?> cls = Class.forName("com.beyond.dhl.exercise.Person");
		Object obj = cls.newInstance();  // 实例化本类对象
		Field nameField = cls.getDeclaredField("name");
		nameField.setAccessible(true);  // 取消封装
		nameField.set(obj, "张三"); // 等价于 对象.name = "张三";
		System.out.println(nameField.get(obj));  // 取得属性
		
 	


注意:

但是如果在实际开发之中使用更多的属性操作绝对不可能直接按照如上的模式进行, 一定要使用setter, getter 方法, 应该可以给用户操作的机会.
在 Field 类中有一个特别有用的方法: 取得属性类型

public Class<?> getType()
package com.beyond.dhl.exercise;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person
	private String name;  // 此时的类中只是明确提供了一个属性
	


public class Test01 
	public static void main(String[] args) throws Exception 
		Class<?> cls = Class.forName("com.beyond.dhl.exercise.Person");
		Object obj = cls.newInstance();  // 实例化本类对象
		Field nameField = cls.getDeclaredField("name");
		System.out.println(nameField.getType().getName());  // 包.类
		System.out.println(nameField.getType().getSimpleName()); // 类名
		
 	


将 Field 取得属性与 Method 类中的 invoke() 结合一起, 可以编写非常灵活的程序了.

以上是关于Java 反射编程(下)的主要内容,如果未能解决你的问题,请参考以下文章

java getClass()

华为大佬讲解JAVA编程不可不知的反射用法总结

网络编程和反射机制

Java—反射

java反射概述

4.Spring中的反射