CoreJava读书笔记--反射

反射

什么是反射?

Java反射机制是在运行状态中,对任意一个类(class文件),都能够知道这个类的属性和方法,对于任意一个对象,都能够调用它的方法和属性。

这种动态获取的信息以及动态调用对象的方法的功能称为Java反射机制。可以理解为对类的剖析。

(一)反射的功能

①在运行时分析类的能力

②在运行时查看对象

③实现通用的数组操作代码

④利用method对象

反射是一种功能强大且复杂的机制,使用它的主要人员是构造工具者,而不是应用程序,但是它也可以用来扩展应用程序。

(二)Class类

在程序运行时,Java始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。

我们知道类就是对某一类型数据的描述,例如学生类,可以描述姓名、年龄,所以我们可以对这些不同的学生创建一个student类,那么我们对每一个类也可以进行抽象,对每一个类的描述就是Class类。如下图:

 对于反射用于扩展应用程序,当我们一个应用程序已经在运行时,我们想要对它进行扩展就变得不那么容易了,可能需要修改源代码,但是这是非常危险的事情。接口也是扩展应用程序一个重要的工具,但是我们实现接口还是需要创建对象,也需要修改源代码,那么如何解决这个问题呢?这时我们可以引入配置文件,告诉我们的程序在这个时候要去读取哪个类的字节码文件,通过Class类就可以获取这个类有哪些属性和方法。

假设电脑运行是一个应用程序,运行都是通过主板,通过主板上的接口来开关其他硬件,比如网卡、声卡。我们试着用代码来展现这个实例:

package reflect;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Properties;

/**
 * Java反射机制是在运行状态中,对任意一个类(class文件),都能够知道这个类的所有属性和方法
 * 对于任意一个对象,都能够调用它的任意一个方法和属性
 * 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
 * 
 * 动态获取类中信息,就是java反射。
 * 可以理解为对类的解剖。
 *
 */


public class ReflectDemo {
	public static void main(String[] args) throws Exception {
		MainBoard mb = new MainBoard();
		mb.run();
		//假设我们需要添加一个声卡,需要创建声卡对象,然后调用声卡类的方法
//		PCI pci = new SoundCard();
//		pci.open();
//		pci.close();
		//在这种情况下,如果还需要添加网卡,鼠标等硬件,我们还是需要修改源码才能实现,但是现在可以利用class类来实现
		//能不能不修改代码就可以完成添加硬件的动作呢?不用new来完成,而只是获取其class文件,在内部实现创建对象的动作。
		
		File configFile = new File("pci.properties");
		Properties prop = new Properties();
		
		FileInputStream fis = new FileInputStream(configFile);
		prop.load(fis);
		//假设有很多个硬件,我们读取配置文件获取多个类,利用多态来创建对象并调用方法。
		for(int i=1;i<=prop.size();i++) {
			String pciName = prop.getProperty("pci"+i);//通过键值对获取类名
			Class clazz = Class.forName(pciName);//使用forName方法获得类名对应的对象
			PCI p = (PCI) clazz.newInstance();
			p.open();
			p.close();
		}
		fis.close();//关闭资源
	}
}
package reflect;
//主板
public class MainBoard {
	public void run() {
		System.out.println("main board run...");
	}
}



package reflect;

/**
 * 这个类表示主板上的接口,用于提供硬件开、关的方法
 *
 */
public interface PCI {
	public void open();
	public void close();
}




package reflect;
//声卡
public class SoundCard implements PCI{
	@Override
	public void open() {
		System.out.println("SoundCard open");
	}

	@Override
	public void close() {
		System.out.println("SoundCard close");
	}
	
}



package reflect;
//网卡
public class NetCard implements PCI{

	@Override
	public void open() {
		System.out.println("NetCard open");
	}

	@Override
	public void close() {
		System.out.println("NetCard close");
	}

}



//pci.priperties文件

pci1=reflect.SoundCard
pci2=reflect.NetCard

 获取Class对象的三种方式

①通过Object类的getClass方法

②通过类的静态属性.class

③通过Class类的forName方法

package reflect;

/**
 * 要想对字节码文件进行剖析,必须要要字节码文件对象
 * 如何获取字节码文件对象呢?有三种方式
 *
 */
public class ReflectDemo2 {

	public static void main(String[] args) throws ClassNotFoundException{
		getClassObject_1();
		getClassObject_2();
		getClassObject_3();
	}
	/*
	 * 方式3:
	 * 只要通过给定的字符串名称就可以获取该类。
	 * 可以用Class类中的方法完成。就是Class类的forName的方法
	 */
	public static void getClassObject_3() throws ClassNotFoundException {
		String className = "reflect.Person";
		Class clazz = Class.forName(className);
		
		System.out.println(clazz.toString());
	}
	
	/*
	 * 方式2:
	 * 任何数据类型都具备一个静态的属性.class来获取其对应的Class对象
	 */
	public static void getClassObject_2() {
		Class clazz = Person.class;
		Class clazz1 = Person.class;
		System.out.println(clazz==clazz1);
	}
	
	/*
	 * 方式1:
	 * Object类中的getClass方法
	 * 想要用这种方式,必须要明确具体的类,并创建对象。但是麻烦
	 */
	public static void getClassObject_1() {
		Person p = new Person();
		Class clazz = p.getClass();
		
		Person p1 = new Person();
		Class clazz1 = p.getClass();
		
		System.out.println(p==p1);
	}
}
package reflect;

public class Person {
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
		System.out.println("person param run.."+this.name +"..."+this.age);
	}
	public Person() {
		super();
		System.out.println("person run");
	}
	
	public void show() {
		System.out.println(name+"...show run..."+age);
	}
	
	public void method() {
		System.out.println("method run");
	}
	
	public void paramMethod(String str,int num) {
		System.out.println("paramMethod run...."+str+":"+num);
	}
	
	public static void staticMethod() {
		System.out.println("static method run...");
	}
}

获取Class中的构造函数

当我们使用空参数的构造函数时,我们可以使用下面的方法来创建该类对象:

String name = "reflect.Person";

Class clazz = Class.forName(name);

Object obj = clazz.newInstance();

但是,如果当我们需要指定构造函数(非空参数)时,我们就需要通过获取某个类的构造函数。如何获取某个类的构造函数?看看下面的例子:

package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectDemo3 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		createNewObject_1();
		createNewObject_2();
	}
	//使用默认构造函数创建某个类的实例
	public static void createNewObject_1() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		String name = "reflect.Person";
		Class clazz = Class.forName(name);
		Object obj = clazz.newInstance();
	}
	//通过获取指定的构造函数创建某个类的实例
	public static void createNewObject_2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		String name = "reflect.Person";
		Class clazz = Class.forName(name);
		Constructor cons = clazz.getConstructor(String.class,int.class);
		Object obj = cons.newInstance("小强",24);
	}
}

获取Class中的字段

通过反射获取某个类的实例域,有个类叫Field类,这个类里有方法可以操作实例域,看看下面的例子:

package reflect;

import java.lang.reflect.Field;

public class ReflectDemo4 {
	public static void main(String[] args) throws Exception{
		getFieldDemo();
	}
	
	/*
	 * 获取字节码文件中的字段
	 */
	public static void getFieldDemo() throws Exception{
		Class clazz = Class.forName("reflect.Person");
//		Field field = clazz.getField("age");//getField方法只能访问公有的属性,而不能访问私有的
		Field field = clazz.getDeclaredField("age");//只获取本类的字段,可以访问私有的。
		
		field.setAccessible(true);//对私有字段的访问取消权限检查,暴力访问
		//创建字节码文件对应类的实例
		Object obj = clazz.newInstance();
		field.set(obj, 89);
		Object o = field.get(obj);
		System.out.println(o);
		
	}
}

 

获取Class中的方法

同上面获取字段一样,我们也可以通过反射来获取方法或指定的方法:

package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectDemo5 {
	/**
	 * 
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		getMethods_1();
		getMethods_2();
		getMethods_3();
	}
	
	/*
	 * 获取指定Class中的所有公共函数
	 */
	public static void getMethods_1() throws Exception{
		Class clazz = Class.forName("reflect.Person");
		
//		Method[] methods = clazz.getMethods();//获取的都是公有的方法
		
		Method[] methods = clazz.getDeclaredMethods();//获取的只是本类中的方法,包含私有
		for(Method m :methods) {
			System.out.println(m);
		}
		
	}
	/*
	 * 获取指定方法,是带参数列表的
	 */
	public static void getMethods_3() throws Exception{
		Class clazz = Class.forName("reflect.Person");
		
		Method method =clazz.getMethod("paramMethod", String.class,int.class);
		
		Object obj = clazz.newInstance();
		
		method.invoke(obj, "小强",77);
		
	}
	
	/*
	 * 获取指定Class中的指定方法(空参数的)
	 */
	public static void getMethods_2() throws Exception{
		Class clazz = Class.forName("reflect.Person");
		
		Method method = clazz.getMethod("show", null);
		
		Constructor cons = clazz.getConstructor(String.class,int.class);
		Object obj = cons.newInstance("小王",33);
		method.invoke(obj, null);
		
		
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值