黑马程序员_Java反射技术

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

   1 概念:反射就是把Java类中的各种成分映射成相应的java类。
    例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,
         包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。
         表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,
         这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
   1.2 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。
   1.3 Class类,反射的基石
   1.3.1 Class类代表Java类,它的各个实例对象又分别对应什么呢?
    对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
    一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,
    所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,
    这个类型是什么呢?
      1.3.2 Class类没有显示的构造函数,字节码文件就是Class类的一个对象。
      1.3.3 得到各个字节码对应的实例对象(Class类型)的三种形式。
    1.3.3.1 类名.class         例如: System.class
    1.3.3.2 对象.getClass()    例如:   new Date().getClass()
    1.3.3.3 Class.forName("类的全名")   例如:Class.forName("java.util.Date")
      1.3.4 Class类包含九个原始Class实例对象,可通过   Class.isprimitive()查看。
    Int.Class == Integer.TYPE;
      1.3.5 在源程序中出现的类型,都有各自的Class实例对象。如int[].


   2 Constructor类:代表某个类中的构造方法。
      2.1 得到某个类所有的构造方法:    
    Constructor[] con = Class.forName("java.lang.String").getConstructor();
      2.2 通过反射创建实例对象。Class.newInstance()方法。例:
    String str = (String)Class.forName("java.lang.String").newInstance();
    该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象,方法内部的具体
    代码用到了缓存机制来保存默认构造方法的实例。



反射构造方法:

package cn.hmm;

//反射构造方法
import java.lang.reflect.*;
import java.util.*;
public class reflectTest {

	public static void main(String[] args) throws Exception{
		// TODO 自动生成的方法存根
		//test1();
		//test2();
		test3();
	}
	
	public static void sop(Object obj){
		System.out.println(obj);
	}
	
	public static void test1() throws Exception{
		Class clazz = Class.forName("cn.hmm.Person");
		Constructor c = clazz.getConstructor(String.class,int.class);
		Person p = (Person)c.newInstance("liming",19);
		sop(p.getName()+"的年龄是"+p.getAge());
	}
	
	public static void test2() throws Exception{
		Class clazz = Class.forName("cn.hmm.Person");
		Constructor c = clazz.getDeclaredConstructor(List.class);
		c.setAccessible(true);        		//暴力反射
		Person p = (Person)c.newInstance(new ArrayList());
		sop(p);
	}
	public static void test3() throws Exception{
		Class clazz = Class.forName("cn.hmm.Person");
		Person p = (Person)clazz.newInstance();
		sop(p);
	}

}


3 Method类:此类代表某个类中的一个成员方法。
      3.1 得到String类的charAt()方法的对象。getMethod()方法。
    例: Method charAt = String.class.getMethod("charAt",int.class);  
      3.2 通过反射调用方法。   invoke(对象,1)
    例: char ch = charAt.invoke(str,1);  str表示对象
      3.3 如果传递给invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法。
    因为静态方法可以不用对象调用,可以直接类型调用,所以传递对象时可以是null。
      3.4 jdk1.4和jdk1.5的invoke方法的区别:
    Jdk1.5:public Object invoke(Object obj,Object... args)
    Jdk1.4:public Object invoke(Object obj,Object[] args)
    即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,
    数组中的每个元素分别对应被调用方法中的一个参数,

    所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。


反射类里面的一些方法:

package cn.hmm;

import java.io.*;
import java.lang.reflect.Method;

//反射类的方法
public class refelctTest2 {

	
	public static void main(String[] args) throws Exception{
		// TODO 自动生成的方法存根
		//test1();
		//test2();
//		test3();
		//test4();
		//test5();
		test6();
	}
	//反射不带参数的方法
	 public static void test1() throws Exception{
			Class clazz = Class.forName("cn.hmm.Person");
			Person p = (Person)clazz.newInstance();
			Method m1 = clazz.getMethod("aa1", null);
			m1.invoke(p, null);
		}
	 //反射带字符串和int类型的参数的方法
	 public static void test2() throws Exception{
		 Class clazz = Class.forName("cn.hmm.Person");
		 Person p = (Person)clazz.newInstance();
		 Method m1 = clazz.getMethod("aa1", String.class,int.class);
		 m1.invoke(p, "hmm",24);
	 }
	 //反射带字符串和int数组参数的方法
	 public static void test3() throws Exception{
		 Class clazz = Class.forName("cn.hmm.Person");
		 Person p = (Person)clazz.newInstance();
		 Method m1 = clazz.getMethod("aa1", String.class,int[].class);
		 Class cs[] = (Class[])m1.invoke(p, "hmm",new int[]{1,2,3});
		 System.out.println(cs[0]);
	 }
	 //反射带InputStream流参数的方法
	 public static void test4() throws Exception{
		 Class clazz = Class.forName("cn.hmm.Person");
		 Person p = (Person)clazz.newInstance();
		 Method m1 = clazz.getDeclaredMethod("aa1", InputStream.class);
		 m1.setAccessible(true);
		 m1.invoke(p, new FileInputStream("c:\\1.exe"));
	 }
	 //反射带int参数的静态方法
	 public static void test5() throws Exception{
		 Class clazz = Class.forName("cn.hmm.Person");
		 Person p = (Person)clazz.newInstance();
		 Method m1 = clazz.getMethod("aa1", int.class);
		 m1.invoke(null, 23);
	 }
	 
	 //反射main方法,要强转成Object
	 public static void test6() throws Exception{
		 Class clazz = Class.forName("cn.hmm.Person");
		 Method m1 = clazz.getMethod("main", String[].class);
		 m1.invoke(null, (Object)new String[]{"nihao"});
	 }
}


4 Field类:代表某个类中的一个成员变量。   
    例如:  字节码实例.getField(”成员变量名“)   字节码.getDeclareField(”成员变量名“)
      4.1 得到的是对应字节码的类的成员变量的声明,而不是具体是值。
     4.2 可通过get(对象)来得到对象对应的共有属性的值.
     4.3 set(对象,newValue)    可以给对象的属性赋一个新的值,包括final的值。
     4.4 得到私有属性的值的方式:
     4.4.1 字节码.getDeclareField(”成员变量名“) 得到属性的定义。
     4.4.2 通过设置 setAccessible(true)使用get(对象)可获取私有变量的值。

反射成员变量的方法:

package cn.hmm;

import java.lang.reflect.Field;

//反射字段
public class reflectTest3 {

	public static void main(String[] args) throws Exception{
		// TODO 自动生成的方法存根
		//test1();
		test2();
	}
	
	public static void test1() throws Exception{
		
		Class clazz = Class.forName("cn.hmm.Person");
		Person p = (Person)clazz.newInstance();
		
		Field f = clazz.getField("as");
		Object obj = f.get(p);
		//获取成员变量的类型
		Class type = f.getType();
		System.out.println(type);
		
		String s = (String)f.get(p);
		System.out.println(s);
		f.set(p, "aabbccdd");
		String s1 = (String)f.get(p);
		System.out.println(s1);
	}
	
	//反射私有成员变量
	public static void test2() throws Exception{
		Class clazz = Class.forName("cn.hmm.Person");
		Person p = (Person)clazz.newInstance();
		
		Field f = clazz.getDeclaredField("aa");
		//暴力反射
		f.setAccessible(true);
		Object obj = f.get(p);
		Class type = f.getType();
		String s = (String)f.get(p);
		System.out.println(s);
		f.set(p, "eefffhhhgg");
		String s1 = (String)f.get(p);
		System.out.println(s1);
	}
}


Person类:

package cn.hmm;

import java.io.InputStream;
import java.util.List;

public class Person {
	private String name;
	private int age;
	public String as = "fdsghh";
	private String aa = "ahgfj";
	
	public Person(){
		System.out.println("构造函数");
	}
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	private Person(List list){
		System.out.println("list");
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	public void aa1(){
		System.out.println("aa1");
	}
	public void aa1(String name,int age){
		System.out.println(name+":"+age);
	}
	
	public Class[] aa1(String name,int[]age){
		return new Class[]{String.class,int.class,float.class,Person.class};
	}
	
	private void aa1(InputStream in){
		System.out.println(in);
	}
	
	public static void aa1(int num){
		System.out.println(num);
	}
	
	public static void main(String[] args){
		System.out.println("main!");
	}
}

总结 反射的作用就是用在写框架 ,如果不写框架就用不到这门技术
框架和工具类不同,框架是调用者,工具类是被调用者
框架要解决的核心问题
    我在写框架时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你
    以后写的类呢?因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new某个
    类的实例对象了,而要用反射方式来做。我们可以用一个类来写配置文件,写的时候通过反射配
    置文件的获得相应的类名,然后用户拿到框架的时候只需要把类名写到配置文件中就可以使用整
    个框架了。

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

详细请查看:www.itheima.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值