zoukankan      html  css  js  c++  java
  • Java反射机制(带应用)

    1、Java的反射机制:

     

           Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
          Java反射机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
           但是Java有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
    ************************************************************************************************************************
    以上是百度百科中对Java反射机制的解释。
     
     
    2、Java反射机制的功能:
     
    (1)在运行时判断任意一个对象所属的类;
    (2)在运行时构造任意一个类的对象;
    (3)在运行时判断任意一个类所具有的成员变量和方法
    (4)在运行时调用任意一个对象的方法;生成动态代理。
     
     
     
    3、与反射相关的类有:
     
    Class:表示类、Field:表示成员变量、 Method:表示方法、Constructor:表示构造器。

     

     
     
    4、获取Class类的三种基本方式:

    1)通过     类名称.class,对基本类型也支持;

                   Class c = int.class

               Class c = int[ ].class

               Class c = String.class

    (2)通过    对象.getClass( )方法

             Class c = obj.getClass(  );

    (3) Class.forName( )  通过类名称加载类,这种方法只要有类名称就可以得到Class

             Class c = Class.forName(“cn.ywq.Demo”);

    示例:通过反射来创建一个对象,利用.newInstance( )方法来实现。

    public class Demo1 {
    	@Test
    	public void fun1() throws Exception {
    		String className = "cn.ywq.User";
    		Class clazz = Class.forName(className); 
    		User user = (User)clazz.newInstance();
    		System.out.println(user);
    	}
    }
    
    class User {
    	private String username;
    	private String password;
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	@Override
    	public String toString() {
    		return "User [username=" + username + ", password=" + password + "]";
    	}
    }
    


     

    5、Field类的使用

    Field表示类的成员变量,可以是实例变量,也可以是静态变量。

     

    (1)获取Field对象,

    获取Field对象需要使用Class对象,下面是Class类的API

    Field getField(String name)通过名字获取公有成员变量的反射对象,包含父类中声明的公有成员变量;

    Field[ ] getFields()获取所有公有成员变量反射对象,包含父类中声明的公有成员变量;

    Field getDeclaredField(String name)通过名字获取本类中某个成员变量,包含本类的private成员变量,但父类中声明的任何成员变量都不包含;

    Field[ ] getDeclaredFields()获取本类中声明的所有成员变量,包含private成员变量,但不包含父类中声明的任何成员变量;

     

    (2)Field类的常用方法

    String getName()获取成员变量名;

    Class getDeclaringClass()获取成员变量的类型;

    Class getType()获取当前成员变量的类型;

    Object get(Object obj)获取obj对象的成员变量的值;

    void set(Object obj, Object value)设置obj对象的成员变量值为value

    示例:通过Field读写成员

    User.java

    public class User {
    	public String username;
    	public String password;
    
    	public User() {
    	}
    
    	public User(String username, String password) {
    		this.username = username;
    		this.password = password;
    	}
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	@Override
    	public String toString() {
    		return "User [username=" + username + ", password=" + password + "]";
    	}
    }
    

    Demo1.java

    public class Demo1 {
    	@Test
    	public void fun1() throws Exception {
    		String className = "cn.itcast.User";
    		Class clazz = Class.forName(className);
    		User user = new User("zhangSan", "123");
    		
    		Field field1 = clazz.getField("username"); 
    		Field field2 = clazz.getField("password") ;
    		
    		String username = (String)field1.get(user); 
    		String password = (String)field2.get(user); 
    		
    		System.out.println(username + ", " + password);
    		
    		field1.set(user, "liSi"); 
    		field2.set(user, "456"); 
    		
    		System.out.println(user);
    	}
    }
    





     Constructor表示一个类的构造器。即构造器的反射对象!

     

    (1)获取Constructor对象

    获取Construcator对象需要使用Class对象,下面API来自Class类:

    Constructor getConstructor(Class… parameterTypes):通过指定的参数类型获取公有构造器反射对象;

    Constructor[ ] getConstructors(  ):获取所有公有构造器对象;

    Constructor getDeclaredConstructor(Class… parameterTypes):通过指定参数类型获取构造器反射对象。可以是私有构造器对象;

    Constructor[ ] getDeclaredConstructors():获取所有构造器对象。包含私有构造器;

     

    (2)Construcator类常用方法

      String getName():获取构造器名;

      Class getDeclaringClass():获取构造器所属的类型;

      Class[ ] getParameterTypes():获取构造器的所有参数的类型;

      Class[ ] getExceptionTypes():获取构造器上声明的所有异常类型;

      newInstance(Object… initargs):通过构造器反射对象调用构造器。

     

    示例:通过Construcator创建对象 

    User.java

    public class User {
    	private String username;
    	private String password;
    
    	public User() {
    	}
    
    	public User(String username, String password) {
    		this.username = username;
    		this.password = password;
    	}
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	@Override
    	public String toString() {
    		return "User [username=" + username + ", password=" + password + "]";
    	}
    }
    
     

    Demo1.java

    public class Demo1 {
    	@Test
    	public void fun1() throws Exception {
    		String className = "cn.itcast.User";
    		Class clazz = Class.forName(className);
    		Constructor c = clazz.getConstructor(String.class, String.class);
    		User user = (User)c.newInstance("zhangSan", "123");
    		System.out.println(user);
    	}
    }
    



    7、Method类的使用 

    (1)获取Method

    获取Method需要通过Class对象,下面是Class类的API

      Method getMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取方法反射对象,包含父类中声明的公有方法,但不包含所有私有方法;

      Method[ ]   getMethods():获取所有公有方法,包含父类中的公有方法,但不包含任何私有方法;

      Method getDeclaredMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取本类中声明的方法的反射对象,包含本类中的私有方法,但不包含父类中的任何方法;

     Method[  ] getDeclaredMethods( ):获取本类中所有方法,包含本类中的私有方法,但不包含父类中的任何方法。

     

    (2)Method常用方法

      String getName( ):获取方法名;

      Class getDeclaringClass( ):获取方法所属的类型;

      Class[ ] getParameterTypes( ):获取方法的所有参数的类型;

      Class[ ] getExceptionTypes( ):获取方法上声明的所有异常类型;

      Class getReturnType( ):获取方法的返回值类型;

      Object invode(Object obj, Object… args):通过方法反射对象调用方法,如果当前方法是实例方法,那么当前对象就是obj,如果当前方法是static方法,那么可以给obj传递nullargs表示是方法的参数;

     

    示例:通过Method调用方法

    public class Demo1 {
    	@Test
    	public void fun1() throws Exception {
    		String className = "cn.ywq.User";
    		Class clazz = Class.forName(className);
    		Constructor c = clazz.getConstructor(String.class, String.class);
    		User user = (User)c.newInstance("zhangSan", "123");
    		
    		Method method = clazz.getMethod("toString");
    		String result = (String)method.invoke(user);
    		System.out.println(result);
    	}
    }
    




    8、AccessibleObject的使用

    AccessibleObject类是ConstructorMethodField三个类的父类。AccessibleObject最为重要的方法如下:

    boolean isAccessible( ):判断当前成员是否可访问;

    voidsetAccessible(boolean flag):设置当前成员是否可访问。

    ConstructorMethodField为私有时,如果我们想反射操作,那么就必须先调用反射对象的setAccessible(true)方法,然后才能操作。

    User.java

    public class User {
    	private String username;
    	private String password;
    
    	public User() {
    	}
    
    	public User(String username, String password) {
    		this.username = username;
    		this.password = password;
    	}
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	@Override
    	public String toString() {
    		return "User [username=" + username + ", password=" + password + "]";
    	}
    }
    

    注意,User类的usernamepassword成员变量为private的,这时再通过Field来反射操作这两个成员变量就必须先通过setAccessible(true)设置后才行。

    public class Demo1 {
    	@Test
    	public void fun1() throws Exception {
    		String className = "cn.ywq.User";
    		Class clazz = Class.forName(className);
    		User user = new User("zhangSan", "123");
    		
    		Field field1 = clazz.getDeclaredField("username");
    		Field field2 = clazz.getDeclaredField("password");
    		
    		field1.setAccessible(true);
    		field2.setAccessible(true);
    		
    		String username = (String)field1.get(user);
    		String password = (String)field2.get(user);
    		
    		System.out.println(username + ", " + password);
    		
    		field1.set(user, "liSi");
    		field2.set(user, "456");
    		
    		System.out.println(user);
    	}
    }
    



     

    9、Java反射机制在工厂方法模式中的使用:


           工厂方法模式模式主要的作用就是创建一个对象,它是new一个对象的替代品。在所有需要生成对象的地方都可以使用。

           工厂方法模式利用Java的反射机制来得到Class类,利用newInstance(  )方法来创建一个对象。

    通用类图如下所示:


    通用源代码:

    //抽象产品类
    public abstract class Product {    
        //产品类的公共方法
        public void method1(){
                //业务逻辑处理
        }  
        //抽象方法
        public abstract void method2();    
    }
    
    //多个具体产品类
    public class ConcreteProduct1 extends Product {
        public void method2() {
                //业务逻辑处理
        }
    }
    public class ConcreteProduct2 extends Product {
        public void method2() {
                //业务逻辑处理
        }
    }
    
    //抽象工厂类
    public abstract class Creator {    
        /*
         * 创建一个产品对象,其输入参数类型可以自行设置
         * 通常为String、Enum、Class等,当然也可以为空
         */        
        public abstract <T extends Product> T create Product(Class<T> c);
    }
    
    //具体工厂类
    public class ConcreteCreator extends Creator {     
        public <T extends Product> T create Product(Class<T> c){
                Product product=null;
                try {
                       product = (Product)Class.forName(c.get Name()).new Instance();
                } catch (Exception e) {
                       //异常处理
                }
                return (T)product;         
        }
    }

    测试代码如下:

    public class Client {
        public static void main(String[] args) {
                Creator creator = new ConcreteCreator();
                Product product = creator.createProduct(ConcreteProduct1.class);
                /*
                 * 继续业务处理
                 */
        }
    }

    可以看到,工厂方法模式中,在具体的工厂中使用了反射机制来创建了一个product的对象。



     


     
     
     
     
     
  • 相关阅读:
    Redis做为缓存的几个问题
    Python——操作smb文件服务器(上传和下载)
    Python——assert、isinstance的用法
    centos7-修改默认python为3
    mqtt
    如何编译生成 mkfs.ubifs、ubinize 工具
    2020-2笔记
    2020-1笔记
    C语言中getopt()和getopt_long()函数的用法
    buildroot
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467291.html
Copyright © 2011-2022 走看看