黑马程序员技术交流社区

标题: 反射怎么理解啊? [打印本页]

作者: 黑马-李勇    时间: 2012-7-29 15:07
标题: 反射怎么理解啊?
看得很晕,有什么好的方法吗?
作者: 刘同超    时间: 2012-7-29 15:16
对象1生对象2。对象2生对象3。 ……
最后根据对象N找到对象1。这是我的理解。

归结起来,就是找到对象的祖宗。。
作者: 田向向    时间: 2012-7-29 15:18
http://search.itheima.com/   
里面很多,搜一下,看看有没有好理解的
作者: 金_鑫    时间: 2012-7-29 15:23
本帖最后由 金_鑫 于 2012-7-29 20:08 编辑

下面是我的理解,看完视频之后的。
什么是反射?
       根据类的信息来加载这个类,然后构造这个对象,然后再调用这个类中的属性和方法。(这句话是老师说的)
       我个人理解就是,反射就是让你可以随便调用你没有实例化的东西,因为类在实例化之后就固定了,而反射就打破了这种固定模式,即使你的类没有被实例化加载到内存中,你一样可以在你要使用的时候找到它。
       张孝祥说:“反射就是把Java类中的各种成分映射成相应的java类”,其细节方面就是你通过自己编写代码来将类加载到java虚拟机中,也有人称“反射”为“类的自解析”。
       通过反射可以让程序变得更加灵活。
反射的应用?
       在.net中连接数据库时为了让程序可以灵活的连接不通的数据库,操作不同的数据库我们使用了抽象工厂+反射+配置文件来实现。
这意味着反射可以用在对“松耦合”要求很高的场合。
还有一个很常见的例子,就是无论你用微软的“死丢丢”也就是vs了,还是java的IDE——eclipse,你编写好一个类之后你调用时,你只需将类实例化,然后实例化对象后面点一下就能出来看访问的属性和方法的列表,这个也是通过反射来实现的。
我冒昧的猜测一下其中的原理,首先你写好一个类之后,编译器一边都会直接进行检查的,也就是进行编译,如果存在编译时期错误就会提示。当你实例化这个类的时候它会进行编译,但这里不是执行,不会加载到内存中。这时你再使用你已经实例化好的类时,它会根据你你提供的类的信息,也就是你类的类型,通过反射找到里面的方法和属性,然后生成列表实现出来。(这段文字还待我探讨,大家踊跃拍砖)

反射的实现?

java中主要是通过四种方式来进行class的加载的:

1.classLoader

2.类名.class.

3.对象名.getClass()

4.Class.forName();
       我个人觉得1、4是比较常用的,因为这两个可以通过类的信息找到类,进而将类加载的JVM中。你只需传递给他们字符串就ok。
下面是两个小练习可以练习一下:

1.  classLoader

[java] view plaincopyprint?import java.lang.reflect.*;  
  
import java.util.*;  
  
   
  
   
  
public class Test {  
  
         public static void main(String[] args) {  
  
                     
  
                   Class c1;  
  
                   ClassLoader classLoader = ClassLoader.getSystemClassLoader();  
  
   
  
                   try {  
  
                            //加载student类   
  
                            c1 = classLoader.loadClass("demo1.Student");  
  
                            System.out.println(c1);  
  
                              
  
                            //获得加载类的所有方法   
  
                            Field[] fields = c1.getFields();  
  
                              
  
                            //遍历输出   
  
                            for (int i = 0; i < fields.length; i++) {  
  
                                     System.out.println(fields.getName());  
  
                                     System.out.println(fields.getType());  
  
                                     System.out.println(fields.getModifiers());  
  
                            }  
  
                            Field stuName = c1.getField("name");  
  
                              
  
                            //获得c1中的方法   
  
                            Class[] parameterTypes = {};  
  
                            Method method = c1.getMethod("say", parameterTypes);  
  
                            //实例化c1对象   
  
                            Object obj = c1.newInstance();  
  
                            //通过实例化后的对象调用c1中方法   
  
                            method.invoke(obj,null);  
  
   
  
                   } catch (Exception e) {  
  
                            // TODO Auto-generated catch block   
  
                            e.printStackTrace();  
  
                   }  
  
                     
  
         }  
  
}  
  
   
  
class Student {  
  
           
  
         public String name;  
  
         public int age;  
  
         protected String nicai;  
  
         private int hh;  
  
         public void say() {  
  
                   System.out.println("I‘m student");  
  
         }  
  
}  
import java.lang.reflect.*;

import java.util.*;





public class Test {

         public static void main(String[] args) {

                  

                   Class c1;

                   ClassLoader classLoader = ClassLoader.getSystemClassLoader();



                   try {

                            //加载student类

                            c1 = classLoader.loadClass("demo1.Student");

                            System.out.println(c1);

                           

                            //获得加载类的所有方法

                            Field[] fields = c1.getFields();

                           

                            //遍历输出

                            for (int i = 0; i < fields.length; i++) {

                                     System.out.println(fields.getName());

                                     System.out.println(fields.getType());

                                     System.out.println(fields.getModifiers());

                            }

                            Field stuName = c1.getField("name");

                           

                            //获得c1中的方法

                            Class[] parameterTypes = {};

                            Method method = c1.getMethod("say", parameterTypes);

                            //实例化c1对象

                            Object obj = c1.newInstance();

                            //通过实例化后的对象调用c1中方法

                            method.invoke(obj,null);



                   } catch (Exception e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                   }

                  

         }

}



class Student {

         

         public String name;

         public int age;

         protected String nicai;

         private int hh;

         public void say() {

                   System.out.println("I‘m student");

         }

}



2.  forName方式

只需要把上面的

c1 = classLoader.loadClass("demo1.Student");

改成c1 = Class.forName("demo1.Student");即可。



通过这两段代码可以看出使用反射,我只需要知道我要调用的类的名字,就可以加载并使用它,并且这样可以更加灵活。你可以把字符串”demo1.Student”这个信息放到一个文件中,或者是放到数据库中,这样程序就不会那么死板了。

来自CSDN



作者: 金龙    时间: 2012-7-29 16:25
我就简单说一下反射的好处以及应用场景吧,或许不太准确,但我觉得有助于理解。

很多时候,当我们写一个程序的时候,类与类之间是相互调用的,有可能我的测试类已经写好了,但是被调用的类还没有写好,或者被调用的类也是需要被改动的,可是如果因为每次的改动而去修改源代码是不现实的,毕竟,一个项目弄好之后,我们提供出去的是class文件,那么,这时候,我们只需要把需要改动的内容写到配置文件中去,以后如果需要再增加什么新的内容时,只改动配置文件就可以了,我们可以读取配置文件中的信息,再通过反射使用次信息所属类的属性以及方法,应该是属于,提高了代码的拓展性和可维护性吧
作者: 肖琦    时间: 2012-7-29 16:27
反射的个人理解:
   为什么要用反射?学的时候我是抱着这种心态的,后来也慢慢有所领悟。在我们写程序中,可能一段代码就写死执行的就是一个结果,如果用反射的话,我们代码不变,改变加载项,运行结果就大不同,这样我们执行改变配置文件就行了。举个很简单的例子(伪代码):
class A{
      public void show(){}//功能一:show
}
class Test{
       public static void main(String[] args){
              new A().show();
       }
}
Test执行过程中只能看到功能一的结果。但如果客户要求一变,我们又要写个类改变方案。
如果用反射的话
class B{
    public void run();
}
class Test{
            public static void main(String[] args){
           Class clazz = class.forName(args[0]);//得到类的字节码
           clazz.getMethod(args[1]).invoke(clazz.newInstance()) ;//得到方法,并指定实例掉用              
      }
}
此时我们只需要在程序加载前 给main方法的String[] 配好参数,指定是哪个类,哪个方法,就可以得到想要的,要改变功能时,只需要改变配置文件就行。这样的话,我们整篇代码不需要定那个具体的类,方法,属性,只需要改配置就有不同的效果,这样用起来就很方便(以上为伪代码,没有经测试)。
  还有就是搞清楚反射的几个常用的类Class,Constructor,Feild,Method吧.这个查API.
  我也就是这么理解的,后续再深入学习的话时可能还有不同的体会。
  可能大部分人开始学这个知识点时有点困惑吧,熬过去,挺下去,照着视频敲个几遍代码,边敲边想,慢慢就好了,自己动手比神马都强


作者: 徐帅    时间: 2012-7-29 17:42
本帖最后由 徐帅 于 2012-7-29 17:44 编辑

想要深刻理解反射,当然必须理解反射的基石Class类:
Java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class
1. Class类的各个实例对象
              对应各个类在内存中的字节码,例如Person类的字节码等
2. 一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类
的字节码,不同的里的字节码是不同的,所以它们在内存中的内容是不同的,这一
个个空间可以分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型就是Class类型
反射:
  就是把java类中的各种成分映射成相应的java类。
通过Class类提供的一系列方法来活得其中的变量,方法,修饰符,包等信息,他们是
Filed,Method,Constructor,Package等,
只是通过函数名和参数类型的不同来区别,一个java类中会有很多种
方法,只要传入函数名,和参数类型,就能够明确所要获取的方法,
反射的作用--> 实现框架功能,
就像房子与门的关系,房子是框架,将门窗插入框架中,房子就可以使用了。
当然房子是在早期就盖好的,我们为了能够在房子框架的基础上使用它,只要调用用户的
提供的一个个模块,比如客厅,厨房,卧室,把他们当做一个个类,他们有各种不同的功能
与方法,是我们来定义的,就像装修一样,每个人装修都会有不同的风格,但是厨房还是做饭的
卧室还是休息的,但房子的框架是固定的,可以通过方法来调用这些功能,就像java中通过一些
方法来获取方法,变量的字节码一样,类是我们后期定义的,通过框架我们都可以使用它们。
对于反射的学习,
个人觉得是把视频多看两遍,但是一定要记笔记,虽然张老师没有给我们总结的
很详细,但是他说的话都很深刻,而且很多重点,所以及时记录下来,多思考,把概念弄清楚了。我想
学习起来就容易多了,因为之后就是方法的使用,java学习,就是在学习一种思想,当然在理解的过程
中不断实践。敲代码分析,会更加深入的理解。
以上只是个人的理解,希望对楼主有帮助。有不对的地方,还请指正








欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2