天天看点

【JAVA高级】反射

反射是什么?

RTTI是类型在编译器就知道了,但是如果类型在编译期不可知,那么就需要使用反射来获取运行时得类型信息。Class和java.lang.reflect类库为反射提供了支持。使用反射时,需要先检查这个对象,看它属于哪个类,然后加载这个类的class对象,那个类的class文件对于jvm来说必须是可获取的,可以在本地机器,也可以是从网络取得。

class对象

java class文件加载过程:jvm把描述类的数据从class文件加载(loading)到内存(java方法区)中,中间对数据进行校验(verification)、转换解析(resolution)和初始化(initialization),最终形成可以被jvm直接使用的Java类,这就是class文件的加载。

获取class对象的三种方式及区别

Class.forName()  

类.class  

对象.getClass()

类.class不会自动初始化该class对象,而Class.forName()会初始化该class对象

类.class不会抛出异常,而Class.forName()会抛出异常。

instanceof和isInstance区别  

类型转换前先做检查

A instanceof B  A.class.isInstance(对象实例); instanceof比较硬编码,需要知道确切的类,而isInstance只要传递实例对象即可,更加的灵活。

Instanceof有严格的限制,只能将其与命名类型进行比较,而不能与Class对象比较。

实战

通过java反射仿造spring加载bean的过程

项目的目录结构如下:

【JAVA高级】反射

首先pom文件导入依赖的jar包,junit和slf4j

<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

	<dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
        <!-- <scope>test</scope> -->
    </dependency>
           

在resources文件夹下,新建两个properties文件,bean.properties和log4j.properties  bean.properties用来配置我们需要加载的类,内容如下:

spring.beanname=com.study.Battle.reflect.Student
           

log4j.properties文件是配置日志输出的地址,本例输出到控制台。内容如下:

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
           

然后新建两个实体类,people和student,student继承people

public interface People {
	void init();

	String getName();
}
           

Student.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Student implements People {

	public static Logger LOGGER = LoggerFactory.getLogger(Student.class);

	private String name;

	public String getName() {
		return name;
	}

	public void init() {
		// TODO Auto-generated method stub
		LOGGER.info("Student init......");
		name = "init";
	}

}
           

新建一个PropertyUtil.java工具类,用来读取properties文件,来获取bean的name

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PropertyUtil {

	private static Logger LOGGER = LoggerFactory.getLogger(PropertyUtil.class);

	public static List<String> getBeanName(String path) {
		List<String> list = new ArrayList<String>();
		Properties properties = new Properties();
		// 使用ClassLoader加载properties配置文件生成对应的输入流
		InputStream in = PropertyUtil.class.getClassLoader().getResourceAsStream(path);
		// 使用properties对象加载输入流
		try {
			properties.load(in);
			// 获取key对应的value值
			list.add(properties.getProperty("spring.beanname"));
		} catch (IOException e) {
			LOGGER.info("文件路径错误,找不到文件");
		}
		return list;
	}

}
           

新建一个工厂类,PropertyBeanFactory.java来实现从properties文件读取并加载bean

public interface BeanFactory {
	Object getBean(String beanName);
}
// 继承BeanFactory
public class PropertyBeanFactory implements BeanFactory {

	private static Logger LOGGER = LoggerFactory.getLogger(PropertyBeanFactory.class);
	// bean的容器
	public static Map<String, Object> beans = new HashMap<String, Object>();

	// 从properties文件中加载bean
	public static void loadBean() {
		List<String> beanNames = PropertyUtil.getBeanName("bean.properties");
		String name = null;
		try {
			for (String beanName : beanNames) {
				if (beans.get(beanName) != null)
					continue;
				name = beanName;
				Class<?> beanClass = Class.forName(beanName);
				Object object = beanClass.newInstance();
				if (People.class.isInstance(object)) {
					((People) object).init();
					;
				}
				beans.put(getSimpleName(beanName), object);
			}
		} catch (ClassNotFoundException e) {
			LOGGER.info("找不到类" + name);
		} catch (Exception e) {

		}
	}

	public static String getSimpleName(String beanName) {
		if (beanName == null) {
			return null;
		} else {
			int index = beanName.lastIndexOf(".");
			if (index < beanName.length()) {
				return beanName.substring(index + 1);
			} else {
				return null;
			}

		}
	}

	static {
		loadBean();
	}

	public Object getBean(String beanName) {
		// TODO Auto-generated method stub
		return beans.get(beanName);
	}

}
           

一切准备就绪,可以获取从容器中获取bean了。

public class ReflectDemo {

	public static void main(String[] args) {
		BeanFactory beanFactory = new PropertyBeanFactory();
		People people = (People) beanFactory.getBean("Student");
		System.out.println(people.getName());
	}

}
           

输出结果如下:

 INFO [main] - Student init......

init