Home

韧桂

思考,总结

Java 反射机制

Java 反射机制 课程内容 1.理解Class类并实例化Class类对象

  1. 运行时创建类对象并获取类的完整结构

3.通过反射调用类的指定方法、指定属性

4.动态代理

  • 反射相关的主要API:
    • java.lang.Class:代表一个类
    • java.lang.reflect.Method:代表类的方法
    • java.lang.reflect.Field:代表类的成员变量
    • java.lang.reflect.Constructor:代表类的构造方法
    • 。。。

了解:ClassLoader

//1.获取一个系统类加载器
ClassLoader classloader = ClassLoader.getSystemClassLoader();
System.out.println(classloader);
//2.获取系统类加载器的父类加载器,即扩展类加载器
classloader = classloader.getParent();
System.out.println(classloader);
//3.获取扩展类加载器的父类加载器,即引导类加载器
classloader = classloader.getParent();
System.out.println(classloader);
//4.测试当前类由哪个类加载器进行加载
classloader = 
Class.forName("exer2.ClassloaderDemo").getClassLoader();
System.out.println(classloader);

//5.测试JDK提供的Object类由哪个类加载器加载
classloader = 
Class.forName("java.lang.Object").getClassLoader();
System.out.println(classloader);
//*6.关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路径下的指定文件的输入流
InputStream in = null;
in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties");
System.out.println(in);

package nineteen;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

import org.junit.Test;

public class TestReflection {

	//四、关于类的加载器:ClassLoader
	@Test
	public void test5() throws Exception{
		ClassLoader loader1 = ClassLoader.getSystemClassLoader();
		System.out.println(loader1);
		
		ClassLoader loader2 = loader1.getParent();
		System.out.println(loader2);
		
		ClassLoader loader3 = loader2.getParent();
		System.out.println(loader3);
		
		Class clazz1 = Person.class;
		ClassLoader loader4 = clazz1.getClassLoader();
		System.out.println(loader4);
		
		String className = "java.lang.String";
		Class clazz2 = Class.forName(className);
		ClassLoader loader5 = clazz2.getClassLoader();
		System.out.println(loader5);
		
		//掌握如下
		//法一:文件在指定包下
		System.out.println();
		ClassLoader loader = this.getClass().getClassLoader();
		InputStream is = loader.getResourceAsStream("nineteen\\jdbc.properties");
		//法二:文件在工程目录下
//		FileInputStream is = new FileInputStream(new File("jdbc1.properties"));
		
		Properties pros = new Properties();
		pros.load(is);
		String name = pros.getProperty("user");
		System.out.println(name);
		
		String password = pros.getProperty("password");
		System.out.println(password);
		
	}


	//三、如何获取Class的实例(4种)
	@Test
	public void test4() throws ClassNotFoundException{
		//1.调用运行时类本身的.class属性
        //前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
		Class clazz1 = Person.class;
		System.out.println(clazz1.getName());//nineteen.Person
		
		Class clazz2 = String.class;
		System.out.println(clazz2.getName());//java.lang.String
		
		//2.通过运行时类的对象获取
        //前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
		Person p = new Person();
		Class clazz3 = p.getClass();
		System.out.println(clazz3.getName());//nineteen.Person
		
		//3.通过Class的静态方法获取.通过此方式,体会一下,反射的动态性。
        //前提:已知一个类的全类名,且该类在类路径下,可通过
		// Class类的静态方法forName()获取,可能抛出ClassNotFoundException
		String className = "nineteen.Person";
		Class clazz4 = Class.forName(className);
//		clazz4.newInstance();//具有通用性,创建一个实例后,可操作许多事
		System.out.println(clazz4.getName());//nineteen.Person
		
		//4.(了解)通过类的加载器
		ClassLoader classLoader = this.getClass().getClassLoader();
		Class clazz5 = classLoader.loadClass(className);
		System.out.println(clazz5.getName());//nineteen.TestReflection
		
		System.out.println(clazz1 == clazz3);//true 指向同一个地址,即都为同一个
		System.out.println(clazz1 == clazz4);//true
		System.out.println(clazz1 == clazz5);//true
	}

	//二、理解反射的源头之 Class类
	/**
	 * java.lang.Class:是反射的源头。
	 * 我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的)
	 * 此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在在缓存区。那么这个运行时类本身就是一个Class的实例!
	 * 1.每一个运行时类只加载一次!
	 * 2.有了Class的实例以后,我们才可以进行如下的操作:
	 *     1)*创建对应的运行时类的对象
	 *     2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解、...)
	 *     3)*调用对应的运行时类的指定的结构(属性、方法、构造器)
	 *     4)反射的应用:动态代理
	 */
	@Test
	public void test3(){
		Person p = new Person();//实例化对象
		Class clazz = p.getClass();//通过运行时类的对象,调用其getClass(),返回其运行时类。
		System.out.println(clazz);//得到完整的“包类”名称

	}
	
	//一、反射的应用实例
	//有了反射,可以通过反射创建一个类的对象,并调用其中的结构
	@Test
	public void test2() throws Exception{
		Class clazz = Person.class;
		
//		Class clazz1 = String.class;
		
		//1.创建clazz对应的运行时类Person类的对象
		Person p = (Person)clazz.newInstance();
		System.out.println(p);
		//2.通过反射调用运行时类的指定的属性
		//2.1
		Field f1 = clazz.getField("name");
		f1.set(p,"LiuDeHua");
		System.out.println(p);
		//2.2
		Field f2 = clazz.getDeclaredField("age");
		f2.setAccessible(true);
		f2.set(p, 20);
		System.out.println(p);
		
		//3.通过反射调用运行时类的指定的方法
		Method m1 = clazz.getMethod("show");
		m1.invoke(p);
		
		Method m2 = clazz.getMethod("display",String.class);
		m2.invoke(p,"CHN");
		
	}
	
	//在有反射以前,如何创建一个类的对象,并调用其中的方法、属性
	@Test
	public void test1(){
		Person p = new Person();
//		Person p1 = new Person();
		p.setAge(10);
		p.setName("TangWei");
		System.out.println(p);
		p.show();
//		p.display("HK");
	}
}
package nineteen;

public class Person{
	public String name;
	private int age;
	
	//创建类时,尽量保留一个空参的构造器。
	public Person() {
		super();
//		System.out.println("今天天气很闷热");
	}
	public Person(String name) {
		super();
		this.name = name;
	}
	private Person(String name, int age) {
		super();
		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;
	}
	
	public void show(){
		System.out.println("我是一个人!");
	}
	
	public void display(String nation) {
		System.out.println("我的国籍是:" + nation);
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	public static void info(){
		System.out.println("中国人!");
	}
}

韧桂 2020-01-11