JAVA进阶 —— 反射

目录

一、什么是反射?

 二、获取 Class对象 的三种方式

三、反射获取构造方法(Constructor)

四、反射获取成员变量(Field)

五、反射获取成员方法(Method)

六、综合练习

1.  保存信息

2.  配置文件结合创建对象


一、什么是反射?

  • 反射允许对成员变量,成员方法和构造方法的信息进行编程访问。
  • 反射就是把java类中的各种成分映射成一个个的Java对象

  • 例如:一个类有:成员变量、方法、构造方法等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

idea自动提示

提问:为什么不能用IO流从上往下一行一行的进行读取呢?

  • 但是当我们读取到构造方法和普通成员方法时,无法区分。
  • 成员变量和局部变量也很难区分。

因此我们使用 反射 获取成员变量就可以得到成员所有信息

 反射的作用:

  • 获取一个类里面的所有的信息,获取到了之后,再执行其他的业务逻辑。
  • 结合配置文件,动态的创建对象并调用方法。

 二、获取 Class对象 的三种方式

使用反射的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)

  1.  Class.forName ( " 全类名 " ) ;             (最为常用)
  2. 类名 . class       (一般更多的是当做参数进行传递)
  3. 对象 . getClass ( ) ;  (当已经有类对象是才能使用)

public class MyReFlectDemo {
	public static void main(String[] args) throws ClassNotFoundException {
		// 1.第一种方式
		// 全类名 : 包名 + 类名
		Class clazz1 = Class.forName("ReFlect.Student");
		System.out.println(clazz1); // class ReFlect.Student

		// 2.第二种方式
		Class clazz2 = Student.class;
		System.out.println(clazz2); // class ReFlect.Student
		System.out.println(clazz1 == clazz2); // true

		// 3.第三种方式
		Student s = new Student();
		Class clazz3 = s.getClass();
		System.out.println(clazz1 == clazz2); // true
		System.out.println(clazz2 == clazz3); // true
	}
}

三、反射获取构造方法(Constructor)

Class类中获取构造方法的方法:

Constructor <?> [ ] getConstructors() 返回所有公共构造方法对象的数组
Constructor <?> [ ] getDeclaredConstructors() 返回所有构造方法对象的数组
Constructor <T> getConstructor ( Class <> .. parameterTypes ) 返回单个公共构造方法对象
Constructor <T> getDeclaredConstructor(Class <>.. parameterTypes) 返回单个构造方法对象

Constructor类中用于创建对象的方法:

T newInstance ( Oject... initargs ) 根据指定的构造方法创建对象
setAccessible ( boolean flag ) 设置为true,表示取消访问检查
public class MyReFlectDemo {
	public static void main(String[] args) throws 
          ClassNotFoundException, NoSuchMethodException, SecurityException {

		// 1.获取Class字节码文件的对象
		Class clazz = Class.forName("ReFlect.Student");

		// 2.获取构造方法
		// 获取所有
		Constructor[] cons1 = clazz.getConstructors();
		for (Constructor con : cons1) {
			System.out.println(con);
		}

		Constructor[] cons2 = clazz.getDeclaredConstructors();
		for (Constructor con : cons2) {
			System.out.println(con);
		}
			// 获取单个
			Constructor con1 = clazz.getDeclaredConstructor();
			System.out.println(con1);  //public ReFlect.Student()

			Constructor con2 = clazz.getDeclaredConstructor(String.class);
			System.out.println(con2);  //public ReFlect.Student(java.lang.String)
			
			Constructor con3 = clazz.getDeclaredConstructor(int.class);
			System.out.println(con3);  //public ReFlect.Student(int)
			
			//获取两个参数
			Constructor con4 = 
               clazz.getDeclaredConstructor(String.class,int.class);
			System.out.println(con4);  //public 
               ReFlect.Student(java.lang.String,int)
			//接下来我们就可以反射获取所有信息:
			//比如1:权限修饰符
			int modifiers = con4.getModifiers();
			System.out.println(modifiers); //1
			//比如2:获取构造方法所有参数
			Parameter[] parameters = con4.getParameters();
			for(Parameter parameter:parameters) {
				System.out.println(parameter); 
				//java.lang.String arg0
				//int arg1
			}
			//比如3:利用构造方法创建对象
			con4.setAccessible(true); //暴力反射:表示临时取消权限校验
			Object stu = (Student)con4.newInstance("张三",23);
			System.out.println(stu); //Student [name=张三, age=23]
	}
}


//Student.java
public class Student {
	private String name;
	private int age;

	public Student() {
	}

	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public Student(String name) {
		this.name = name;
	}

	public Student(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

四、反射获取成员变量(Field)

Class类中获取成员变量的方法:

Field [ ]  getFields() 返回所有公共成员变量对象的数组
Field [ ]  getDeclaredFields ( ) 返回所有成员变量对象的数组
Field getField ( String name ) 返回单个公共成员变量对象
Field getDeclaredField ( String name ) 返回单个成员变量对象

Field类中用于创建对象的方法:

void set ( Object obj , Object value ) 赋值
Object get ( Object obj ) 获取值
public class MyReFlectDemo {
	public static void main(String[] args) throws 
               ClassNotFoundException, NoSuchFieldException{

		// 1.获取Class字节码文件的对象
		Class clazz = Class.forName("ReFlect.Student");

		// 获取成员变量
		//获取所有的成员变量
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			System.out.println(field);
			//private java.lang.String ReFlect.Student.name
			//private int ReFlect.Student.age
			//public java.lang.String ReFlect.Student.gender
		}
		
		//获取单个成员变量
		Field gender = clazz.getField("gender");
		System.out.println(gender);
		//public java.lang.String ReFlect.Student.gender
		
		//Field name = clazz.getField("name");  
		//无法获取 name是private私有的
		Field name = clazz.getDeclaredField("name"); 
		System.out.println(name);
		//private java.lang.String ReFlect.Student.name
		
		//获取到成员变量后我们可以继续:
		//1.获取权限修饰符
		int modifier = name.getModifiers();
		System.out.println(modifier);  //2
		//2.获取成员变量名
		String n = name.getName();
		System.out.println(n); //name
		//3.获取数据类型
		Class<?> type = name.getType();
		System.out.println(type); //class java.lang.String
		//4.获取成员变量记录的值
		Student s = new Student("张三",23,"男");
		name.setAccessible(true);
		Object value = (String)name.get(s);  //张三
		System.out.println(value);
		//5.修改成员变量记录的值
		name.set(s, "李四");
		System.out.println(s);  //Student [name=李四, age=23, gender=男]	
	}
}



public class Student {
	private String name;
	private int age;
	public String gender;

	public Student() {
	}

	public Student(String name, int age, String gender) {
		this.name = name;
		this.age = age;
		this.gender = gender;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]";
	}
}

五、反射获取成员方法(Method)

Class类中获取成员方法的方法:

Method [ ]  getMethods ( ) 返回所有公共成员方法对象的数组,包括继承的
Method [ ]  getDeclaredMethods ( ) 返回所有成员方法对象的数组,不包括继承的
Method getMethod ( String name ,  Cass <?> .. parameterTypes ) 返回单个公共成员方法对象
Method getDeclaredMethod ( String name ,  Class<?>... parameterTypes ) 返回单个成员方法对象

Method类中用于创建对象的方法:

Object invoke ( Object obj ,  Object... args ) 运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
public class MyReFlectDemo {
	public static void main(String[] args) throws 
           ClassNotFoundException, NoSuchFieldException {

		// 1.获取Class字节码文件的对象
		Class clazz = Class.forName("ReFlect.Student");

		// 2.获取里面所有的方法对象
		//(包含所有父类中的所有的公共方法)
		Method[] methods1 = clazz.getMethods();
		for(Method method : methods1) {
			System.out.println(method);
		}
		//获取里面所有的方法对象(只能获取本类中私有方法)
		Method[] methods2 = clazz.getDeclaredMethods();
		for(Method method : methods2) {
			System.out.println(method);
		}
		
		//3.获取指定单一方法对象
		Method m = clazz.getDeclaredMethod("eat", String.class);
		System.out.println(m); //private void ReFlect.Student.eat(java.lang.String)
		  //1.获取权限修饰符
		int modifers = m.getModifiers();
		System.out.println(modifers); //2
		//2.获取方法名
		String name = m.getName();
		System.out.println(name);  //eat
		//3.获取方法形参
		Parameter[] parameters = m.getParameters();
		for (Parameter parameter : parameters) {
		System.out.println(parameter);	 //java.lang.String arg0
		}
		//4.获取方法返回值
		//5.获取方法抛出异常
		Class<?>[] exceptionTypes = m.getExceptionTypes();
		for(Class exceptiontype : exceptionTypes) {
			System.out.println(exceptiontype);
			//class Java.io.TOException
			//class java. lang. NullPointerException
			//class java. lang.ClassCastException

		}
		
		//方法运行
		Student s = new Student();
		m.setAccessible(true);
		m.invoke(s, "汉堡包");
	}
}


public class Student {
	private String name;
	private int age;

	public Student() {
	}

	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}

	public void sleep() throws 
            IOException, NullPointerException, ClassCastException {
		System.out.println("睡觉");
	}

	private void eat(String something) {
		System.out.println("在吃" + something);
	}
}

六、综合练习

1.  保存信息

对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去。

public class MyReFlectDemo {
	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, IOException {

		Student s = new Student("张三", 23, '男', 175, "睡觉");
		Teacher t = new Teacher("李四", 10000);

		saveObject(s);

	}

	// 把对象里面所有的成员变量名和值保存到本地文件中
	public static void saveObject(Object obj) throws IllegalArgumentException, IllegalAccessException, IOException {
		// 1.获取字节码文件的对象
		Class clazz = obj.getClass();

		// 创建IO流
		BufferedWriter bw = new BufferedWriter(new FileWriter("java02//a.txt"));

		// 2.获取所有的成员变量
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			// 获取成员变量的名字
			String name = field.getName();
			// 获取成员变量的值
			Object value = field.get(obj);
			// 写出数据
			bw.write(name + "=" + value);
			bw.newLine();
			// System.out.println(name + "=" +value);
		}
		bw.close();
	}
}

2.  配置文件结合创建对象

结合配置文件,动态的创建对象,并调用方法

public class MyReFlectDemo {
	public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

		//1.读取配置文件中的信息
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream("java02//prop.properties");
		prop.load(fis);
		fis.close();
		System.out.println(prop);
		
		//2.获取全类名和方法名
		String classname = (String)prop.get("classname");
		String methodname = (String)prop.get("method");
		
		System.out.println(classname);
		System.out.println(methodname);
		
		//3.利用反射创建对象并运行方法
		Class clazz = Class.forName(classname);
		
		//获取构造方法
		Constructor con = clazz.getDeclaredConstructor();
		Object o = con.newInstance();
		System.out.println(o);
		
		//获取成员方法并运行
		Method method = clazz.getDeclaredMethod(methodname);
		method.setAccessible(true);
		method.invoke(o);
	}
}

猜你喜欢

转载自blog.csdn.net/hdakj22/article/details/129663016