黑马程序员——Java反射机制

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

  Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制,用一句话总结就是:反射就是把java类中的各种成分映射成相应的java类。 

反射机制的基本应用场景:

  一个程序的应用程序比如Tomcat,为了提高其扩展性,会对外暴露一个接口,在外部定义一个类实现这个接口,但是在应用程序内部无法new对象,所以应用程序会提供一个配置文件,使用接口者可以将写好的并且实现接口的类名,写进配置文件,而应用程序利用反射机制会获取到指定名称的类的字节码文件并加载其中的内容进行调用,这就是反射机制的基本应用。

总结:反射技术提高了程序的扩展性,且应用简单,用户和程序之间的桥梁变为了配置文件

  现实中的事物,不断向上抽取其共性内容,可以得到类来描述事物,反射机制中,也是将字节码向上抽取,用Class来描述字节码文件,那么就可以产生对象,就可以提供方法,获取字节码文件的成员,如:名称、字段、构造函数、一般函数等所有内容,反射就是依靠该类来完成的。 想要对一个类文件进行解剖,只要获取该类的字节码文件即可。

定义演示类

package com.itheima;

public class ReflectPoint {
	public int x;
	private int y;
	public ReflectPoint(int x ,int y){
		this.x=x;
		this.y=y;
	}	
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ReflectPoint other = (ReflectPoint) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}
}	
获取Class对象的三种方式:

1.Object类中的getClass方法用这种方式,必须明确具体的类,并创建对象

ReflectPoint rp=new ReflectPoint();
Class clazz=rp.getClass();

2.任何数据类型都具备一个静态属性.class来获取其对应Class对象

Class clazz=ReflectPoint.class;
相对简单,但是还是 需要明确类中的静态 成员,扩展性不高

3.只要通过给定的类的字符串名称就可以获取该类,可以用Class类中的forName方法来完成,这种方式只要有名称即可(重点掌握)

forName(String classname)
返回与带有给定字符串名的类或接口相关联的Class对象。

forName(String name,boolean initialize,ClassLoader loader)
使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的Class对象。

		String classname = "com.itheima.ReflectPoint";//明确是哪个包中的类
		Class<?> cls = Class.forName(classname);

获取Class中的构造函数

ReflectPoint rp=new ReflectPoint();以前new对象,先根据被new的类的名称,寻找该类的字节码文件,并加载进内存,并创建该字节码文件对象,并接着创建该字节码文件对应的对象

newInstance()

创建此Class对象所表示的类的一个新实例。如同用一个带有一个空参数列表的new表达式实例化该类。如果该类尚未初始化,则初始化这个类。实际上就是ReflectPoint中的空参的构造函数。

类中有空参构造函数

		String classname = "ReflectPoint";
		//找寻该名称类文件,并加载进内存,产生Class对象
		Class<?> cls = Class.forName(classname);		
		Object obj = cls.newInstance();

类中无空参构造函数

果直接调用上述方法,会抛出初始化异常InstantiationException

如果有空参构造函数,但是私有的private,会抛出无效访问异常IllegalAccessException

所以当获取指定名称类中所体现的对象时,而对象初始化不使用空参数构造时,应该先获取其构造函数:

getConstructor(Class<?>...parameterTypes)
返回一个Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。

getDeclaredConstructors()
返回Constructor对象的一个数组,这些对象反映此Class对象表示的类声明的所有构造方法。

Constructor对象中有方法new对象:

newInstance(Object...initargs)
使用此Constructor对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

		String classname = "ReflectPoint";
		Class<?> cls = Class.forName(classname);		
		//参数数组,一个int基本数据类型对应的字节码是int.class
		Constructor<?> constructor = cls.getConstructor(int.class,int.class);
		//获取到了指定构造函数的对象	
		Object obj = constructor.newInstance(1,1);
只不过在配置文件的时候需要写明类名和构造函数的参数信息

PS:一般被反射的类一般都是带有空参,因为获取实例方便

获取Class中的字段

getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

getFields()

返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

getDeclaredFiels()
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段

public static void reflect_Demo3() throws Exception {
	
	String classname = "ReflectPoint";
	Class<?> cls = Class.forName(classname);
	Constructor<?> constructor = cls.getConstructor(int.class,int.class);
	Object obj = constructor.newInstance(1,1);//有参构造		
	//Field field = cls.getField("x");///获取本类及其父类所有公共方法  
	Field field = cls.getDeclaredField("x");//能获取本类所有字段,包括私有
	int x = (int)field.get(obj);
	System.out.println(x);
	//获取字段的值.........	
	Field field2 = cls.getDeclaredField("y"); 
	//System.out.println(field2.get(obj));//访问失败因为其是私有的
	//对私有字段的访问取消权限检查,-> 暴力访问
	field2.setAccessible(true);//Field的父类方法,修改其访问权限
	field2.set(obj,2);//设置值
	int y = (int)field2.get(obj);
	System.out.println(y);//
}
API:AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。

PS:不建议用暴力访问的方式访问数据,会破坏原有程序的封装性

获取指定Class中的方法

获取一个无参方法

public static void reflect_Demo() throws Exception {
		
		String classname = "ReflectPoint";
		Class<?> cls = Class.forName(classname);
		
        //Method[] methods = cls.getMethods();//获取本类及其父类所有公共方法
		//methods = cls.getDeclaredMethods();//只获取本类中,所有方法,包括私有
		//for(Method M : methods){
		//System.out.println(M);
		//}
		//拿一个无参方法
		Method method = cls.getMethod("getX", null);//注意与拿构造函数不同,方法名,方法参数列表
		//Object obj = cls.newInstance();//无参构造
		//method.invoke(obj, null);
		Constructor<?> constructor = cls.getConstructor(int.class,int.class);
		Object obj = constructor.newInstance(1,1);//有参构造		
		method.invoke(obj, null);//对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
	}
获取有参方法

public static void reflect_Demo2() throws Exception {
	
	String classname = "ReflectPoint";
	Class<?> cls = Class.forName(classname);
	
	Method method = cls.getMethod("setX", int.class);//方法参数列表
	Constructor<?> constructor = cls.getConstructor(int.class,int.class);
	Object obj = constructor.newInstance(1,1);//有参构造		
	method.invoke(obj,2);//对获取到的方法进行调用
}
反射练习:

package com.itheima;

import java.io.*;
import java.lang.reflect.*;
import java.util.*;
/*从properties配置文件中读取classname属性,是ArraysList还是Hashcode
 * 从而根据不同的配置文件创建不同的集合并判断集合长度
*/

public class ReflectTest {
	public static void main(String[] args)throws Exception{
		InputStream ips =new FileInputStream("cofig.properties");
		Properties props=new Properties();
		props.load(ips);//从配置文件中读取classname的值
		ips.close();
		String classname=props.getProperty("classname");
		Collection collection =(Collection)Class.forName(classname).newInstance();
		ReflectPoint pt1=new ReflectPoint(3,3);//根据配置文件创建不同的集合对象
		ReflectPoint pt2=new ReflectPoint(3,5);
		ReflectPoint pt3=new ReflectPoint(3,3);
		collection.add(pt1);
		collection.add(pt2);
		collection.add(pt3);
		System.out.println(collection.size());//判断集合长度
	}

properties:

classname=java.util.ArrayList


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值