黑马程序员---反射

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


一,什么是反射机制 
        简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 
    那么就可以通过反射机制来获得类的所有信息。 
二,哪里用到反射机制 
        有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码, 
    Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成 
    驱动对象实例,并不知道它的具体含义。听了反射机制这节课后,才知道,原来这就是反射,现在很多开 
    框架都用到反射机制,hibernate、struts都是用反射机制实现的。 
三,反射机制的优点与缺点 
        为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念, 
    静态编译:在编译时确定类型,绑定对象,即通过。 
    动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多 
    态的应用,有以降低类之间的藕合性。 
    一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中 
    它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编 
    译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如 
    这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能 
    的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功 
    能。 
       它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 
    满足我们的要求。这类操作总是慢于只直接执行相同的操作。
四,获取某个类的Class对象的三种方式: 
  方式一:调用对象的getClass()方法。它是Object类中的方法。
       此方法是普通方法,不是静态的,要通过类的对象的引用去调用。
       Student stu = new Studetn();
       Class stuClass = stu.getClass();
  方式二:任何的"数据类型"都有一个"静态的属性"--class属性,这个属性可以
       获取这个类的Class对象
  方式三:调用Class类中的静态方法forName()可以获取某个类的Class对象;
  public static Class forName(String className) 

  常用:方式三

 public class Demo {
	public static void main(String[] args) throws ClassNotFoundException {
		Student stu = new Student();
		//方式一:
		Class stuClass1 = stu.getClass();
		//方式二:
		Class stuClass2 = Student.class;
		//方式三:
	//	Class stuClass3 = Class.forName("Student");//运行时异常。这里需要的是:全名限定的类名(带包的类名)
		Class stuClass3 = Class.forName("cn.itcast.demo01_获取Class对象的三种方式.Student");
		
		//对于Student的Class对象,三种方式获取的都是同一个Class对象。这个Class对象,在内存中只产生一个。
		System.out.println("stuClass1 == stuClass2 :" + (stuClass1 == stuClass2));
		System.out.println("stuClass1 == stuClass3 : " + (stuClass1 == stuClass3));;
	}
}
通过这个Class对象,我们可以:
  1,获取并调用这个类的所有的构造方法:
  批量获取
  1.public Constructor[] getConstructors():获取所有公共构造方法
  2.public Constructor[] getDeclaredConstructors():获取所有构造方法。包括公有,受保护,默认,私有
  获取单个的构造方法:
  1.public Constructor getConstructor(Class... parameterTypes):获取类中的指定的"公有构造方法"。
    参数:parameterTypes:构造方法形参的类型的Class
  2.public Constructor getDeclaredConstructor(Class...parameterTypes):获取类中的任何的构造方法,包括私有的

调用构造方法:通过Constructor去调用。使用方法:public T newInstance(Object... initargs)
2,通过Class对象获取成员属性,并调用:
 
  批量获取:
  1.Field[] getFields() :所用"公有"的成员属性
  2.Field[] getDeclaredFields()  :所有的成员属性,包括私有的:
  获取单个的属性
  1.Field getField(String fieldName):获取单个的,公有的成员属性
  2.Field getDeclaredField(String fieldName):获取单个的成员属性,可以是任何的访问级别
  
  怎样设置和获取属性的值?
  Field:
  set(Object obj,Object value):设置值。注意:设置前,一定要先实例化一个此类的对象。
  get(Object obj)
3,通过Class对象获取某个类的成员方法并调用:
  
  批量获取:
  1.Method[] getMethods() :获取所有的"公有"方法;
  2.Method[] getDeclaredMethods() :获取所有方法,包括私有的。
 
  获取单个的:
  1.Method getMethod(String name, Class<?>... parameterTypes) :获取某个公有的方法。
                形参:name:方法名;
                parameterTypes:形参的类型列表;
       2.Method getDeclaredMethod(String name, Class<?>... parameterTypes):获取某个方法。可以是私有的。
       
  调用方法:
  Method:public Object invoke(Object obj,Object... args):调用此方法;
  注意:调用方法前,一定要先实例化一个此类对象。
  参数:
  obj : 方法所属的对象;
  args: 调用方法需要的实参
五, 一个小例子:
  1.定义一个具有Integer类型泛型的集合对象,问:怎么可以向这个集合中添加一个字符串;

  public class Demo {
	public static void main(String[] args) throws Exception{
		ArrayList<Integer> intList = new ArrayList<>();
		
		intList.add(10);
	//	intList.add("abc");
		
		//通过反射,直接去加载ArrayList的Class,然后调用它的add方法
		Class listClass = ArrayList.class;
		//获取add方法
		Method addMethod = listClass.getMethod("add", Object.class);
		//调用add方法
		addMethod.invoke(intList, "abc");
		
		//遍历集合
		System.out.println("遍历集合:");
		for(Object o : intList){
			System.out.println(o);
		}
	}
}
六,代理模式:
  
  1.例子:
  1).Student类中有一个coding()方法,写程序;
  2).测试类中如果需要coding()方法,需要直接实例化一个Student,并调用方法;
    如果想在coding()方法的前面或者后面添加一些其他功能,可以不用修改Student类,而为Student类添加
    一个"代理类",代理类会调用Student类中的方法。
       3).增加了代理类后,测试类不需要直接面对Student,转而使用代理类。代理类中为coding方法添加了新的功能。
  动态代理:
  
  1.之前的例子实现有些麻烦,要为每个需要代理的类单独提供一个"代理类";
  2.Java类中提供了"动态代理",使我们不需要为每个类都提供"代理类",它在内部会动态的生成代理类:
  3.使用动态代理的步骤:
  1).自定义一个类,实现InvocationHandler接口,重写内部的invoke()方法;
  2).在需要代理类的时候,使用Proxy的newProxyInstance()方法获取代理类的对象
七,一些简单代码:
  实例一:获得完整的类名  
//获得完整的类名  
public class GetClassName {    
    public String getNameByClass() {  
        String name = "";  
        System.out.println("通过类本身获得对象");  
        Class UserClass = this.getClass();  
        System.out.println("获得对象成功!\n");  
        System.out.println("通过类对象获得类名");  
        name = UserClass.getName();  
        System.out.println("获得类名成功!");  
        return name;  
    }  
    public static void main(String[] args) {  
          
        GetClassName gcn = new GetClassName();  
        System.out.println("类名为:"+gcn.getNameByClass());  
    }  
  
}  
运行结果:
通过类本身获得对象
获得对象成功!
通过类对象获得类名
获得类名成功!
类名为:reflection.getclassname.GetClass Name   

实例二:获得类的属性
//获得类的属性  
public class GetFields {  
    public static void getFieldNames(String className) {  
          
        try {  
            //获得类名  
            Class c = Class.forName(className);  
            //获得所有属性  
            Field[] fds = c.getFields();  
              
            for (int i=0; i<fds.length; i++)  
            {  
                String fn = fds[i].getName();  
                Class tc = fds[i].getType();  
                String ft = tc.getName();  
                System.out.println("该属性的名字为:"+fn+",该属性的类型为:"+ft);  
            }  
        }catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
      
    public static void main(String[] args) {  
        GetFields.getFieldNames("reflection.getfields.FieldInfo");  
    }  
  
}  

运行结果:
该属性的名字为:id,该属性的类型为:java.lang.String
该属性的名字为:username,该属性的类型为:java.lang.String    

实例三:获得类实现的接口

//获得类实现的接口  
public class GetInterfaces {  
  
    public static void getInterfaces(String className) {  
        try {  
            //取得类  
            Class cl = Class.forName(className);  
            Class[] ifs = cl.getInterfaces();  
            for (int i = 0; i<ifs.length;i++)  
            {  
                String IName = ifs[i].getName();  
                System.out.println("该类实现的接口名字为:"+IName);  
            }  
        }catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
      
    public static void main(String[] args) {  
        GetInterfaces.getInterfaces("reflection.getinterfaces.Student");  
    }  
  
}  

运行结果:
该类实现的接口名字为:reflection.getinterfaces.Person    

实例四:获得类及其属性的修饰符

//获得类及其属性的修饰符  
public class GetModifiers {  
  
    private String username = "liu shui jing";  
    float f = Float.parseFloat("1.000");  
    public static final int i = 37;  
      
    //获得类的修饰符  
    public static String useModifiers(UserInfo ui) {  
          
        Class uiClass = ui.getClass();  
        int m = uiClass.getModifiers();  
        return Modifier.toString(m);  
          
    }  
      
    //获得本类属性的修饰符  
    public void checkThisClassModifiers() {  
          
        Class tc = this.getClass();       
        Field fl[] = tc.getDeclaredFields();  
      
        for(int i=0;i<fl.length;i++)  
        {  
            System.out.println("第"+(i+1)+"个属性的修饰符为:"+Modifier.toString(fl[i].getModifiers()));  
        }  
          
    }  
    public static void main(String[] args) {  
          
        //获得类的修饰符  
        UserInfo ui =new UserInfo();  
        System.out.println("获得这个类的修饰符:"+GetModifiers.useModifiers(ui)+"\n");  
          
        //获得本类属性的修饰符  
        GetModifiers gm = new GetModifiers();  
        gm.checkThisClassModifiers();  
          
    }  
  
}  
运行结果:
获得这个类的修饰符:public
 
第1个属性的修饰符为:private
第2个属性的修饰符为:
第3个属性的修饰符为:public static final  

实例五:获得类的构造函数

//获得类的构造函数  
public class GetConstructor {  
  
    //构造函数一  
    GetConstructor(int a) {  
          
    }  
      
    //构造函数二  
    GetConstructor(int a, String b) {  
          
    }  
      
    public static void getConstructorInfo(String className) {  
        try {  
            //获得类的对象  
            Class cl =Class.forName(className);  
            System.out.println("获得类"+className+"所有的构造函数");  
            Constructor ctorlist[] = cl.getDeclaredConstructors();  
            System.out.println("遍历构造函数\n");  
            for(int i =0 ; i<ctorlist.length; i++)  
            {  
                Constructor con = ctorlist[i];  
                System.out.println("这个构造函数的名字为:"+con.getName());  
                System.out.println("通过构造函数获得这个类的名字为:"+con.getDeclaringClass());  
                  
                Class cp[] = con.getParameterTypes();  
                for (int j=0; j<cp.length; j++)  
                {  
                    System.out.println("参数 "+j+" 为 "+cp[j]+"\n");  
                }  
            }  
        }catch (Exception e) {  
                System.err.println(e);            
        }  
    }  
    public static void main(String[] args) {  
        GetConstructor.getConstructorInfo("reflection.getconstructor.GetConstructor");  
    }  
  
}  

运行结果:
获得类reflection.getconstructor.GetConstructor所有的构造函数
遍历构造函数
 
这个构造函数的名字为:reflection.getconstructor.GetConstructor
通过构造函数获得这个类的名字为:class reflection.getconstructor.GetConstructor       
参数 0 为 int
 
这个构造函数的名字为:reflection.getconstructor.GetConstructor
通过构造函数获得这个类的名字为:class reflection.getconstructor.GetConstructor
参数 0 为 int
 
参数 1 为 class java.lang.String



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值