java_反射

来源:互联网 发布:环保75标准数据 编辑:程序博客网 时间:2024/06/11 02:43

Java 反射

一 认识反射

l  “程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。

 

l  尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。

 

什么是反射

a)        反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

 

b)        JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

 

应用场景

Ø  Spring框架:IOC(控制反转)

Ø  Hibernate框架:关联映射等

Ø  白盒测试

 

 


 

二 反射讲解

l 什么是反射:

可以通过类名动态的创建对象,可以根据对象获取类中所有的属性和方法。

 

获取Class

根据字符串得到类名Class cls=Class.forName(String className);

根据对象获取类:Class =obj.getClass();

根据类获取类:Class cls =Person.class;

根据全路径来获取:Class cls=Class.forName(报名.类名);

 

 

获取属性

获取所有属性Filed[] filed =cls.getDeclaredFields();

获取所有公共属性: Filed[] fields=cls.getFileds();

获取指定属性:Field fields=cls.getDeclaredFiled(Stringname)

取得指定公共属性Field fields=cls.getField(String name)

 

取得方法

获得所有方法:  Methodmethods=cls.getDeclaredMethods();

获取所有公共方法:Method[] methods=cls.getMethods();

取得指定的方法:Method method=cls.getDeclaredMethod(Stringname,Class[] paramsType);

获取指定公共的方法: Method method =cls.getMethod(Stringname,Class[] paramsType);

 

获取构造方法

获得使用特殊的参数类型的公共构: Constructor constructor=cls.getConstructor(Class[]params) 

获得类的所有公共构造函数:Constructor[] constructor=cls. getConstructors()

获得使用特定参数类型的构:Constructor constructor=cls.getDeclaredConstructor(Class[]params)

获得类的所有构造函数:Constructor[] constructor=cls.getDeclaredConstructors()

 

执行某个方法

Method.invoke(Object target,Object[] params);

 

 

List获取类:

获取方式

说明

示例

object.getClass()

每个对象都有此方法

获取指定实例对象的Class

List list = new ArrayList();

Class listClass = list.getClass();

class. getSuperclass()

获取当前Class的继承类Class

List list = new ArrayList();

Class listClass = list.getClass();

Class superClass = listClass. getSuperclass();

Object.class

.class直接获取

Class listClass = ArrayList.class;

Class.forName(类名)

用Class的静态方法,传入类的全称即可

try {

Class c = Class.forName("java.util.ArrayList");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

Primitive.TYPE

基本数据类型的封装类获取Class的方式

Class longClass = Long.TYPE;

Class integerClass = Integer.TYPE;

Class voidClass = Void.TYPE;

 

 平常情况我们通过new Object来生成一个类的实例,但有时候我们没法直接new,只能通过反射动态生成。

实例化无参构造函数的对象,两种方式:

①Class. newInstance();

②Class. getConstructor (new Class[]{}).newInstance(new Object[]{})

实例化带参构造函数的对象:

clazz.getConstructor(Class<?>... parameterTypes) .newInstance(Object... initargs)

 

 

 


程序实例:

 

public class BaseUser {

    private StringId;

    private Stringname;

    public BaseUser(){

       

    }

    public BaseUser(String name, String id) {

        super();

        this.name = name;

        Id = id;

    }

    public String getId() {

        returnId;

    }

    public String getName() {

        returnname;

    }

 

    public voidsetId(String id) {

        Id = id;

    }

    public voidsetName(String name) {

        this.name = name;

    }

    public String toString() {

        return"BaseUser[name=" +name + ", Id="+Id + "]";

    }  

}

 

public class User extendsBaseUser {

    private Stringsex;

    public User(){

       

    }

    public User(String sex) {

        super();

        this.sex = sex;

    }

    public User (String id,String name,String sex){

        super(name, id);

        this.sex=sex;

    }

    public String getSex() {

        returnsex;

    }

    public voidsetSex(String sex) {

        this.sex = sex;

    }

   

    public String toString() {

        return"User[sex=" +sex +", name="+this.name+", id="+this.Id+"]";

    }

   

}


 

测试类:

public classReflaceTest {

 

    /**

     * @param args

     * @throws SecurityException

     * @throws NoSuchMethodException

     * @throws InvocationTargetException

     * @throws IllegalArgumentException

     * @throws IllegalAccessException

     * @throws InstantiationException

     */

public static void main(String[] args)throwsIllegalArgumentException, InvocationTargetException, NoSuchMethodException,SecurityException, InstantiationException, IllegalAccessException {

        // TODO Auto-generated method stub

        Class cls= User.class;

        User user=(User) cls.newInstance();

        System.out.println(user);

        User user2=(User) cls.getConstructor(new Class[]{}).newInstance(new Object[]{});

        System.out.println(user2); 

        User user3=(User)cls.getConstructor(new Class[]{String.class,String.class,String.class}).newInstance(new Object[]{"肖正文","xwx354128",""});

        System.out.println(user3); 

        User user4=newUser("");

        System.out.println(user4); 

   Class clss=Class.forName("xiao.it.base.User");

       User u=(User) clss.newInstance();

       System.out.println(u);

    }

}

User [sex=null,name=null, id=null]

User [sex=null,name=null, id=null]

User [sex=男, name=xwx354128, id=肖正文]

User [sex=男, name=null, id=null]

User [sex=null,name=null, id=null]

 


 

Ø 获得当前类以及超类的public Method:

–     Method[] arrMethods = classType. getMethods();

Ø 获得当前类申明的所有Method:

–     Method[] arrMethods = classType. getDeclaredMethods();

Ø 获得当前类以及超类指定的public Method:

–     Method method = classType. getMethod(String name,Class<?>... parameterTypes);

Ø 获得当前类申明的指定的Method:

–     Method method = classType. getDeclaredMethod(String name,Class<?>... parameterTypes)

Ø 通过反射动态运行指定Method:

–      Object obj = method.invoke(Object obj, Object... args)

 

 

  反射的方式进行方法的调用

public class Methodss {

 

    /**

     * @param args

     * @throwsSecurityException

     * @throwsNoSuchMethodException

     * @throwsInvocationTargetException

     * @throwsIllegalArgumentException

     * @throwsIllegalAccessException

     * @throwsInstantiationException

     */

    public static void main(String[] args)throws NoSuchMethodException,SecurityException, IllegalAccessException, IllegalArgumentException,InvocationTargetException, InstantiationException {

       // TODO Auto-generatedmethod stub

       Class<?> cls=User.class;

       User u=(User) cls.newInstance();

       Method[] me=cls.getMethods();

       for(Method m:me){

           System.out.println("本类与超类的公共方法"+m);

       }

       Method setId=cls.getMethod("setId",new Class[]{String.class});

       System.out.println("当前类或是父类的setId方法"+setId);                 System.out.println("===========================");

       Method[] me1=cls.getDeclaredMethods();

       for(Method m:me1){

           System.out.println("本类的方法"+m);

       }

       System.out.println("===========================");

       Method setSex=cls.getDeclaredMethod("setSex",new Class[]{String.class});

       System.out.println("本类的方法的setSex方法"+setSex);

       //不做java访问语言检查,类外访问私有字段

       setId.setAccessible(true);

       setId.invoke(u, new Object[]{"xwx354128"});

       System.out.println("反射的方式调用父类或本类的方法"+cls.getMethod("getId",new Class[]{}).invoke(u, new Object[]{}));

       System.out.println("==========================");

       setSex.setAccessible(true);

       setSex.invoke(u, new Object[]{""});

       System.out.println("反射的方式调用本类的方法"+cls.getMethod("getSex",new Class[]{}).invoke(u, new Object[]{}));

       System.out.println("========================");

    }

}

 

测试结果:

本类与超类的公共方法public java.lang.String xiao.it.base.User.toString()

本类与超类的公共方法public void xiao.it.base.BaseUser.setId(java.lang.String)

本类与超类的公共方法public java.lang.String xiao.it.base.BaseUser.getName()

本类与超类的公共方法public java.lang.String xiao.it.base.BaseUser.getId()

本类与超类的公共方法public voidxiao.it.base.BaseUser.setName(java.lang.String)

本类与超类的公共方法public final void java.lang.Object.wait() throws java.lang.InterruptedException

本类与超类的公共方法public final void java.lang.Object.wait(long,int) throwsjava.lang.InterruptedException

本类与超类的公共方法public final native void java.lang.Object.wait(long)throwsjava.lang.InterruptedException

本类与超类的公共方法public boolean java.lang.Object.equals(java.lang.Object)

本类与超类的公共方法public native int java.lang.Object.hashCode()

本类与超类的公共方法public final native java.lang.Classjava.lang.Object.getClass()

本类与超类的公共方法public final native void java.lang.Object.notify()

本类与超类的公共方法public final native void java.lang.Object.notifyAll()

当前类或是父类的setId方法public void xiao.it.base.BaseUser.setId(java.lang.String)

===========================================

本类的方法public void xiao.it.base.User.setSex(java.lang.String)

本类的方法public java.lang.String xiao.it.base.User.getSex()

本类的方法public java.lang.String xiao.it.base.User.toString()

===========================================

本类的方法的setSex方法public void xiao.it.base.User.setSex(java.lang.String)

反射的方式调用父类或本类的方法xwx354128

===========================================

反射的方式调用本类的方法男

===========================================

 


 

 

 

Ø  获得当前类以及超类的publicField:

–     Field[] arrFields = classType. getFields();

Ø  获得当前类申明的所有Field:

–     Field[] arrFields = classType. getDeclaredFields();

Ø  获得当前类以及超类指定的publicField:

–     Field field = classType. getField(String name);

Ø  获得当前类申明的指定的Field:

–     Field field = classType. getDeclaredField(String name);

Ø  通过反射动态设定Field的值:

–     fieldType.set(Object obj, Object value);

Ø  通过反射动态获取Field的值:

–     Object obj = fieldType. get(Object obj) ;

 

public class Filedsds {

 

    /**

     * @param args

     */

    public static void main(String[] args)throws Exception {

       // TODO Auto-generatedmethod stub

       User u=new User();

       Class cls=User.class;

       Field [] field=cls.getFields();

       for(Field f:field){

           System.out.println("子类或者父类的字段属性public"+f);

       }  

       System.out.println("=======================");

      

       Field [] fileds=cls.getDeclaredFields();

       for(Field ff:fileds){

           System.out.println("本类字段"+ff);

       }

       System.out.println("=======================");

      

       Field name=cls.getField("name");

       name.setAccessible(true);

       name.set(u, "肖正文");

       System.out.println("公共类与子类的字段子类或者父类的字段属性public:"+name.get(u));

       System.out.println("=======================");

      

       Field sex=cls.getDeclaredField("sex");

       sex.setAccessible(true);

       sex.set(u, "");

       System.out.println("本类中声明的方法"+sex.get(u));

       System.out.println("=======================");

    }

}

 

运行结果:

子类或者父类的字段属性public型public java.lang.String xiao.it.base.BaseUser.Id

子类或者父类的字段属性public型public java.lang.String xiao.it.base.BaseUser.name

=======================

本类字段private java.lang.String xiao.it.base.User.sex

=======================

公共类与子类的字段子类或者父类的字段属性public型:肖正文

=======================

本类中声明的方法女

=======================


 

1.检测类:

1.1 reflection的工作机制

import java.lang.reflect.*;

public class DumpMethods {

    public static voidmain(String args[]) {

        try {

            Class c =Class.forName(args[0]);

            Method m[] =c.getDeclaredMethods();

            for (int i = 0; i< m.length; i++)

               System.out.println(m[i].toString());

        } catch (Throwable e){

           System.err.println(e);

        }

    }

}

按如下语句执行:

java DumpMethods java.util.Stack

它的结果输出为:

public java.lang.Object java.util.Stack.push(java.lang.Object)

public synchronized java.lang.Objectjava.util.Stack.pop()

public synchronized java.lang.Objectjava.util.Stack.peek()

public boolean java.util.Stack.empty()

public synchronized intjava.util.Stack.search(java.lang.Object)

这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。

这个程序使用 Class.forName 载入指定的类,然后调用getDeclaredMethods 来获取这个类

中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

  框架应用案例:hibernate

已知有一个user实体(属性id,name,phone)需要被update

我们的解决方式其实很简单:

首先User loadUser = session.load(user.getId); 此时loadUser是持久化的

然后使用loadUser.setXXX(user.getXXX)方法把需要更新的字段set一下

至于怎么判断哪些属性需要更新,我们可以通过反射先获得所有的getXXX方法,然后逐个invoke获得它们的值,判断一下如果值需要更新才执行loadUser.setXX(user.getXXX)

 

 

  框架应用案例之spring IOC

 

  只要用到反射,先获得Class Object

  没有方法能获得当前类的超类的private方法和属性,你必须通过getSuperclass()找到超类以后再去尝试获得

  通常情况即使是当前类,private属性或方法也是不能访问的,你需要 设置压制权限setAccessible(true)来取得private的访问权。但说实话,这已经破坏了面向对象的规则,所以除非万不得已,请尽量少用。


 

 

 

0 0
原创粉丝点击