黑马程序员 反射

------- android培训java培训、期待与您交流! ----------

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



1.Class类

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 


想要获取到一个类的字段,方法,构造函数等,首先要获取其字节码文件。
    获取字节码的三种方式:
  •     1、当获取一个对象时,想要获取其类的字节码,使用getClass()方法。
  •     Class cl = p.getClass() //获取对象p的字节码文件
  •     2、当获取一个指定类的字节码时,使用该类的class方法
  •     Class cl = Student.class //获取Student类的字节码文件
  •     3、获取一个类的的字节码,也可以通过Class类的forName()方法加上类的全限定名获取
  •     Class cl = Class.forName("java.util.Arrays"); //获取Arrays类的字节码文件


九个预定义Class对象:8个基本数据类型,和void。
在Class类中有一些常用方法:


  • public static Class<?> forName(String className):通过类的名字获得该类的Class对象,这个方法是静态方法。在Class类中没有构造方法,要想获得Class对象只能通过静态方法返回。
  • Class getClass() :返回Class对象即字节码对象
  • public Field getField(String name):返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。name 参数是一个 String,用于指定所需字段的简称。
  • public Method getMethod(String name,Class<?>... parameterTypes):返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
  • public String getName():以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。 public boolean isArray():判定此 Class 对象是否表示一个数组类。
  • public boolean isPrimitive():判定指定的 Class 对象是否表示一个基本类型。
  • public boolean isInterface():判定指定的 Class 对象是否表示一个接口类型。 
  • public T newInstance():创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。


可以看到,反射就是将Java类中的各种成分映射成相应的java类。例如,类中的组成成分:成员变量、构造方法、方法、包信息等分别对应Field、Constructor、Method、Package等。


2.构造函数的反射

当一个类不存在空参数的构造函数时,就不能通过newInstance方法获得其对象,所以必须先要通过反射获得其构造函数。
构造函数可能有多种重载方式,我们通过不同的参数列表来确定反射的是哪个构造函数。或者通过getConstructors方法得到其全部的构造函数。


Constructor cons =  String.class.getConstructor(StringBuffer.class);
String str2 = (String)cons.newInstance(new StringBuffer("abc"));



3.成员变量的反射

使用getField方法获得成员变量的字段。
Field fieldY = XXX.getClass().getField("Y");
获得了Field对象后可以再使用Field对象给指定对象上的成员变量设定指定的值,或者得到一个对象上这个字段的值
  • public void set(Object obj,Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
  • public Object get(Object obj):返回指定对象上此 Field 表示的字段的值。如果该值是一个基本类型值,则自动将其包装在一个对象中。 
  • 如果要访问私有的字段,要先设置其权限
  • public void setAccessible(boolean flag):将此对象的 accessible 标志设置为指示的布尔值。值为true时表示可以访问。
 
public class ReflactTest2 {


	public static void main(String[] args)throws Exception {
		Class c =Class.forName("Person");
		
		//调用默认的构造函数
		Person p = (Person)c.newInstance();
		
		//获得Field对象,是属于字节码的。对于private的属性要使用getDeclaredFile才可以看见。
		Field age = c.getDeclaredField("age");
		//对于private的变量,要通过下面的方法设置权限
		age.setAccessible(true);
		//调用Field对象的set方法设置具体person对象的age
		age.set(p, 10);
		
		Field name = c.getDeclaredField("name");
		name.setAccessible(true);
		name.set(p, "zhangsan");


		//不是private的属性使用getField就可以拿到。
		Field address = c.getField("address");
		address.set(p, "beijing");
		
		System.out.println(p.toString());
	}
}
class Person{
	private int age ;
	private String name ;
	public String address;
	
	public Person(){
		System.out.println("Person run.."+this.name+":"+this.age);
	}
	
	public void show(){
		System.out.println("Pserson show ...");
	}
	
	public void show(String p){
		System.out.println("Pserson show ..."+"String:"+p);
	}
	
	private void show(int i){
		System.out.println("private method show ..."+"String:"+i);
	}
}



4.方法的反射

通过Class类中的getMethod方法来获得指定的Method对象
  • public Method getMethod(String name,Class<?>... parameterTypes):获得一个指定的Method对象,该方法的名字以传入的值确认,parameterTypes代表该方法的参数列表 ,无参数可以写null。
  • public Method[] getMethods():返回一个包含某些 Method 对象的数组
  • public Method getDeclaredMethod(String name,Class<?>... parameterTypes):获得本类私有方法


Method类中常用的方法有:
  • public Object invoke(Object obj,Object... args):对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。obj表示指定的对象,args表示参数列表当这个方法为静态方法时作用对象可以填null,无参方法时参数可以填null。


public static void getPersonMethod() throws Exception{
	//如果想要获取方法,必须先要有对象。
	Class clazz=Class.forName("cn.itheima.Person");
	Person p=(Person)clazz.newInstance();
		
	
	Method[] mes=clazz.getMethods();//只获取所有方法
	
	for(Method me:mes){
		System.out.println(me);
	}
		
	//获取单个方法
	Method me=clazz.getMethod("toString", null);
	Object returnVaule=me.invoke(p, null);
	System.out.println(returnVaule);	
}




5.反射在框架中的作用



java框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现。
框架在开发时,无法知道后来开发要调用的类名,所以无法直接通过new某个对象,而是通过反射来创建对象。


public class ReflactTest {
	public static void main(String[] args)throws Exception {
		//加载配置文件
		Properties proper = new Properties();
		InputStream is = new FileInputStream("G:\\eclipse\\Reflect\\src\\init.property");
		proper.load(is);
		//拿到配置文件中,对应的类名
		String soundcard = proper.getProperty("soundCard");
		String netcard = proper.getProperty("netCard") ;
		//根据上面的类名,通过反射获得类的对象
		pci p1 = (pci)Class.forName(soundcard).newInstance();
		pci p2 = (pci)Class.forName(netcard).newInstance() ;
		//调用对象的方法
		p1.run();
		p2.run();
	}
}


class SoundCart implements pci{
	public void start(){
		System.out.println("Sound is start");
	}
	public void close(){
		System.out.println("Sound is close");
	}
	public void run(){
		start();
		close();
	}
}


class netCard implements pci{


	public void start() {
		System.out.println("netCard is start");	
	}
	@Override
	public void close() {
		System.out.println("netCard is start");	
	}
	public void run(){
		start();
		close();
	}
}




6.一个反射应用实例



可以看到,泛型的出现让程序变得更安全,但是反射可以绕过泛型,让程序又出现了安全隐患。。


/**
 *
 * 3、 ArrayList<Integer> list = new ArrayList<Integer>(); 
 *    在这个泛型为Integer的ArrayList中存放一个String类型的对象。
 */


import java.lang.reflect.*;
import java.util.*;
public class pritice03 {
		public static void main(String[] args)
		{
			ArrayList<Integer> list = new ArrayList<Integer>();
			//@SuppressWarnings("rawtypes")
			Class<?> listcls = list.getClass();
			
			try {
				Method me = listcls.getMethod("add", Object.class);//获得ArrayList中的add方法
				me.invoke(list,"哥就是要存字符串");
				//调用该方法存入字符串到泛型为Integer的ArrayList中
				System.out.println(list);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}	
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值