Java基础13-深入理解反射机制(二)

简介: Java基础13-深入理解反射机制(二)

Java基础13-深入理解反射机制(一):https://developer.aliyun.com/article/1535685

获取方法

获取某个Class对象的方法集合,主要有以下几个方法:

getDeclaredMethods()方法返回类或接口声明的所有方法,

包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法

public Method[] getDeclaredMethods() throws SecurityException

getMethods()方法返回某个类的所有公用(public)方法,

包括其继承类的公用方法。

public Method[] getMethods() throws SecurityException

getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象

public Method getMethod(String name, Class<?>... parameterTypes)

只是这样描述的话可能难以理解,我们用例子来理解这三个方法:本文中的例子用到了以下这些类,用于反射的测试。

//注解类,可可用于表示方法,可以通过反射获取注解的内容。    //Java注解的实现是很多注框架实现注解配置的基础@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Invoke {}

userbean的父类personbean

public class PersonBean {private String name;int id;public String getName() {    return name;}public void setName(String name) {    this.name = name;}

接口user

public interface User {    public void login ();}

userBean实现user接口,继承personbean

public class UserBean extends PersonBean implements User{    @Override    public void login() {    }    class B {    }    public String userName;    protected int i;    static int j;    private int l;    private long userId;    public UserBean(String userName, long userId) {        this.userName = userName;        this.userId = userId;    }    public String getName() {        return userName;    }    public long getId() {        return userId;    }    @Invoke    public static void staticMethod(String devName,int a) {        System.out.printf("Hi %s, I'm a static method", devName);    }    @Invoke    public void publicMethod() {        System.out.println("I'm a public method");    }    @Invoke    private void privateMethod() {        System.out.println("I'm a private method");    }}

1 getMethods和getDeclaredMethods的区别

public class 动态加载类的反射 {    public static void main(String[] args) {        try {            Class clazz = Class.forName("com.javase.反射.UserBean");            for (Field field : clazz.getDeclaredFields()) {//                field.setAccessible(true);                System.out.println(field);            }            //getDeclaredMethod*()获取的是类自身声明的所有方法,包含public、protected和private方法。            System.out.println("------共有方法------");//        getDeclaredMethod*()获取的是类自身声明的所有方法,包含public、protected和private方法。//            getMethod*()获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。            for (Method method : clazz.getMethods()) {                String name = method.getName();                System.out.println(name);                //打印出了UserBean.java的所有方法以及父类的方法            }            System.out.println("------独占方法------");            for (Method method : clazz.getDeclaredMethods()) {                String name = method.getName();                System.out.println(name);            }        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}

2 打印一个类的所有方法及详细信息:

public class 打印所有方法 {    public static void main(String[] args) {        Class userBeanClass = UserBean.class;        Field[] fields = userBeanClass.getDeclaredFields();        //注意,打印方法时无法得到局部变量的名称,因为jvm只知道它的类型        Method[] methods = userBeanClass.getDeclaredMethods();        for (Method method : methods) {            //依次获得方法的修饰符,返回类型和名称,外加方法中的参数            String methodString = Modifier.toString(method.getModifiers()) + " " ; // private static            methodString += method.getReturnType().getSimpleName() + " "; // void            methodString += method.getName() + "("; // staticMethod            Class[] parameters = method.getParameterTypes();            Parameter[] p = method.getParameters();            for (Class parameter : parameters) {                methodString += parameter.getSimpleName() + " " ; // String            }            methodString += ")";            System.out.println(methodString);        }        //注意方法只能获取到其类型,拿不到变量名/*        public String getName()        public long getId()        public static void staticMethod(String int )        public void publicMethod()        private void privateMethod()*/    }}

获取构造器信息

获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例:

public class 打印构造方法 {    public static void main(String[] args) {        // constructors        Class<?> clazz = UserBean.class;        Class userBeanClass = UserBean.class;        //获得所有的构造方法        Constructor[] constructors = userBeanClass.getDeclaredConstructors();        for (Constructor constructor : constructors) {            String s = Modifier.toString(constructor.getModifiers()) + " ";            s += constructor.getName() + "(";            //构造方法的参数类型            Class[] parameters = constructor.getParameterTypes();            for (Class parameter : parameters) {                s += parameter.getSimpleName() + ", ";            }            s += ")";            System.out.println(s);            //打印结果//public com.javase.反射.UserBean(String, long, )        }    }}

获取类的成员变量(字段)信息

主要是这几个方法,在此不再赘述:

getFiled: 访问公有的成员变量 getDeclaredField:所有已声明的成员变量。但不能得到其父类的成员变量 getFileds和getDeclaredFields用法同上(参照Method)

public class 打印成员变量 {    public static void main(String[] args) {        Class userBeanClass = UserBean.class;        //获得该类的所有成员变量,包括static private        Field[] fields = userBeanClass.getDeclaredFields();        for(Field field : fields) {            //private属性即使不用下面这个语句也可以访问//            field.setAccessible(true);            //因为类的私有域在反射中默认可访问,所以flag默认为true。            String fieldString = "";            fieldString += Modifier.toString(field.getModifiers()) + " "; // `private`            fieldString += field.getType().getSimpleName() + " "; // `String`            fieldString += field.getName(); // `userName`            fieldString += ";";            System.out.println(fieldString);                        //打印结果//            public String userName;//            protected int i;//            static int j;//            private int l;//            private long userId;        }    }}

调用方法

当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为:

public Object invoke(Object obj, Object... args)        throws IllegalAccessException, IllegalArgumentException,           InvocationTargetException       public class 使用反射调用方法 {    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {        Class userBeanClass = UserBean.class;        //获取该类所有的方法,包括静态方法,实例方法。        //此处也包括了私有方法,只不过私有方法在用invoke访问之前要设置访问权限        //也就是使用setAccessible使方法可访问,否则会抛出异常//       // IllegalAccessException的解释是//        * An IllegalAccessException is thrown when an application tries// * to reflectively create an instance (other than an array),// * set or get a field, or invoke a method, but the currently// * executing method does not have access to the definition of// * the specified class, field, method or constructor.//        getDeclaredMethod*()获取的是类自身声明的所有方法,包含public、protected和private方法。//            getMethod*()获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。        //就是说,当这个类,域或者方法被设为私有访问,使用反射调用但是却没有权限时会抛出异常。        Method[] methods = userBeanClass.getDeclaredMethods(); // 获取所有成员方法        for (Method method : methods) {            //反射可以获取方法上的注解,通过注解来进行判断            if (method.isAnnotationPresent(Invoke.class)) { // 判断是否被 @Invoke 修饰                //判断方法的修饰符是是static                if (Modifier.isStatic(method.getModifiers())) { // 如果是 static 方法                    //反射调用该方法                    //类方法可以直接调用,不必先实例化                    method.invoke(null, "wingjay",2); // 直接调用,并传入需要的参数 devName                } else {                    //如果不是类方法,需要先获得一个实例再调用方法                    //传入构造方法需要的变量类型                    Class[] params = {String.class, long.class};                    //获取该类指定类型的构造方法                    //如果没有这种类型的方法会报错                    Constructor constructor = userBeanClass.getDeclaredConstructor(params); // 获取参数格式为 String,long 的构造函数                    //通过构造方法的实例来进行实例化                    Object userBean = constructor.newInstance("wingjay", 11); // 利用构造函数进行实例化,得到 Object                    if (Modifier.isPrivate(method.getModifiers())) {                        method.setAccessible(true); // 如果是 private 的方法,需要获取其调用权限//                        Set the {@code accessible} flag for this object to//     * the indicated boolean value.  A value of {@code true} indicates that//     * the reflected object should suppress Java language access//     * checking when it is used.  A value of {@code false} indicates//                                * that the reflected object should enforce Java language access checks.                        //通过该方法可以设置其可见或者不可见,不仅可以用于方法                        //后面例子会介绍将其用于成员变量                                            //打印结果//            I'm a public method// Hi wingjay, I'm a static methodI'm a private method                    }                    method.invoke(userBean); // 调用 method,无须参数                                                        }            }        }    }}

利用反射创建数组

数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。下面我们看一看利用反射创建数组的例子:

public class 用反射创建数组 {    public static void main(String[] args) {        Class<?> cls = null;        try {            cls = Class.forName("java.lang.String");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        Object array = Array.newInstance(cls,25);        //往数组里添加内容        Array.set(array,0,"hello");        Array.set(array,1,"Java");        Array.set(array,2,"fuck");        Array.set(array,3,"Scala");        Array.set(array,4,"Clojure");        //获取某一项的内容        System.out.println(Array.get(array,3));        //Scala    }}

其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象,它的原型是:

public static Object newInstance(Class<?> componentType, int length)        throws NegativeArraySizeException {        return newArray(componentType, length);    }

而newArray()方法是一个Native方法,它在Hotspot JVM里的具体实现我们后边再研究,这里先把源码贴出来

private static native Object newArray(Class<?> componentType, int length)        throws NegativeArraySizeException;

Java反射常见面试题

什么是反射?

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

哪里用到反射机制?

JDBC中,利用反射动态加载了数据库驱动程序。Web服务器中利用反射调用了Sevlet的服务方法。Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。很多框架都用到反射机制,注入属性,调用方法,如Spring。

什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作?

对象序列化,将对象中的数据编码为字节序列的过程。反序列化;将对象的编码字节重新反向解码为对象的过程。JAVA提供了API实现了对象的序列化和反序列化的功能,使用这些API时需要遵守如下约定:被序列化的对象类型需要实现序列化接口,此接口是标志接口,没有声明任何的抽象方法,JAVA编译器识别这个接口,自动的为这个类添加序列化和反序列化方法。为了保持序列化过程的稳定,建议在类中添加序列化版本号。不想让字段放在硬盘上就加transient 以下情况需要使用 Java 序列化:想把的内存中的对象状态保存到一个文件中或者数据库中时候;想用套接字在网络上传送对象的时候;想通过RMI(远程方法调用)传输对象的时候。

反射机制的优缺点?

优点:可以动态执行,在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性。缺点:对性能有影响,这类操作总是慢于直接执行java代码。

动态代理是什么?有哪些应用?

动态代理是运行时动态生成代理类。动态代理的应用有 Spring AOP数据查询、测试框架的后端 mock、rpc,Java注解对象获取等。

怎么实现动态代理?

JDK 原生动态代理和 cglib 动态代理。JDK 原生动态代理是基于接口实现的,而 cglib 是基于继承当前类的子类实现的。

Java反射机制的作用

在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任意一个对象的方法

如何使用Java的反射?

通过一个全限类名创建一个对象

Class.forName(“全限类名”); 例如:com.mysql.jdbc.Driver Driver类已经被加载到 jvm中,并且完成了类的初始化工作就行了 类名.class; 获取Class<?> clz 对象 对象.getClass();

获取构造器对象,通过构造器new出一个对象

Clazz.getConstructor([String.class]); Con.newInstance([参数]); 通过class对象创建一个实例对象(就相当与new类名()无参构造器) Cls.newInstance();

通过class对象获得一个属性对象

Field c=cls.getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。Field c=cls.getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的声明字段

通过class对象获得一个方法对象

Cls.getMethod(“方法名”,class……parameaType);(只能获取公共的) Cls.getDeclareMethod(“方法名”);(获取任意修饰的方法,不能执行私有) M.setAccessible(true);(让私有的方法可以执行) 让方法执行 1). Method.invoke(obj实例对象,obj可变参数);-----(是有返回值的)

目录
相关文章
|
2天前
|
监控 安全 Java
Java面试题:描述Java反射机制及其应用场景,并讨论其优缺点。
Java面试题:描述Java反射机制及其应用场景,并讨论其优缺点。
11 1
|
5天前
|
Java 程序员 测试技术
解析Java中的反射机制及其应用场景
解析Java中的反射机制及其应用场景
|
9天前
|
缓存 Java 测试技术
Java中的反射机制及其应用场景
Java中的反射机制及其应用场景
|
9天前
|
存储 安全 Java
Java中的反射机制及其应用场景详解
Java中的反射机制及其应用场景详解
|
3天前
|
Java API
Java注解与反射机制
Java注解与反射概述: - 注解用于元数据,包括元注解`@Target`, `@Retention`, `@Documented`, `@Inherited`。 - 自定义注解用于自定义行为标记,参考[链接]例化后通过`getClass()`获取类信息。 - 主要API涉及类的多种获取方式,如`对象.getClass()`, `类名.class`, `Class.forName()`和内置类型`TYPE`。 - 应用场景包括动态创建对象,获取泛型和注解信息以及分析运行时结构。
|
4天前
|
Java 程序员 测试技术
解析Java中的反射机制及其应用场景
解析Java中的反射机制及其应用场景
|
4天前
|
缓存 Java 测试技术
Java中的反射机制及其应用场景
Java中的反射机制及其应用场景
|
1月前
|
Oracle IDE Java
Java基础13-深入理解反射机制(一)
Java基础13-深入理解反射机制(一)
25 5
|
12天前
|
Java
解析Java中的反射机制应用
解析Java中的反射机制应用
|
12天前
|
设计模式 缓存 Java
Java中的反射机制:使用场景与注意事项
Java中的反射机制:使用场景与注意事项