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类型以及全部继承的方法中查找声明的共有方法
    -查询当前类和父类中的继承的方法

  • 相关阅读:
    centos crash debug
    go get Unknown SSL protocol error in connection to gopkg.in
    Tensorflow serving with Kubernetes
    Spring 集成 Swagger UI
    Docker Registry V2 Garbage Collection
    Docker Registry V2 with Nginx
    Zabbix磁盘性能监控
    Zabbix CPU utilization监控参数
    Windows挂载Gluster复制卷
    Redis持久化存储(三)
  • 原文地址:https://www.cnblogs.com/chenzhiwei/p/9517015.html
Copyright © 2011-2022 走看看