详解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 反射机制 动态代理的资料请关注我们其它相关文章!

(0)

相关推荐

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

  • 浅析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 反射机制原理与用法.分享给大家供大家参考,具体如下: 反射反射,程序员的快乐! 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动态代理和反射机制详解

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

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

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

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

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

  • 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语言的反射机制.通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以,这是一种动态获取类的信息以及动态调用对象方法的能力. 想要使用反射机制,就必须要先获取到该类

  • 一文详解Java中的类加载机制

    目录 一.前言 二.类加载的时机 2.1 类加载过程 2.2 什么时候类初始化 2.3 被动引用不会初始化 三.类加载的过程 3.1 加载 3.2 验证 3.3 准备 3.4 解析 3.5 初始化 四.父类和子类初始化过程中的执行顺序 五.类加载器 5.1 类与类加载器 5.2 双亲委派模型 5.3 破坏双亲委派模型 六.Java模块化系统 一.前言 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最 终形成可以被虚拟机直接使用的Java类型,这个过程

  • 图文详解Java中的序列化机制

    目录 概述 对象序列化和反序列化机制 修改默认的序列化机制 使用transient关键字 自定义readObject.writeObject方法 实现Externalizable接口 serialVersionUID的作用 使用序列化clone 概述 java中的序列化可能大家像我一样都停留在实现Serializable接口上,对于它里面的一些核心机制没有深入了解过.直到最近在项目中踩了一个坑,就是序列化对象添加一个字段以后,使用方系统报了反序列化失败,原因是我们双方的序列化对象没有加上seri

  • Java中的反射机制详解

    Java中的反射机制详解 反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高! 看概念很晕的,继续往下

  • 详解java中反射机制(含数组参数)

    详解java中反射机制(含数组参数) java的反射是我一直非常喜欢的地方,因为有了这个,可以让程序的灵活性大大的增加,同时通用性也提高了很多.反射原理什么的,我就不想做过大介绍了,网上一搜,就一大把.(下面我是只附录介绍下) Reflection 是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等).superclass(例如O

  • Java中的反射机制示例详解

    目录 反射 什么是Class类 获取Class实例的三种方式 通过反射创建类对象 通过反射获取类属性.方法.构造器 更改访问权限和实例赋值 运用场景 反射 反射就是把Java类中的各个成分映射成一个个的Java对象.即在运行状态中,对于任意一个类,都能够知道这个类的所以属性和方法:对于任意一个对象,都能调用它的任意一个方法和属性.这种动态获取信息及动态调用对象方法的功能叫Java的反射机制 每一个Java程序执行必须通过编译.加载.链接和初始化四个阶段 1.编译:将.java.文件编译成字节码.

  • Java中的反射机制基本运用详解

    目录 Java中的反射机制基本运用 1.什么是反射(reflect) 2.反射机制提供的功能 3.反射->获取类对象 4.反射->利用无参构造实例化对象 5.反射->利用有参构造实例化对象 6.反射->调用无参方法 7.反射->调用有参方法 8.反射->访问私有方法 9.反射->类加载路径 总结 Java中的反射机制基本运用 看完反射可以了解一下注解 注解annotation://www.jb51.net/article/221276.htm 1.什么是反射(re

  • 详解java中各类锁的机制

    目录 前言 1. 乐观锁与悲观锁 2. 公平锁与非公平锁 3. 可重入锁 4. 读写锁(共享锁与独占锁) 6. 自旋锁 7. 无锁 / 偏向锁 / 轻量级锁 / 重量级锁 前言 总结java常见的锁 区分各个锁机制以及如何使用 使用方法 锁名 考察线程是否要锁住同步资源 乐观锁和悲观锁 锁住同步资源后,要不要阻塞 不阻塞可以使用自旋锁 一个线程多个流程获取同一把锁 可重入锁 多个线程公用一把锁 读写锁(写的共享锁) 多个线程竞争要不要排队 公平锁与非公平锁 1. 乐观锁与悲观锁 悲观锁:不能同时

  • 详解Java中的不可变对象

    不可变对象想必大部分朋友都不陌生,大家在平时写代码的过程中100%会使用到不可变对象,比如最常见的String对象.包装器对象等,那么到底为何Java语言要这么设计,真正意图和考虑点是什么?可能一些朋友没有细想过这些问题,今天我们就来聊聊跟不可变对象有关的话题. 一.什么是不可变对象 下面是<Effective Java>这本书对于不可变对象的定义: 不可变对象(Immutable Object):对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化. 从不可变对象的定义来看,

  • 详解Java中自定义注解的使用

    目录 什么是注解 注解的注意事项 注解的本质 自定义注解使用 使用方式 1 使用方式 2 什么是注解 在早期的工作的时候 ,自定义注解写的比较多,可大多都只是因为 这样看起来 不会存在一堆代码耦合在一起的情况,所以使用了自定义注解,这样看起来清晰些, Annontation是Java5开始引入的新特征,中文名称叫注解. 它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类.方法.成员变量等)进行关联.为程序的元素(类.方法.成员变量)加上更直观.更明了的说

随机推荐