Java 动态性

本文介绍了Java的动态性,包括反射机制,如何动态加载类、创建对象、调用方法等;字节码操作,如Javassist、CGLIB,用于提高性能;以及代理,探讨了静态代理和JDK动态代理的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态性

Java本质为静态语言,而不是动态语言。动态语言显著的特点是在程序运行时,可以改变程序结构或变量类型,典型的动态语言有Python、ruby、javascript等。Java不是动态语言,但Java具有一定的动态性,表现在以下几个方面:

l  反射机制;

l  动态字节码操作;

l  动态编译;

l  执行其他脚本代码;

下面我们将介绍反射机制和动态字节码操作等内容。

1、       反射机制

反射机制指的是可以在运行时加载、探知,使用编译期间完全未知的类。我们知道,当类加载完毕后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象)。这个对象包含了完整的类结构信息,通过该对象就可以获知类的结构信息,如类的方法、属性等。

所以通过一个类的Class对象,我们就可以动态的创建实例、调用方法、访问属性等。当一个类被加载时,JVM便自动产生了一个Class对象,Class对象是反射的根源,使用反射机制的前提是获取类的Class对象。Class的描述如下:

Instances of the class Class represent classes and interfaces in a running Javaapplication. An enum is a kind of class and an annotation is a kind ofinterface. Every array also belongs to a class that is reflected as a Class object that is shared byall arrays with the same element type and number of dimensions. The primitiveJava types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.

Class has no public constructor. Instead Class objects are constructedautomatically by the Java Virtual Machine as classes are loaded and by calls tothe defineClass method in the classloader.

反射机制常见的操作有:

l   动态加载类、动态获取类的信息,如构造器、方法、属性等;

l   动态构造对象;

l   动态调用类和对象的任意方法(公有和私有)、构造器等;

l   访问任意属性(公有和私有),在访问私有属性时,需要设置setAccessible属性为真,这时候告诉JVM不做安全检查,可以直接反问,而且由于不做安全检查,提高了效率;

l   处理注解;

l   获取泛型信息;

使用反射机制最大的问题就是性能问题,若大量使用反射则性能会大幅下降,如下:

public class Main

{

   public static void main(String[] args)

  {

        test1();

        test2();

        test3();

  }

  

   public static void test1()

   {

        long startTime=System.currentTimeMillis();

        String string=new String();

        for (long i = 0; i < 1000000000L; i++)

        {

            string.trim();

        }

        long endTime=System.currentTimeMillis();

        System.out.println("普通方法调用10亿次耗时:"+(endTime-startTime));

   }

  

   public static void test2()

   {

      try

      {

            long startTime=System.currentTimeMillis();

             Class<String> clazz=String.class;

             String string=clazz.newInstance();

             Method method=clazz.getMethod("trim",null);

             for (long i = 0; i < 1000000000L; i++)

             {

                 method.invoke(string, null);

             }

             long endTime=System.currentTimeMillis();

             System.out.println("反射方法调用10亿次耗时:"+(endTime-startTime));

      }

      catch (Exception e)

      {

         

      }

   }

  

   public static void test3()

   {

      try

      {

             long startTime=System.currentTimeMillis();

             Class<String> clazz=String.class;

             String string=clazz.newInstance();

             Method method=clazz.getMethod("trim",null);

             method.setAccessible(true);

             for (long i = 0; i < 1000000000L; i++)

             {

                 method.invoke(string, null);

             }

             long endTime=System.currentTimeMillis();

             System.out.println("反射方法调用10亿次,不做安全检查耗时:"+(endTime-startTime));

      }

      catch (Exception e)

      {

         

      }

   }

}

普通方法调用10亿次耗时:1271

反射方法调用10亿次耗时:2912

反射方法调用10亿次,不做安全检查耗时:2164

为了提高性能,可以采用Javassistcglib等进行字节码操作

2、       字节码操作

运行时操作字节码,比反射开销下,效率高,可以实现如下功能:

l  动态生成新的类;

l  动态改变某个类的结构,如添加、删除、修改属性或方法等;

常见的字节码操作类库有:

l  BCEL

l  ASM

l  CGLIB

l  Javassist

3、       代理

在Java中代理分为静态代理和动态代理两种类型。静态代理就是显示源码创建一个类的代理,当代理较多时,需要写大量的代理类源码;而动态代理是动态创建一个类的代理类,如可以通过JDK动态生成代理类,也可以采用字节码操作动态创建代理类。通过JDK提供的Proxy、InvocationHandler来动态创建代理类的步骤如下:

1)     定义接口

2)     提供实现类

3)     实现InvocationHandler

/**

 * 定义接口

 * */

public interface UserDao

{

   public void add();

}

  /**

    * 实现类

 * */

public class UserDaoImpl  implements UserDao

{

    public void add()

    {

    System.out.println("adduser");

    }

}

/**

   * InvocationHandler

 * */

public class ProxyFactory  implements InvocationHandler

{

     private Object real;

     public ProxyFactory(Object real)

     {

          this.real=real;

     }

    

    /**

      * 通过Proxy来返回代理对象

 * */

     publicObject getProxyObject()

     {

         returnProxy.newProxyInstance(ClassLoader.getSystemClassLoader(),real.getClass().getInterfaces(),this);

     }

    

     @Override

     public Object invoke(Object proxy, Method method, Object[] args)

               throws Throwable

     {

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

          Object result=method.invoke(real, args);

          return result;

     }

 

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值