第15章 反射

第15章 反射

反射的概念

JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

我们创建对象的方式: Date date = new Date(); 在编译阶段类型是确定的; 反射可以提供运行期创建对象的方式. 客车: 在车站里载人, 静态的; 运行期是客车在路上正在运行: 上个人. java程序如何在运行期创建对象并调用方法, 调用方法才可以获取对象的功能.

反射在java的框架中都得到深入的使用, mybatis,Spring 核心框架技术都是基于反射的技术.

反射的基础

从哪里开始进行反射的操作? 生活中反射的意思: 镜子可以反射出对象的信息: 张书峰站在镜子面前可以反射出张书峰的信息: 身高, 性别, 眨眼(动作). 我们要有一个镜子, 第二要有反射的对象. 镜子是最关键的东西, 回到程序: 我们发现所有的java程序都由类组成的. 镜子要能够描述类的信息.有一个类叫Class就是一面镜子. There is a class named Class.

反射的对象

package com.hanker.reflection;

import java.io.Closeable;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
/**
 * 被反射的对象
 * @author Administrator
 * @Title:  Student.java
 * All rights Reserved, Designed By www.hanker.com
 * @date:   2020年1月2日 下午2:26:51   
 * @version V1.0 
 * @Copyright: 2020 www.hanker.com Inc. All rights reserved. 
 * 注意:本内容仅限于河南汉科网络信息技术股份有限公司内部传阅,禁止外泄以及用于其他的商业目
 */
public class Student implements Serializable,Closeable {
	//2    +  8    + 16
	private static final long serialVersionUID = 1L;
	private String name;
	public int age;
	protected double height;
	
	public static void main(String[] args) {
		System.out.println(Arrays.toString(args));
		Student s = new Student("古力娜扎",35,1.63);
		s.print();
	}
	
	public void print() {
		System.out.println("姓名:"+name);
		System.out.println("年龄:"+age);
		System.out.println("身高:"+height);
	}
	
	public int work(int hours,int money) {
		int  salary = hours*money;
		return  salary;
	}
	
	public Student() {
		super();
		System.out.println("====调用无参构造方法=====");
	}
	public Student(String name, int age, double height) {
		super();
		System.out.println("====调用有参构造方法=====");
		this.name = name;
		this.age = age;
		this.height = height;
	}
	public String getName() {
		System.out.println("==调用getName方法==");
		return name;
	}
	public void setName(String name) {
		System.out.println("==调用setName方法==");
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public double getHeight() {
		return height;
	}
	public void setHeight(double height) {
		this.height = height;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", height=" + height + "]";
	}

	@Override
	public void close() throws IOException {
		
		
	}
}
//============================
package com.hanker.reflection;
public class Teacher {
	private String name;
	public void teach() {
		System.out.println(name + "在教学.....");
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

Class简介

public final class Class<T> extends Object
        implements Serializable, GenericDeclaration, Type, AnnotatedElement

Class类是反射的基础, 是一面镜子. 如何获取Class类型的对象. 然后才可以获取类的各种信息,并且可以调用方法.

获取Class的方式

通过对象getClass方法获取

private static void test1() {
    //如果类型名称知道,还有对象名,就不用通过反射获取类的信息
    Student  student = new Student();
    Class<? extends Student> class1 = student.getClass();
    //可以获取Student类的相关信息
    String name = class1.getName();
    System.out.println("类的名称:"+name);
}

通过Class.forName获取

/**
	 * 万物皆对象
	 * Student---->学生
	 * Computer--->电脑
	 * File------->电脑的文件信息
	 * Math------->数学相关的信息
	 * Class------>java的字节码文件,所有的类的信息
	 * Field------>类的属性信息
	 * Method----->类的方法信息
	 * Constructor->类的构造方法信息
	 * @param args
	 * @throws ClassNotFoundException
	 */
public static void main(String[] args) throws ClassNotFoundException {
    /**
	* clazzName 是对象名, 谁的对象:Class类型的对象
	* 这个对象描述信息是谁的? Student
	*/
    String className = "com.hanker.reflection.Student";
    Class<?> clazzName = Class.forName(className);
    System.out.println("类名:"+clazzName.getName());
}

通过Type属性获取

private static void test2() {
    //前提条件是知道类名称,这样也不用反射
    Class<Integer> intClass = Integer.TYPE;
    System.out.println("类名:"+intClass.getName());
    System.out.println("简单的类名:"+intClass.getSimpleName());
    System.out.println("类型名称:"+intClass.getTypeName());
}

通过类名获取Class对象

private static void test3() {
    //还是要知道类名,如果知道类名就可以创建对象调用方法,就没有反射的必要
    Class<Student> clazz = Student.class;
    Class<? super Student> superclass = clazz.getSuperclass();
    System.out.println("父类:"+superclass.getName());
    Class<?>[] interfaces = clazz.getInterfaces();
    for (int i = 0; i < interfaces.length; i++) {
        System.out.println("实现的接口: " + interfaces[i]);
    }
}

反射类的信息

private static void test4() throws ClassNotFoundException {
		/**
		 * clazzName 是对象名, 谁的对象:Class类型的对象
		 * 这个对象描述信息是谁的? Student
		 */
		String className = "com.hanker.reflection.Student";
		Class<?> clazzName = Class.forName(className);
		System.out.println("类名:"+clazzName.getName());
		System.out.println("简单的类名:"+clazzName.getSimpleName());
		System.out.println("父类:"+clazzName.getSuperclass().getName());
		Class<?>[] interfaces = clazzName.getInterfaces();
		for (int i = 0; i < interfaces.length; i++) {
			System.out.println("实现的接口: " + interfaces[i]);
		}
		System.out.println("类所在的包:"+clazzName.getPackage().getName());
		System.out.println("类的访问修饰符:"+clazzName.getModifiers());
	}

在这里插入图片描述

反射创建对象

public static void main(String[] args) throws Exception {
    // Student stu = new Student();
    String className = "com.hanker.reflection.Student";
    Class<?> clazz = Class.forName(className);
    //调用对应类型的无参构造方法,必须有无参构造方法,并且不能是私有的private
    Object obj = clazz.newInstance();
    //调用toString方法
    System.out.println(obj);
}

反射属性信息

private static void test1() throws ClassNotFoundException, NoSuchFieldException {
		String clazzName="com.hanker.reflection.Student";
		Class clazz  = Class.forName(clazzName);
		//获取所有的属性信息
		Field[] fields = clazz.getFields();//获取所有的共有的属性
		System.out.println(fields.length);
		Field[] df = clazz.getDeclaredFields();//获取所有属性
		System.out.println(df.length);
		for (Field field : df) {
			System.out.println("属性名称:"+field.getName()+
					"类型:"+field.getType()+
					"修饰符:"+field.getModifiers());
		}
		//获取指定属性
		Field nameField = clazz.getDeclaredField("name");
		System.out.println("name属性 :" +nameField);
	}

获取属性的目的是绑定值, 如何调用属性的方法:

public static void main(String[] args) throws Exception {
		//默认私有属性没有权限访问
		String clazzName="com.hanker.reflection.Student";
		Class clazz  = Class.forName(clazzName);
		Object obj = clazz.newInstance();
		Field nameField = clazz.getDeclaredField("name");
		nameField.setAccessible(true);//强制执行,破门而入
		nameField.set(obj, "迪丽热巴");
		System.out.println("获取属性值:"+nameField.get(obj));
		//set方法和get方法并不是调用的属性对应的getter和setter方法
	}

反射构造方法信息

private static void test3() throws Exception {
		String clazzName="com.hanker.reflection.Student";
		Class clazz  = Class.forName(clazzName);
		//获取所有的构造方法:共有的
		Constructor[] constructors = clazz.getConstructors();
		for (Constructor constructor : constructors) {
			System.out.println("构造方法:"+constructor);
		}
		//获取无参构造方法
		Constructor c = clazz.getConstructor();
		Object obj = c.newInstance();
		//获取有参构造器
		Constructor c2 = clazz.getConstructor(String.class,int.class,double.class);
		Object obj2 = c2.newInstance("迪丽热巴",27,1.65);
		System.out.println(obj2);
	}

反射普通方法信息

private static void test1() throws Exception {
		String clazzName="com.hanker.reflection.Student";
		Class clazz  = Class.forName(clazzName);
		//获取所有的方法:公有私有,只是当前类声明的
		System.out.println("==========获取当前类方法===========");
		Method[] methods = clazz.getDeclaredMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
		System.out.println("==========获取所有方法包括父类===========");
		//当前类和父类的方法
		Method[] methods2 = clazz.getMethods();
		for (Method method : methods2) {
			System.out.println(method);
		}
		//获取指定方法
		System.out.println("========获取指定方法==========");
		Method workMethod = clazz.getMethod("work", int.class,int.class);
		System.out.println(workMethod);
	}

调用方法:

private static void test2() throws Exception {
		String clazzName="com.hanker.reflection.Student";
		Class clazz  = Class.forName(clazzName);
		Object obj = clazz.newInstance();//创建对象
		Method workMethod = clazz.getMethod("work", int.class,int.class);
		//必须有对象,注意传对应的参数
		Object result = workMethod.invoke(obj, 10,100);
		System.out.println("应付工资:"+result);
}

反射main方法信息

private static void test3() throws Exception {
    String clazzName="com.hanker.reflection.Student";
    Class clazz  = Class.forName(clazzName);
    Method mainMethod = clazz.getMethod("main", String[].class);
    //main方法不用对象,传的是null
    mainMethod.invoke(null, new Object[]{new String[] {"a","b","c"}});
}

反射越过泛型检查

package com.hanker.reflection;

import java.lang.reflect.Method;
import java.util.ArrayList;
//反射越过泛型检查
public class GeneralricDemo {
	public static void main(String[] args) throws Exception {
		ArrayList<String> list = new ArrayList<>();
		list.add("this");
		list.add("is");
		//strList.add(5);//报错
		/********** 越过泛型检查    **************/
		//获取ArrayList的Class对象,反向的调用add()方法,添加数据
		Class listClass = list.getClass(); 
		//获取add()方法
		Method m = listClass.getMethod("add", Object.class);
		//调用add()方法
		m.invoke(list, 5);
		
		//遍历集合
		for(Object obj : list){
			System.out.println(obj);
		}
	}
}

反射获取泛型信息

package com.hanker.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
//反射越过泛型检查
public class GeneralricDemo {
	
	public void test01(Map<String,Student> map,List<Teacher> list) {
		System.out.println("方法:test01");
	}	
	public Map<String,Student> test02(){
		System.out.println("方法:test02");
		return null;
	}
	
	
	
	public static void main(String[] args) throws Exception {
		//根据方法名称和参数类型获取方法
		Method method01 = GeneralricDemo.class.getMethod("test01", Map.class,List.class);
		//获取该方法的泛型参数类型
		Type[] types = method01.getGenericParameterTypes();
		for (Type type : types) {
			System.out.println("参数:"+type);
			Type[] act = ((ParameterizedType)type).getActualTypeArguments();
			for (Type t : act) {
				System.out.println("真实类型:"+ t);
			}
		}
		System.out.println("==========获取返回值泛型============");
		Method m02 = GeneralricDemo.class.getMethod("test02");
		//获取方法的泛型类型的返回值
		Type retType = m02.getGenericReturnType();
		System.out.println("返回值类型:"+retType);
		Type[] actualType = ((ParameterizedType)retType).getActualTypeArguments();
		for (Type type : actualType) {
			System.out.println("\t" + type);
		}
	}

	private static void test1() throws Exception {
		ArrayList<String> list = new ArrayList<>();
		list.add("this");
		list.add("is");
		//strList.add(5);//报错
		/********** 越过泛型检查    **************/
		//获取ArrayList的Class对象,反向的调用add()方法,添加数据
		Class listClass = list.getClass(); 
		//获取add()方法
		Method m = listClass.getMethod("add", Object.class);
		//调用add()方法
		m.invoke(list, 5);
		
		//遍历集合
		for(Object obj : list){
			System.out.println(obj);
		}
	}
}

反射获取jar包信息

在SpringBoot等框架中大量使用到jar包,通过如下方式获取jar包中类的信息.

package com.hanker.reflection;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ReflectionJarDemo {

	public static void main(String[] args) throws Exception {
		//1.创建文件
		File file = new File("lib/commons-fileupload-1.4.jar");
		//2.获取url地址
		URL url = file.toURI().toURL();
		//创建JarFile对象
		JarFile jarFile = new JarFile(file);
		Enumeration<JarEntry> entries = jarFile.entries();
		StringBuffer buffer = new StringBuffer();
		while(entries.hasMoreElements()) {
			JarEntry jarf = entries.nextElement();
			String classFullName = jarf.getName();
			//以class结尾的才是完成类名
			if(classFullName.endsWith("class")) {
				String className=classFullName.substring(0, classFullName.length()-6).replace("/", ".");
				System.out.println(className);
				Class<?> clazz = Class.forName(className);
				buffer.append("类名:"+className+"\n");
				Field[] fields = clazz.getDeclaredFields();
				for (Field field : fields) {
					buffer.append("属性名:"+field.getName()+",属性类型:" + field.getType()+"\n");
				}
				Method[] methods = clazz.getDeclaredMethods();
				for (Method method : methods) {
					buffer.append(method+"\n");
				}
			}
			buffer.append("===============================================");
		}
		jarFile.close();
		//写到文件
		BufferedWriter writer = new BufferedWriter(new FileWriter("src/info.txt"));
		writer.write(buffer.toString());
		writer.close();
	}
}

反射创建数组

package com.hanker.reflection;

import java.lang.reflect.Array;
import java.util.Arrays;

public class ArrayReflectionDemo {
	//反射背景: 运行中,不知
	public static void main(String[] args) {
		//int[]arr = new int[10];
		Object arr = Array.newInstance(int.class, 10);
		//arr[5] = 100
		Array.set(arr, 5, 100);//arr是数组名,5下标,100是值
		//int num = arr[5]
		Object object = Array.get(arr, 5);
		System.out.println("=="+Arrays.toString((int[])arr));
		System.out.println(object);
	}

}

设计模式-动态代理

见下一章

手写Spring框架

在这里插入图片描述

student=com.hanker.reflection.Student
teacher=com.hanker.reflection.Teacher
package com.hanker.reflection;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class HankerSpring {

	public static void main(String[] args) throws Exception {
		Object obj = getBean("student");
		System.out.println(obj);	
		Teacher t = (Teacher) getBean("teacher");
		t.setName("孔夫子");
		t.teach();
		
	}

	private static Object getBean(String k) throws Exception {
		Map<String,Object> factory = new HashMap<>();//对象工厂
		Map<String,String> map = new HashMap<>();//配置文件信息
		//创建文件对象
		File file = new File("src/hanker_config.txt");
		//读取文件
		BufferedReader reader = new BufferedReader(new  FileReader(file));
		while(reader.ready()) {
			String line = reader.readLine();//读取一行
			String[] data = line.split("=");//分割
			map.put(data[0], data[1]);//把分割后的放到map
		}
		reader.close();//关闭输入流
		//遍历Map集合
		Set<Entry<String, String>> entrySet = map.entrySet();
		for (Entry<String, String> entry : entrySet) {
			String key = entry.getKey();//获取key
			String value = entry.getValue();//获取value 包名+类名
			Class<?> clazz = Class.forName(value);//反射获取clazz对象
			Object o = clazz.newInstance();//调用无参构造方法创建对象
			factory.put(key,o);//放到对象工厂: key=student value是对象
		}
		return factory.get(k);//根据key获取对应的对象
	}

} 
发布了91 篇原创文章 · 获赞 43 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/kongfanyu/article/details/103809920