详解Java中的反射机制和动态代理

一、反射概述

反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以,这是一种动态获取类的信息以及动态调用对象方法的能力。

想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过该类的字节码对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。

Java提供的反射机制,依赖于我们下面要讲到的Class类和java.lang.reflect类库。我们下面要学习使用的主要类有:①Class表示类或者接口;②java.lang.reflect.Field表示类中的成员变量;③java.lang.reflect.Method表示类中的方法;④java.lang.reflect.Constructor表示类的构造方法;⑤Array提供动态数组的创建和访问数组的静态方法。

二、反射之Class类

2.1、初识Class类

在类Object下面提供了一个方法:

public final native Class<?> getClass()

此方法将会被所有的子类继承,该方法的返回值为一个Class,这个Class类就是反射的源头。那么Class类是什么呢?Class类是Java中用来表达运行时类型信息的对应类,我们刚刚也说过所有类都会继承Object类的getClass()方法,那么也体现了着Java中的每个类都有一个Class对象,当我们编写并编译一个创建的类就会产生对应的class文件并将类的信息写到该class文件中,当我们使用正常方式new一个对象或者使用类的静态字段时候,JVM的累加器子系统就会将对应的Class对象加载到JVM中,然后JVM根据这个类型信息相关的Class对象创建我们需要的实例对象或者根据提供静态变量的引用值。将Class类称为类的类型,一个Class对象称为类的类型对象。

2.2、Class有下面的几个特点

①Class也是类的一种(不同于class,class是一个关键字);

②Class类只有一个私有的构造函数

private Class(ClassLoader loader)

只有JVM能够创建Class类的实例;

③对于同一类的对象,在JVM中只存在唯一一个对应的Class类实例来描述其信息;

④每个类的实例都会记得自己是由哪个Class实例所生成;

⑤通过Class可以完整的得到一个类中的完整结构;

2.3、获取Class类实例

刚刚说到过Class只有一个私有的构造函数,所以我们不能通过new创建Class实例,有下面这几种获取Class实例的方法:

①Class.forName("类的全限定名"),该方法只能获取引用类型的类类型对象。该方法会抛出异常(a.l类加载器在类路径中没有找到该类 b.该类被某个类加载器加载到JVM内存中,另外一个类加载器有尝试从同一个包中加载)

//Class<T> clazz = Class.forName("类的全限定名");这是通过Class类中的静态方法forName直接获取一个Class的对象
Class<?> clazz1 = null;
try {
    clazz1 = Class.forName("reflect.Person");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
System.out.println(clazz1); //class reflect.Person

②如果我们有一个类的对象实例,那么通过这个对象的getClass()方法可以获得他的Class对象,如下所示

//Class<T> clazz = xxx.getClass(); //通过类的实例获取类的Class对象
Class<?> clazz3 = new Person().getClass();
System.out.println(clazz3); //class reflect.Person

Class<?> stringClass = "string".getClass();
System.out.println(stringClass); //class java.lang.String

/**
 * [代表数组,
 * B代表byte;
 * I代表int;
 * Z代表boolean;
 * L代表引用类型
 * 组合起来就是指定类型的一维数组,如果是[[就是二维数组
 */
Class<?> arrClass = new byte[20].getClass();
System.out.println(arrClass); //class [B

Class<?> arrClass1 = new int[20].getClass();
System.out.println(arrClass1); //class [I

Class<?> arrClass2 = new boolean[20].getClass();
System.out.println(arrClass2); //class [Z

Class<?> arrClass3 = new Person[20].getClass();
System.out.println(arrClass3); //class [Lreflect.Person;

Class<?> arrClass4 = new String[20].getClass();
System.out.println(arrClass4); //class [Ljava.lang.String;

③通过类的class字节码文件获取,通过类名.class获取该类的Class对象

//Class<T> clazz = XXXClass.class; 当类已经被加载为.class文件时候,
Class<Person> clazz2 = Person.class;
System.out.println(clazz2);
System.out.println(int [][].class);//class [[I
System.out.println(Integer.class);//class java.lang.Integer

2.4、关于包装类的静态属性

我们知道,在Java中对于基本类型和void都有对应的包装类。在包装类中有一个静态属性TYPE保存了该类的类类型。如下所示

/**
     * The {@code Class} instance representing the primitive type
     * {@code int}.
     *
     * @since   JDK1.1
     */
    @SuppressWarnings("unchecked")
    public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");

我们使用这个静态属性来获得Class实例,如下所示

Class c0 = Byte.TYPE; //byte
Class c1 = Integer.TYPE; //int
Class c2 = Character.TYPE; //char
Class c3 = Boolean.TYPE; //boolean
Class c4 = Short.TYPE; //short
Class c5 = Long.TYPE; //long
Class c6 = Float.TYPE; //float
Class c7 = Double.TYPE; //double
Class c8 = Void.TYPE; //void

2.5、通过Class类的其他方法获取

①public native Class<? super T> getSuperclass():获取该类的父类

Class c1 = Integer.class;
Class par = c1.getSuperclass();
System.out.println(par); //class java.lang.Number

②public Class<?>[] getClasses():获取该类的所有公共类、接口、枚举组成的Class数组,包括继承的;

③public Class<?>[] getDeclaredClasses():获取该类的显式声明的所有类、接口、枚举组成的Class数组;

④(Class/Field/Method/Constructor).getDeclaringClass():获取该类/属性/方法/构造器所在的类

三、Class类的API

这是下面测试用例中使用的Person类和实现的接口

package reflect;

interface Test {
    String test = "interface";
}

public class Person  implements Test{

    private String id;
    private String name;

    public void sing(String name) {
        System.out.println(getName() + "会唱" + name +"歌");
    }

    private void dance(String name) {
        System.out.println(getName() + "会跳" + name + "舞");
    }

    public void playBalls() {
        System.out.println(getName() + "会打篮球");
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person() {
    }

    public Person(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public Person(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}
//Person

3.1、创建实例对象

public void test4() throws Exception{
    Class clazz =Class.forName("reflect.Person");
    Person person = (Person)clazz.newInstance();
    System.out.println(person);
}

创建运行时类的对象,使用newInstance(),实际上就是调用运行时指定类的无参构造方法。这里也说明要想创建成功,需要对应的类有无参构造器,并且构造器的权限要足够,否则会抛出下面的异常。

①我们显示声明Person类一个带参构造,并没有无参构造,这种情况会抛出InstantiationException

②更改无参构造器访问权限为private

3.2、获取构造器

(1)获取指定可访问的构造器创建对象实例

上面我们所说的使用newInstance方法创建对象,如果不指定任何参数的话默认是调用指定类的无参构造器的。那么如果没有无参构造器,又想创建对象实例怎么办呢,就使用Class类提供的获取构造器的方法,显示指定我们需要调用哪一个无参构造器。

@Test
public void test5() throws Exception {
    Class clazz = Class.forName("reflect.Person");
    //获取带参构造器
    Constructor constructor = clazz.getConstructor(String.class, String .class);
    //通过构造器来实例化对象
    Person person = (Person) constructor.newInstance("p1", "person");
    System.out.println(person);
}

当我们指定的构造器全部不够(比如设置为private),我们在调用的时候就会抛出下面的异常

(2)获得全部构造器

@Test
public void test6() throws Exception {
    Class clazz1 = Class.forName("reflect.Person");
    Constructor[] constructors = clazz1.getConstructors();
    for (Constructor constructor : constructors) {
        Class[] parameters = constructor.getParameterTypes();
        System.out.println("构造函数名:" + constructor + "\n" + "参数");
        for (Class c: parameters) {
            System.out.print(c.getName() + " ");
        }
        System.out.println();
    }
}

运行结果如下

  

3.3、获取成员变量并使用Field对象的方法

(1)Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(对象引用,属性值)方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(对象引用)可以获取指定对象中该字段的值。

@Test
public void test7() throws Exception {
    Class clazz1 = Class.forName("reflect.Person");
    //获得实例对象
    Person person = (Person) clazz1.newInstance();
    /**
     * 获得类的属性信息
     * 使用getField(name),通过指定的属性name获得
     * 如果属性不是public的,使用getDeclaredField(name)获得
     */
    Field field = clazz1.getDeclaredField("id");
    //如果是private的,需要设置权限为可访问
    field.setAccessible(true);
    //设置成员变量的属性值
    field.set(person, "person1");
    //获取成员变量的属性值,使用get方法,其中第一个参数表示获得字段的所属对象,第二个参数表示设置的值
    System.out.println(field.get(person)); //这里的field就是id属性,打印person对象的id属性的值
}

(2)获得全部成员变量

@Test
public void test8() throws Exception{
    Class clazz1 = Class.forName("reflect.Person");
    //获得实例对象
    Person person = (Person) clazz1.newInstance();
    person.setId("person1");
    person.setName("person1_name");
    Field[] fields = clazz1.getDeclaredFields();
    for (Field f : fields) {
        //打开private成员变量的可访问权限
        f.setAccessible(true);
        System.out.println(f+ ":" + f.get(person));
    }
}

  

3.4、获取方法并使用method

(1)使用Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,如果为私有方法,则需要打开一个权限。setAccessible(true);用invoke(Object, Object...)可以调用该方法。如果是私有方法而使用的是getMethod方法来获得会抛出NoSuchMethodException

@Test
public void test9() throws Exception{
    Class clazz1 = Class.forName("reflect.Person");
    //获得实例对象
    Person person = (Person) clazz1.newInstance();
    person.setName("Person");
    //①不带参数的public方法
    Method playBalls = clazz1.getMethod("playBalls");
    //调用获得的方法,需要指定是哪一个对象的
    playBalls.invoke(person);

    //②带参的public方法:第一个参数是方法名,后面的可变参数列表是参数类型的Class类型
    Method sing = clazz1.getMethod("sing",String.class);
    //调用获得的方法,调用时候传递参数
    sing.invoke(person,"HaHaHa...");

    //③带参的private方法:使用getDeclaredMethod方法
    Method dance = clazz1.getDeclaredMethod("dance", String.class);
    //调用获得的方法,需要先设置权限为可访问
    dance.setAccessible(true);
    dance.invoke(person,"HaHaHa...");
}

(2)获得所有方法(不包括构造方法)

@Test
public void test10() throws Exception{
    Class clazz1 = Class.forName("reflect.Person");
    //获得实例对象
    Person person = (Person) clazz1.newInstance();
    person.setName("Person");
    Method[] methods = clazz1.getDeclaredMethods();
    for (Method method: methods) {
        System.out.print("方法名" + method.getName() + "的参数是:");
        //获得方法参数
        Class[] params = method.getParameterTypes();
        for (Class c : params) {
            System.out.print(c.getName() + " ");
        }
        System.out.println();
    }
}

3.5、获得该类的所有接口

Class[] getInterfaces():确定此对象所表示的类或接口实现的接口,返回值:接口的字节码文件对象的数组

@Test
public void test11() throws Exception{
    Class clazz1 = Class.forName("reflect.Person");
    Class[] interfaces = clazz1.getInterfaces();
    for (Class inter : interfaces) {
        System.out.println(inter);
    }
}

3.6、获取指定资源的输入流

InputStreamgetResourceAsStream(String name),返回值:一个 InputStream 对象;如果找不到带有该名称的资源,则返回null;参数:所需资源的名称,如果以"/"开始,则绝对资源名为"/"后面的一部分。

@Test
public void test12() throws Exception {
    ClassLoader loader = this.getClass().getClassLoader();
    System.out.println(loader);//sun.misc.Launcher$AppClassLoader@18b4aac2 ,应用程序类加载器
    System.out.println(loader.getParent());//sun.misc.Launcher$ExtClassLoader@31befd9f ,扩展类加载器
    System.out.println(loader.getParent().getParent());//null ,不能获得启动类加载器

    Class clazz = Person.class;//自定义的类
    ClassLoader loader2 = clazz.getClassLoader();
    System.out.println(loader2);//sun.misc.Launcher$AppClassLoader@18b4aac2

    //下面是获得InputStream的例子
    ClassLoader inputStreamLoader = this.getClass().getClassLoader();
    InputStream inputStream = inputStreamLoader.getResourceAsStream("person.properties");
    Properties properties = new Properties();
    properties.load(inputStream);
    System.out.println("id:" + properties.get("id"));
    System.out.println("name:" + properties.get("name"));
}

其中properties文件内容

id = person001

name = person-name1

四、反射的应用之动态代理

代理模式在Java中应用十分广泛,它说的是使用一个代理将对象包装起来然后用该代理对象取代原始对象,任何原始对象的调用都需要通过代理对象,代理对象决定是否以及何时将方法调用转到原始对象上。这种模式可以这样简单理解:你自己想要做某件事情(被代理类),但是觉得自己做非常麻烦或者不方便,所以就叫一个另一个人(代理类)来帮你做这个事情,而你自己只需要告诉要做啥事就好了。上面我们讲到了反射,在下面我们会说一说java中的代理

4.1、静态代理

静态代理其实就是程序运行之前,提前写好被代理类的代理类,编译之后直接运行即可起到代理的效果,下面会用简单的例子来说明。在例子中,首先我们有一个顶级接口(ProductFactory),这个接口需要代理类(ProxyTeaProduct)和被代理类(TeaProduct)都去实现它,在被代理类中我们重写需要实现的方法(action),该方法会交由代理类去选择是否执行和在何处执行;被代理类中主要是提供顶级接口的的一个引用但是引用实际指向的对象则是实现了该接口的代理类(使用多态的特点,在代理类中提供构造器传递实际的对象引用)。分析之后,我们通过下面这个图理解一下这个过程。

package proxy;

/**
 * 静态代理
 */
//产品接口
interface ProductFactory {
    void action();
}

//一个具体产品的实现类,作为一个被代理类
class TeaProduct implements ProductFactory{
    @Override
    public void action() {
        System.out.println("我是生产茶叶的......");
    }
}

//TeaProduct的代理类
class ProxyTeaProduct implements ProductFactory {
    //我们需要ProductFactory的一个实现类,去代理这个实现类中的方法(多态)
    ProductFactory productFactory;

    //通过构造器传入实际被代理类的对象,这时候代理类调用action的时候就可以在其中执行被代理代理类的方法了
    public ProxyTeaProduct(ProductFactory productFactory) {
        this.productFactory = productFactory;
    }

    @Override
    public void action() {
        System.out.println("我是代理类,我开始代理执行方法了......");
        productFactory.action();
    }
}
public class TestProduct {

    public static void main(String[] args) {
        //创建代理类的对象
        ProxyTeaProduct proxyTeaProduct = new ProxyTeaProduct(new TeaProduct());
        //执行代理类代理的方法
        proxyTeaProduct.action();
    }
}

那么程序测试的输出结果也很显然了,代理类执行自己实现的方法,而在其中有调用了被代理类的方法

  

那么我们想一下,上面这种称为静态代理的方式有什么缺点呢?因为每一个代理类只能为一个借口服务(因为这个代理类需要实现这个接口,然后去代理接口实现类的方法),这样一来程序中就会产生过多的代理类。比如说我们现在又来一个接口,那么是不是也需要提供去被代理类去实现它然后交给代理类去代理执行呢,那这样程序就不灵活了。那么如果有一种方式,就可以处理新添加接口的以及实现那不就更加灵活了吗,在java中反射机制的存在为动态代理创造了机会

4.2、JDK中的动态代理

动态代理是指通过代理类来调用它对象的方法,并且是在程序运行使其根据需要创建目标类型的代理对象。它只提供一个代理类,我们只需要在运行时候动态传递给需要他代理的对象就可以完成对不同接口的服务了。看下面的例子。(JDK提供的代理正能针对接口做代理,也就是下面的newProxyInstance返回的必须要是一个接口)

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK中的动态代理
 */
//第一个接口
interface TargetOne {
    void action();
}
//第一个接口的被代理类
class TargetOneImpl implements TargetOne{
    @Override
    public void action() {
        System.out.println("我会实现父接口的方法...action");
    }
}

//动态代理类
class DynamicProxyHandler implements InvocationHandler {
    //接口的一个引用,多态的特性会使得在程序运行的时候,它实际指向的是实现它的子类对象
    private TargetOne targetOne;
    //我们使用Proxy类的静态方法newProxyInstance方法,将代理对象伪装成那个被代理的对象
    /**
     * ①这个方法会将targetOne指向实际实现接口的子类对象
     * ②根据被代理类的信息返回一个代理类对象
     */
    public Object setObj(TargetOne targetOne) {
        this.targetOne = targetOne;
        //    public static Object newProxyInstance(ClassLoader loader, //被代理类的类加载器
        //                                          Class<?>[] interfaces, //被代理类实现的接口
        //                                          InvocationHandler h) //实现InvocationHandler的代理类对象
        return Proxy.newProxyInstance(targetOne.getClass().getClassLoader(),targetOne.getClass().getInterfaces(),this);
    }
    //当通过代理类的对象发起对接口被重写的方法的调用的时候,都会转换为对invoke方法的调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("这是我代理之前要准备的事情......");
        /**
         *      这里回想一下在静态代理的时候,我们显示指定代理类需要执行的是被代理类的哪些方法;
         *      而在这里的动态代理实现中,我们并不知道代理类会实现什么方法,他是根据运行时通过反射来
         *  知道自己要去指定被代理类的什么方法的
         */
        Object returnVal = method.invoke(this.targetOne,args);//这里的返回值,就相当于真正调用的被代理类方法的返回值
        System.out.println("这是我代理之后要处理的事情......");
        return returnVal;
    }
}
public class TestProxy {
    public static void main(String[] args) {
        //创建被代理类的对象
        TargetOneImpl targetOneImpl = new TargetOneImpl();
        //创建实现了InvocationHandler的代理类对象,然后调用其中的setObj方法完成两项操作
        //①将被代理类对象传入,运行时候调用的是被代理类重写的方法
        //②返回一个类对象,通过代理类对象执行接口中的方法
        DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
        TargetOne targetOne = (TargetOne) dynamicProxyHandler.setObj(targetOneImpl);
        targetOne.action(); //调用该方法运行时都会转为对DynamicProxyHandler中的invoke方法的调用
    }
}

运行结果如下。现在我们对比jdk提供的动态代理和我们刚刚实现的静态代理,刚刚说到静态代理对于新添加的接口需要定义对应的代理类去代理接口的实现类。而上面的测试程序所使用的动态代理规避了这个问题,即我们不需要显示的指定每个接口对应的代理类,有新的接口添加没有关系,只需要在使用的时候传入接口对应的实现类然后返回代理类对象(接口实现类型),然后调用被代理类的方法即可。

  

五、动态代理与AOP简单实现

5.1、AOP是什么

AOP(Aspect Orient Programming)我们一般称之为面向切面编程,作为一种面向对象的补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志记录等。AOP实现的关键在于AOP的代理(实际实现上有静态代理和动态代理),我们下面使用JDK的动态代理的方式模拟实现下面的场景。

5.2、模拟实现AOP

我们先考虑下面图中的情况和说明。然后我们使用动态代理的思想模拟简单实现一下这个场景

package aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//基于jdk的针对接口实现动态代理,要求的接口
interface Target {
    void login();

    void logout();
}

//被代理类
class TargetImpl implements Target {
    @Override
    public void login() {
        System.out.println("log......");
    }

    @Override
    public void logout() {
        System.out.println("logout......");
    }
}

class Util {
    public void printLog() {
        System.out.println("我是记录打印日志功能的方法......");
    }

    public void getProperties() {
        System.out.println("我是获取配置文件信息功能的方法......");
    }
}

//实现了InvocationHandler的统一代理类
class DynamicProxyHandler implements InvocationHandler {
    private Object object;

    /**
     * 参数为obj,是应对对不同的被代理类,都能绑定与该代理类的代理关系
     * 这个方法会将targetOne指向实际实现接口的子类对象,即当前代理类实际要去代理的那个类
     */
    public void setObj(Object obj) {
        this.object = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Util util = new Util();
        util.getProperties();
        Object object = method.invoke(this.object, args); //这个方法是个动态的方法,可以是login,可以是logout,具体在测试调用中调用不同方法
        util.printLog();
        return object;
    }
}

//该类的主要作用就是动态的创建一个代理类的对象,同时需要执行被代理类
class MyDynamicProxyUtil {
    //参数obj表示动态的传递进来被代理类的对象
    public static Object getProxyInstance(Object object) {
        //获取代理类对象
        DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
        dynamicProxyHandler.setObj(object);
        //设置好代理类与被代理类之间的关系后,返回一个代理类的对象
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), dynamicProxyHandler);
    }
}

public class TestAop {
    public static void main(String[] args) {
        //获得被代理类
        Target target = new TargetImpl();
        //通过代理类工具类,设置实际与代理类绑定的被代理类,并返回一个代理类对象执行实际的方法
        Target execute = (Target) MyDynamicProxyUtil.getProxyInstance(target);
        execute.login();
        execute.logout();
    }
}

现在来分析一下上面的代码,首先我们看一下下面的这个图。在图中动态代理增加的通用日志方法、配置文件方法就是增加的方法,他在执行用户实际自己开发的方法之前、之后调用。对应于上面的程序就是Target接口的实现类实现的login、logout方法被代理类动态的调用,在他们执行之前会调用日志模块和配置文件模块的功能。

以上就是详解Java中的反射机制和动态代理的详细内容,更多关于Java 反射机制 动态代理的资料请关注我们其它相关文章!

时间: 2021-06-10

浅析Java 反射机制的用途和缺点

反射的用途 Uses of Reflection Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by

Java动态代理和反射机制详解

反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). 静态代理 预先(编译期间)确定了代理者与被代理者之间的关系,也就是说,若代理类在程序运行前就已经存在了,这种情况就叫静态代理 动态代理 代理类在程序运行时创建的代理方式.也就是说,代理类并不是在Java代码中定义的,而是在运行期间根据我们在Java代码中的"指示"动态生成的. 动态代理比

实例讲解Java中动态代理和反射机制

反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). 静态代理 预先(编译期间)确定了代理者与被代理者之间的关系,也就是说,若代理类在程序运行前就已经存在了,这种情况就叫静态代理 动态代理 代理类在程序运行时创建的代理方式.也就是说,代理类并不是在Java代码中定义的,而是在运行期间根据我们在Java代码中的"指示"动态生成的. 动态代理比

浅谈Java注解和动态代理

本文主要介绍Java中与注解和动态代理有关的部分知识,接下来我们看看具体内容. Annotation(注解) 其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行. 1. 三个基本的Annotation: Override:限定重写父类方法, 该注解只能用于方法 Deprecated:用于表示某个程序元素(类, 方法等)已过时 SuppressWarnings:抑制编译器警告. 2.自定义Annotati

java反射机制根据属性名获取属性值的操作

一.考虑安全访问范围内的属性,没有权限访问到的属性不读取 /** * 根据属性名获取属性值 * * @param fieldName * @param object * @return */ private String getFieldValueByFieldName(String fieldName, Object object) { try { Field field = object.getClass().getField(fieldName); //设置对象的访问权限,保证对priva

Java基于反射机制实现全部注解获取的方法示例

本文实例讲述了Java基于反射机制实现全部注解获取的方法.分享给大家供大家参考,具体如下: 一 代码 class Info{ //给mytoString方法加了2个内建Annotation @Deprecated @SuppressWarnings(value = "This is a waring!") public String mytoString(){ return "hello world"; } } class GetAnnotations{ publi

Java 反射机制原理与用法详解

本文实例讲述了Java 反射机制原理与用法.分享给大家供大家参考,具体如下: 反射反射,程序员的快乐! 1.什么是反射? Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:并且能改变它的属性.而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是

Java中反射动态代理接口的详解及实例

Java语言中反射动态代理接口的解释与演示 Java在JDK1.3的时候引入了动态代理机制.可以运用在框架编程与平台编程时候捕获事件.审核数据.日志等功能实现,首先看一下设计模式的UML图解: 当你调用一个接口API时候,实际实现类继承该接口,调用时候经过proxy实现. 在Java中动态代理实现的两个关键接口类与class类分别如下: java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 我们下面就通过InvocationHan

java反射机制给实体类相同字段自动赋值实例

一.封装一个工具类 1.简易版 package net.aexit.construct.acceptance.websky.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class ClassReflection { /** * @par

深入浅析Java反射机制

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制.反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩.当然反射本身并不是一个新概念,它可能会使我们联想到光

利用Java反射机制实现对象相同字段的复制操作

一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档),我采用POJO来对应数据表结构,使用VO来给传递前端要展示的数据,同时使用DTO来进行请求参数的封装.以上是一个具体的场景,可以发现这样子一个现象:POJO.VO.DTO对象是同一个数据的不同视图,所以会有很多相同的字段,由于不同的地方使用不同的对象,无可避免的会存在对象之间的值迁移问题,迁移的一

java 利用java反射机制动态加载类的简单实现

如下所示: ////////////////// Load.java package org.bromon.reflect; import java.util.ArrayList; import java.util.List; public class Load implements Operator { @Override public List<?> act(List<?> params) { // TODO Auto-generated method stub List<

利用java反射机制调用类的私有方法(推荐)

试想一下,如果你可以轻易地调用一个类的私有方法,那么是不是说你的封装都失效了?最近在看java的反射机制,发现居然可以利用java的反射机制去调用其他类的私有方法,至于这能干什么,那就见人见智了.. 我写的一段简易实例代码如下: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author thomaslwq * @version 创建时间:Sep 4, 201

利用java反射机制实现自动调用类的简单方法

1. 新建TestServlet类 package com.yanek.test; import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.ht

Java反射机制概念、原理与用法总结

本文实例讲述了Java反射机制概念.原理与用法.分享给大家供大家参考,具体如下: 反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 反射机制能做什么 反射机制主要提供了以下功能: ① 在运行时判断任意一个对象所属的类: ② 在运行时构造任意一个类的对象: ③ 在运行时判断任意一个类所具有的成员变量和方法: ④ 在运行时调用任意一个

Java 反射机制实例详解

Java 反射机制实例详解 一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,Java和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反射.通过反射,Java可以于运行时加载.探知和使用编译期间完全求和的类.生成其对象实体,调用其方法或者对属性设值.所以Java算是一个半动态的语言吧. 反射的概念: 在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对

Java反射机制的实现详解

很多主流框架都使用了反射技术.像ssh框架都采用两种技术 xml做配置文件+反射技术. 与反射有关的类包. java.lang.reflect.*;和java.lang.Class; Java中所有类型(包括基本类型)都对应一个Class对象,这个Class就是java.lang.Class.即每一个类型,在Class中都有一个Class对象跟它对应.Class 没有公共构造方法.注意不是没有,是没有公共的. 如何获得Class对象 复制代码 代码如下: .针对每一个对象.getCalss(),

Java反射机制的学习总结

一.什么是反射机制 简单的来说,反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息. 二.哪里用到反射机制 有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码, Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成驱动对象实例,并不知道它的具体含义.听了反射机制这节课后,才知道,原来这