深入理解java:1.1.1.反射机制

反射

到底什么是反射(Reflection)呢?

反射有时候也被称为内省(Introspection),事实上,反射,就是一种内省的方式,

Java不允许在运行时改变程序结构或类型变量的结构,但它允许在运行时去探知、加载、调用在编译期完全未知的class,可以在运行时加载该class,生成实例对象(instance object),调用method,或对field赋值。

这种类似于“看透”了class的特性被称为反射(Reflection),我们可以将反射直接理解为:可以看到自己在水中的倒影,这种操作与直接操作源代码效果相同,但灵活性高得多。

反射概念,反射的应用场景

反射的应用场景:如果我们在程序运行时,一个对象想要检视自己所拥有的成员属性,该如何操作?

如果我们想要在运行期获得某个类Class的信息如它的属性、构造方法、一般方法 后再考虑是否创建它的对象,这种情况该怎么办呢?

这就需要用到反射!

.Java文件在编译后会变成.class文件,

这就像是个镜面,本身是.java,在镜中是.class,他们其实是一样的;

那么同理,我们看到镜子的反射是.class,就能通过反编译,了解到.java文件的本来面目。即为反射

官方给出的概念:反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。

例如它允许一个java的类获取它所有的成员变量和方法并且显示出来。

反射机制的作用:

1,反编译:.class-->.java

2,通过反射机制访问java对象的属性,方法,构造方法,甚至其父类,接口等。

获取类的三种方式

  1. //第一种方式:
  2. Class c1 = Class.forName(User);
  3. //第二种方式:
  4. //java中每个类型都有class 属性.
  5. Class c2 = User.class
  6. //第三种方式:
  7. //java语言中任何一个java对象都有getClass 方法
  8. User u = new User();
  9. Class c3 = u.getClass(); //c3是运行时类 (e的运行时类是User)

创建对象方法

[java]

  1. Class c =Class.forName("User");
  2. //创建此Class 对象所表示的类的一个新实例
  3. Object o = c.newInstance(); //调用了User的无参数构造方法.

获取类属性

  1. //获取整个类
  2. Class c = Class.forName("java.lang.Integer");
  3. //获取所有的属性
  4. Field[] fs = c.getDeclaredFields();

获取方法

getDeclaredMethods()

...

反射的缺点:

反射机制给予Java开发很大的灵活性,但反射机制本身也有缺点,代表性的缺陷就是反射的性能,

一般来说,通过反射调用方法的效率比直接调用的效率要至少慢一倍以上。

关于性能的问题,可以参考这篇博客http://blog.csdn.net/l_serein/article/details/6219897

优点:

a、Java的反射机制就是增加程序的灵活性,避免将程序写死到代码里。
例如: 实例化一个 person()对象, 不使用反射,需要new person(); 如果想变成实例化其他类,那么必须修改源代码,并重新编译。
使用反射: class.forName("person").newInstance();

而且这个类描述可以写到配置文件中,如 **.xml, 这样如果想实例化其他类,只要修改配置文件的"类描述"就可以了,不需要重新修改代码并编译。

在JavaWeb中加载数据库驱动时会用到。
b、增加程序的灵活性。
例如:struts中。请求的派发控制。
当请求来到时。struts通过查询配置文件。找到该请求对应的action方法。然后通过反射实例化action。并调用响应method。

如果不适用反射,那么你就只能写死到代码里了。

反射一般在框架中使用较多。

因为框架要适用更多的情况。对灵活性要求较高。

反射与设计模式

反射的一个很重要的作用,就是在设计模式中的应用,包括在工厂模式和代理模式中的应用。

工厂模式和代理模式又在各种框架(如Strust2,Spring)中广泛应用。

先来看看,如果不用反射的时候,的工厂模式吧:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

/**

 * @author Rollen-Holt 设计模式之 工厂模式

 */

interface fruit{

    public abstract void eat();

}

class Apple implements fruit{

    public void eat(){

        System.out.println("Apple");

    }

}

class Orange implements fruit{

    public void eat(){

        System.out.println("Orange");

    }

}

// 构造工厂类

// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了

class Factory{

    public static fruit getInstance(String fruitName){

        fruit f=null;

        if("Apple".equals(fruitName)){

            f=new Apple();

        }

        if("Orange".equals(fruitName)){

            f=new Orange();

        }

        return f;

    }

}

class hello{

    public static void main(String[] a){

        fruit f=Factory.getInstance("Orange");

        f.eat();

    }

}

这样,当我们在添加一个子类的时候,就需要修改工厂类了。如加一个梨的子类时,需要修改工厂类。

如果我们添加太多的子类的时候,改的就会很多。

现在我们看看利用反射机制:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

package Reflect;

interface fruit{

    public abstract void eat();

}

class Apple implements fruit{

    public void eat(){

        System.out.println("Apple");

    }

}

class Orange implements fruit{

    public void eat(){

        System.out.println("Orange");

    }

}

class Factory{

    public static fruit getInstance(String ClassName){

        fruit f=null;

        try{

            f=(fruit)Class.forName(ClassName).newInstance();

        }catch (Exception e) {

            e.printStackTrace();

        }

        return f;

    }

}

class hello{

    public static void main(String[] a){

        fruit f=Factory.getInstance("Reflect.Apple");

        if(f!=null){

            f.eat();

        }

    }

}

我们传给工厂类的参数是子类的全名,现在就算我们添加任意多个子类的时候,工厂类就不需要修改。

上面的代码虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。

而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。

下面我们来看看: 结合属性文件的工厂模式,可以称之为  动态工厂模式。

首先创建一个fruit.properties的资源文件,

内容为:


1

2

apple=Reflect.Apple

orange=Reflect.Orange

 然后编写主类代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

package Reflect;

import java.io.*;

import java.util.*;

interface fruit{

    public abstract void eat();

}

class Apple implements fruit{

    public void eat(){

        System.out.println("Apple");

    }

}

class Orange implements fruit{

    public void eat(){

        System.out.println("Orange");

    }

}

//操作属性文件类

class init{

    public static Properties getPro() throws FileNotFoundException, IOException{

        Properties pro=new Properties();

        File f=new File("fruit.properties");

        if(f.exists()){

            pro.load(new FileInputStream(f));

        }else{

            pro.setProperty("apple""Reflect.Apple");

            pro.setProperty("orange""Reflect.Orange");

            pro.store(new FileOutputStream(f), "FRUIT CLASS");

        }

        return pro;

    }

}

class Factory{

    public static fruit getInstance(String ClassName){

        fruit f=null;

        try{

            f=(fruit)Class.forName(ClassName).newInstance();

        }catch (Exception e) {

            e.printStackTrace();

        }

        return f;

    }

}

class hello{

    public static void main(String[] a) throws FileNotFoundException, IOException{

        Properties pro=init.getPro();

        fruit f=Factory.getInstance(pro.getProperty("apple"));

        if(f!=null){

            f.eat();

        }

    }

}

【运行结果】:Apple

动态代理模式

接下来我们来看一下代理。
代理可以帮助我们进行很好的封装,使底层的代码能够有效的隐藏起来。
我们先来看看静态代理吧。

public class Main2 {
    //这里传入的是接口类型的对象,方便向上转型,实现多态
    public static void consumer(ProxyInterface pi){
        pi.say();
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        consumer(new ProxyObject());
    }
}

//代理接口
interface ProxyInterface{
    public void say();
}

//被代理者
class RealObject implements ProxyInterface{
    //实现接口方法
    @Override
    public void say() {
        // TODO Auto-generated method stub
        System.out.println("say");
    }

}

//代理者
class ProxyObject implements ProxyInterface{

    @Override
    public void say() {
        // TODO Auto-generated method stub
        //dosomething for example
        System.out.println("hello proxy");
        new RealObject().say();
        System.out.println("this is method end");
    }

}
output:
hello proxy
say
this is method end

这就是静态代理,理解这个应该不难。
下面我们再来看看动态代理

import java.lang.reflect.*;

public class Main {
    static void customer(ProxyInterface pi){
        pi.say();
    }
    public static void main(String[] args){
        RealObject real = new RealObject();        //当运行时(动态)才创建代理类
        ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(real.getClass().getClassLoader(), real.getClass().getInterfaces(), new ProxyObject(real));
        customer(proxy);
    }
}

interface ProxyInterface{
    void say();
}

//被代理类
class RealObject implements ProxyInterface{
    public void say(){
        System.out.println("i‘m talking");
    }
}

//代理类,实现InvocationHandler 接口
class ProxyObject implements InvocationHandler{
    private Object proxied = null;
    public ProxyObject(){

    }
    public ProxyObject(Object proxied){
        this.proxied  = proxied;
    }
    public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
        System.out.println("hello");
        return arg1.invoke(proxied, arg2);
    };
}

可以看到动态代理的代理类是实现了一个InvocationHandler的接口,

我们通过reflect.Proxy的类的newProxyInstance方法就可以得到这个接口的实例,然后再来作为参数传递进去,

这里每一个在代理类上处理的东西也会被重定向到调用处理器上。

至于动态代理和静态代理的区别,

即动态代理是动态的创建代理和动态的处理方法的,这也是反射的一个重要体现之处。

时间: 2024-08-14 00:30:22

深入理解java:1.1.1.反射机制的相关文章

java工厂类与反射机制

java 简单工厂类 2012-04-22 15:44:07|  分类: java |  标签:java工厂类  简单工厂类  |举报|字号 订阅 简单工厂模式需要由以下角色组成: 接口                        接口的实现类(简单工厂模式里面的具体产品角色)                        工厂注意对比以下三个实例的不同实例1: package org.jzkangta.factorydemo01;//定义接口interface Car{    public 

Java 核心类库之反射机制

1:什么是反射机制? 2:反射机制它可以做什么呢? 3:反射机制对应的API又是什么? 1):通过反射机制来获取一个对象的全限定名称(完整包名),和类名: 2):实例化Class对象 3):获取对象的父类与实现的接口 4):获取类中的所有的方法或者单个方法 5):使用反射调用方法 && 使用反射调用静态方法 6):使用反射调用数组参数 7):使用反射,动态拷贝数组 7):获取一个类中所有的构造器,获取单个不带参数的构造器,获取带参数的构造器 8):使用反射调用构造器---->创建对象

Java学习之:反射机制

一.反射机制应用场景 知道在哪里用的情况很重要,任何东西的产生都有他的来由,知道了场景才知道为什么要发明这个东西. 一般在开发针对java语言相关的开发工具和框架时使用,比如根据某个类的函数名字,然后执行函数,实现类的动态调用! 而且这么看,所有面向对象的语言可能都会用到这个机制,西草原生并不支持这种机制,但是可以手动实现,详情请见好基友的文章,http://blog.csdn.net/k346k346/article/details/51698184 二.反射机制 言归正传,来具体说说什么是反

【深入理解Java虚拟机】垃圾回收机制

本文内容来源于<深入理解Java虚拟机>一书,非常推荐大家去看一下这本书. 本系列其他文章: [深入理解Java虚拟机]Java内存区域模型.对象创建过程.常见OOM 1.垃圾回收要解决的问题 垃圾收集(Garbage Collection,GC),要设计一个GC,需要考虑解决下面三件事情: (1)哪些内存需要回收? (2)什么时候回收? (3)如何回收? 哪些内存需要回收? 根据<Java内存区域模型.对象创建过程.常见OOM>中介绍的java内存模型,其中,程序计数器.虚拟机栈

深入理解java动态代理的实现机制

今天将从以下5方面来系统的学习一下java动态代理的实现机制: 什么是代理 什么是静态代理 什么是动态代理 动态代理的实现机制 动态代理的使用场景 1,什么是代理 相信大家都有购买过火车票或者机票的经历,有的人在携程买,有的在飞猪,也有的在微信上买等等,这里的携程飞猪微信也好都是受铁路部的委托代理售卖火车票,这里的携程飞猪就是代理类,铁路部就是委托类,这就是代理 2,什么是静态代理 所谓的静态代理就是在代码运行之前,代理类就已经存在,通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生

java的泛型与反射机制

什么是泛型? 泛型,即"参数化类型".顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参). 为什么要使用泛型? 先看如下代码: public class GenericTest { public static void main(String[] args) { List list = new ArrayList(); list.add("qqyumidi"

Java进阶之reflection(反射机制)——反射概念与基础

反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见的JavaScript就是动态语言,除此之外Ruby,Python等也属于动态语言,而C.C++则不属于动态语言. 二.Java是动态语言吗? 从动态语言能在运行时改变程序结构结构或则变量类型上看,Java和C.C++一样都不属于动态语言. 但是JAVA却又一个非常突出的与动态相关的机制:反射机制.

java.lang.Class&lt;T&gt; -- 反射机制

1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 2反射机制能做什么 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类: 在运行时构造任意一个类的对象: 在运行时判断任意一个类所具有的成员变量和方法: 在运行时调用任意一个对象的方法: 生成动态代理. 3反射机制的相关API 通过一个对象获得完整的包名和类名 pac

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

一.什么是反射机制? 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.简单来说,就是Java对每一个类和类中的所有成员都进行了封装,这样每个类都有一个与之对应的Class对象,通过这个对象可以直接访问类中的所有成员. 二.Class类 1.在一个Class类中,将被封装类的方法(构造器之外)封装为Method类,将字段封装为Filed类,将构造器封装为Co

【Java基础】java类加载过程与反射机制

1.类的加载.连接和初始化 当程序使用某个类时,如果该类还未被加载到内存中,则系统会通过加载.连接.初始化三个步骤来对类进行初始化.如果没有意外,jvm将会连续完成这三个步骤,有时也把这三个步骤统称为类的加载和类初始化. 1.1 类的加载 类加载指的是将类的class文件读入内存,并且为之创建一个java.lang.Class对象,也就是说当程序中使用任何类时,都会为之创建一个java.lang.Class对象.类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器是前面所有程序运行的基