zoukankan      html  css  js  c++  java
  • 反射01

    1.java提供了一套API
    2.提供了检查一对对象内部结构的手段

    3.反射的用途

    1.java的动态执行  API

       a.动态加载类
      b.动态创建对象
      c.动态访问属性
      d.动态调执行方法
    2.可以用于实现组件的“解耦”

       -可以实现现在组件和未来组件的耦合关系,调用未来的程序组件

    重点掌握方法:

    1.Class.forName(类名)

    2.Method.invole(obj)

    3.Class.newInstancea()

    4.setAccessible(true)


    利用反射可以实现一段程序与未来一个类之间耦合在一起,
    这段程序就是与未来的类之间是松耦合的关系,也就是解除耦合了。
    如:Eclipse可以开发任何未来的程序,解析任何未来的程序结构
          Eclipse的快捷菜单用到了哪些技术?
    答:Eclipse利用反射技术实现快捷菜单,可以使用Eclipse被开发的类解耦。

    动态加载类

     类只加载一次,即便多次调用forName方法

    ,类也只加载一次,forName返回值是同一个对象的引用

    Class cls=Class.forName(String className);
    package day01;
    
    import java.util.Scanner;
    
    /*
     * 动态加载类到内存中
     *  Class.forName(
     */
    public class ClassForNameDemo02 {
    
    	public static void main(String[] args) throws ClassNotFoundException  {
    		Scanner in=new Scanner(System.in);
    		System.out.println("输入类名");
    		//输入的类名需要输入包名加类名(全限定名),例如:day01.Point (day01包下的Point类)
    		String className=in.nextLine();
    		//动态加载类
    		//当类名错误的时候会抛出类没有找到的异常
    		Class cls=Class.forName(className);
    Class cls1=Class.forName(classname);
                     Class cls2=Class.forName(classname);
                      System.out.println(cls1==cls2); 
     

    } }

      

    API方法动态创建对象

      a.Instance实例(对象)

      b.创建cls代表的类型的实例

      c.cls类型上必须包含无参数据构造器(可以是默认构造器)

      d.newInstance就是调用这个无参构造器创建对象

      e.如果没有无参数构造器则抛出异常

    package day01;
    
    import java.util.Scanner;
    
    /*
     * 动态加载类到内存中
     *  Class.forName(
     */
    public class ClassForNameDemo02 {
    
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException  {
            Scanner in=new Scanner(System.in);
            System.out.println("输入类名");
            //输入的类名需要输入包名加类名(全限定名),例如:day01.Point
            String className=in.nextLine();
            //动态加载类
            //当类名错误的时候会抛出类没有找到的异常
            Class cls=Class.forName(className);
            System.out.println(cls);

    /*
    * 若输入java.util.ArrayList 输出class java.util.ArrayList []
    * ArrayList无元素toString则输出【】
    *
    */

    //利用反射API动态创建对象
            Object obj=cls.newInstance();
            System.out.println(obj);  //day01.Point@4aa298b7
            //此时Point类没有重写toString,但表示创建成功
            
            
            
        }
    }

    例如Eclipse中当我们输入对象名.时,下面提示的方法和变量,就是有利用反射原理。

     动态访问属性:

    /*
    * 在Field类型上定义了get方法,可以用于获取对象的属性值
    * ,如果需要获取属性的值:
    *
    * -利用Class类型对象的方法,才能获取Field类型对象
    * -obj.getClass();
    * -Class.forName();
    * -获取Field类型对象
    * -调用get方法
    *
    */

    package day01;
    
    import java.lang.reflect.Field;
    import java.util.Scanner;
    
    public class ClassForNameDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, 
    IllegalAccessException, NoSuchFieldException, SecurityException {
    	System.out.println("请输入限定名");
    	Scanner scan=new Scanner(System.in);
    	//加载类
    	String str=scan.nextLine();
    	Class cls=Class.forName(str);
    	
    	System.out.println("请输入属性名");
    	
    	String fieldName=scan.nextLine();
    	/*
    	 * 查找类中的属性
    	 * getDeclaredFields 带s的则获取全部属性(成员变量),
    	 * 不加s的获取的是指定名字的一个属性
    	 * 找到就返回属性fid,找不到就抛异常
    	 */
    	Field fld=cls.getDeclaredField(fieldName);
    	System.out.println(fld);
    	
    	
    	//加载对象
    	Object obj=cls.newInstance();   //动态获取对象
    	//动态访问属性
    			/*
    			 * 在Field类型上定义了get方法,可以用于获取对象的属性值
    			 * ,如果需要获取属性的值:
    			 * 
    			 * -利用Class类型对象的方法,才能获取Field类型对象
    			 *   -obj.getClass();
    			 *   -Class.forName();
    			 *   -获取Field类型对象
    			 *   -调用get方法
    			 *   属性名是用户运行期间输入的,输入哪个属性
    			 *   名这段程序就会输出哪个属性的值
    			 *   也就意味着,程序和属性之间是松耦合关系
    			 *   
    			 */   
    	  Object val=fld.get(obj);//因为输入的属性类型不确定,故用object接收
    	  
    	  System.out.println(val);//获取obj对象中的FieldName值
    	
    	
    	
    	
    }
    }
    

    访问的属性如果为不可见(私有加跨包)属性(被private修饰的属性),则抛java.lang.IllegalAccessException异常。

    解决该问题的方法:调用setAccessible(true)方法(故private修饰的属性外部不能访问不正确,利用反射可以访问私有属性)

    注:无论是私有属性还有私有方法,都可以利用反射API进行调用,在调用之前使用fld.setAccessible(true);该方法执行之后可以打开原来私有的访问权限。不仅仅如此,该方法还可以打开任何不可见的属性/方法的访问权限。

    package day01;
    
    import java.lang.reflect.Field;
    import java.util.Scanner;
    
    public class FieldGetDemo {
    public static void main(String[] args) throws ClassNotFoundException,
    InstantiationException, IllegalAccessException,
    NoSuchFieldException, SecurityException {
    	
    	System.out.println("输入限定名");
    	Scanner scan=new Scanner(System.in);
    	String forName=scan.nextLine();
    	System.out.println("请输入属性名");
    	String fieldName=scan.nextLine();
    	
    	Class cls=Class.forName(forName);
    	Object obj=cls.newInstance();//动态创建对象
    	
    	Field fl=cls.getDeclaredField(fieldName);//动态访问属性
    	fl.setAccessible(true);
    	//如果访问的是私有属性在获取对象值之前用该对象调用setAccessible方法,传入的
    	//参数为true,则可以访问私有属性
    	Object val=fl.get(obj);
    	System.out.println(fl);
    	System.out.println(val);
    	
    	scan.close();
    	
    }
    }
    

      

    利用反射访问对象的方法
    访问方法的核心API

    使用步骤
    1.获取Class对象,才能利用其方法找到Method对象
    -Class.forName(类名)
    2.Method getDeclaredMethod(方法名)根据方法名找到Method对象
    -Method
    3.得到包含方法的对象obj
    -cls.newInstances()
    4.准备参数(调取的方法有参数)
    method.invoke(obj)该方法的返回值为该方法的返回值,如果方法没有返回值,则返回值为null

     package day01import java.lang.reflect.Method;

    import java.util.Scanner;
    
    /**
     * 利用反射API动态的执行对象的方法
     * @author TEDU
     *
     */
    public class InvokeMethodDemo {
    public static void main(String[] args) 
    	throws Exception{
    		/*
    		 *利用反射API动态执行对象的方法 
    		 */
    		Scanner scan=new Scanner(System.in);
    		System.out.print("输入类型:");
    		String className=scan.nextLine();
    		System.out.println("请输入方法名:");
    	    String methodName=scan.nextLine();
    	//动态加载类
    	Class cls=Class.forName(className);
    	
    	//在类cls中找到需要执行的methodName方法
    	//如果方法名错误,将抛出没有找到的方法异常
    	Method method=cls.getDeclaredMethod(methodName);
    	System.out.println("method:"+method);
    	//动态创建对象
    	Object obj=cls.newInstance();
    	//执行invoke时, obj对象一定包含制定的mothod的对象,否则将抛出异常
    	Object value=method.invoke(obj);//输出的是方法的返回值
    	System.out.println("value:"+value);

    //public int day01.Point.run()输出的是全限定名 } }

      

    cls.getDeclaredMethod在当前cls类型上查找当前类中声明的方法
    -getDeclaredMethod只查询当前类中的方法
    cls.getMethod 在当前cls类型以及全部继承的方法中查找声明的共有方法
    -查询当前类和父类中的继承的方法

  • 相关阅读:
    NABCD项目分析
    周总结6
    移动端展示
    暑期周进度报告(四)
    暑期周进度报告(三)
    暑期周进度报告(二)
    暑期周进度报告(一)
    《人件》阅读笔记02
    周学习进度报告(2020/06/05)
    2020春季软件工程课程总结
  • 原文地址:https://www.cnblogs.com/chenzhiwei/p/9517015.html
Copyright © 2011-2022 走看看