什么是JAVA的反射机制?有什么作用?_第3页回答

2021-01-05 14:51发布

26条回答
灰机带翅膀
2楼 · 2021-01-07 14:23

1、Java反射机制是在运行状态中,对于任意一个类,都能知道这个类所有的属性和方法;
对于任意一个对象,都能调用任意一个属性和方法;
这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

通俗的讲:反射就是把Java类中的各个部分,映射成一个个的Java对象,例如,一个类有:成员变量,方法,构造方法,等信息,利用反射技术咱们可以把这些组成部分映射成一个个对象,拿到这些对象后就可以做一些事情。

2、一般来说反射是用来做框架的,我们自己平时的项目开发过程中,基本很少会直接用到反射机制,但很多设计开发都与反射机制有关,例如模块化的开发,通过反射机制去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们经常使用的Spring····等框架也大量使用到了反射机制。

举例:
1、我们在使用JDBC连接数据库使用Class.forName()通过反射记载数据库的驱动程序;
2、Spring配置文件里的常见的bean配置,可以用反射很轻易的就可以实现:解析xml然后把xml里的内容作为参数,利用反射创建对象。
3、动态配置实例的属性;

虽然反射在日常的开发中用到的不多,但是咱们还必须搞懂它,因为搞懂了反射以后,可以帮助咱们理解框架的一些原理。所以说有一句很经典的话:反射是框架设计的灵魂


增加程序的灵活性。

如struts中请求的派发控制。

当请求来到时。struts通过查询配置zhuan文件。找到shu该请求对应的action。已经方法。

然后通过反射实例化action。并调用响应method。

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

所以说,一个灵活,一个不灵活。

很少情况下是非用反射不可的。大多数情况下反射是为了提高程序的灵活性。

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


收获很多
4楼 · 2021-01-08 09:43

Java反射机制是在运行状态中,对于任意一个类,都能知道这个类所有的属性和方法;对于任意一个对象,都能调用任意一个属性和方法;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制,通俗的讲:反射就是把Java类中的各个部分,映射成一个个的Java对象,例如,一个类有:成员变量,方法,构造方法,等信息,利用反射技术咱们可以把这些组成部分映射成一个个对象,拿到这些对象后就可以做一些事情。

小小李兆佳
5楼 · 2021-01-08 10:20
  • 在运行时判断一个对象所属的类;

  • 在运行时构造任意一个类的对象;

  • 在运行时判断任意一个类所具有的成员变量和方法;

  • 在运行时调用任意一个对象的方法;

  • 生成动态代理;


梵梵
6楼 · 2021-01-08 19:18

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方专法属;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能:在运行时判定任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判定任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

我的网名不再改
7楼 · 2021-01-09 13:53

Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助。

那么什么是Java的反射呢?

       大家都知道,要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载。Java类如果不被Java虚拟机加载,是不能正常运行的。现在我们运行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类的已经被加载了。

Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。这样的特点就是反射。

那么Java反射有什么作用呢?

假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。

Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。

Class类

       要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。

反射API

       u反射API用于反应在当前Java虚拟机中的类、接口或者对象信息

u功能
—获取一个对象的类信息.

       —获取一个类的访问修饰符、成员、方法、构造方法以及超类的信息.

       —检获属于一个接口的常量和方法声明.

       —创建一个直到程序运行期间才知道名字的类的实例.

       —获取并设置一个对象的成员,甚至这个成员的名字是
   在程序运行期间才知道.

       —检测一个在运行期间才知道名字的对象的方法

       利用Java反射机制我们可以很灵活的对已经加载到Java虚拟机当中的类信息进行检测。当然这种检测在对运行的性能上会有些减弱,所以什么时候使用反射,就要靠业务的需求、大小,以及经验的积累来决定。

       那么如何利用反射API在运行的时候知道一个类的信息呢?

代码示例:


[java]  view plain copy

  1. "font-size:16px;">import java.lang.reflect.Field;  

  2. import java.lang.reflect.Method;  

  3. import javax.swing.JOptionPane;  

  4. /** 

  5.   *本类用于测试反射API,利用用户输入类的全路径, 

  6. *找到该类所有的成员方法和成员属性 

  7.   */  

  8. public class MyTest {  

  9.      /** 

  10.      *构造方法 

  11.      */  

  12.     public MyTest(){  

  13.        String classInfo=JOptionPane.showInputDialog(null,"输入类全路径");//要求用户输入类的全路径  

  14.        try {  

  15.            Class cla=Class.forName(classInfo);//根据类的全路径进行类加载,返回该类的Class对象  

  16.             

  17.            Method[] method=cla.getDeclaredMethods();//利用得到的Class对象的自审,返回方法对象集合  

  18.             

  19.            for(Method me:method){//遍历该类方法的集合  

  20.               System.out.println(me.toString());//打印方法信息  

  21.            }  

  22.             

  23.            System.out.println("********");  

  24.             

  25.            Field[] field=cla.getDeclaredFields();//利用得到的Class对象的自审,返回属性对象集合  

  26.            for(Field me:field){ //遍历该类属性的集合  

  27.               System.out.println(me.toString());//打印属性信息  

  28.            }  

  29.        } catch (ClassNotFoundException e) {  

  30.            e.printStackTrace();  

  31.        }  

  32.     }  

  33.     public static void main(String[] args) {  

  34.        new MyTest();  

  35.     }  

  36. }  


运行的时候,我们输入javax.swing.JFrame,那么运行结果如下:

public void javax.swing.JFrame.remove(java.awt.Component)

public void javax.swing.JFrame.update(java.awt.Graphics)

…………

********

public static final int javax.swing.JFrame.EXIT_ON_CLOSE

private int javax.swing.JFrame.defaultCloseOperation

…………

    大家可以发现,类的全路径是在程序运行的时候,由用户输入的。所以虚拟机事先并不知道所要加载类的信息,这就是利用反射机制来对用户输入的类全路径来对类自身的一个自审。从而探知该类所拥有的方法和属性。

通过上面代码,大家可以知道编译工具为什么能够一按点就能列出用户当前对象的属性和方法了。它是先获得用户输入对象的字符串,然后利用反射原理来对这样的类进行自审,从而列出该类的方法和属性。

使用反射机制的步骤:

u导入java.lang.relfect 包

u遵循三个步骤
第一步是获得你想操作的类的 java.lang.Class 对象
第二步是调用诸如 getDeclaredMethods 的方法
第三步使用 反射API 来操作这些信息

获得Class对象的方法

u如果一个类的实例已经得到,你可以使用

       【Class c = 对象名.getClass(); 

      例: TextField t = new TextField();

              Class c = t.getClass();

              Class s = c.getSuperclass();

u如果你在编译期知道类的名字,你可以使用如下的方法

Class c = java.awt.Button.class; 
或者

         Class c = Integer.TYPE;

u如果类名在编译期不知道, 但是在运行期可以获得, 你可以使用下面的方法

          Class c = Class.forName(strg);

   这样获得Class类对象的方法,其实是利用反射API把指定字符串的类加载到内存中,所以也叫类加载器加载方法。这样的话,它会把该类的静态方法和静态属性,以及静态代码全部加载到内存中。但这时候,对象还没有产生。所以为什么静态方法不能访问非静态属性和方法。因为静态方法和属性产生的时机在非静态属性和方法之前。

代码示例:


[java]  view plain copy

  1. "font-size:16px;">package  com;  

  2.    

  3. public class MyTest {  

  4.     public static void main(String[] args) {  

  5.        TestOne  one=null;  

  6.        try{  

  7.        Class  cla=Class.forName("com.TestOne");//进行com.TestOne类加载,返回一个Class对象  

  8.        System.out.println("********");  

  9.        one=(TestOne)cla.newInstance();//产生这个Class类对象的一个实例,调用该类无参的构造方法,作用等同于new TestOne()  

  10.        }catch(Exception e){  

  11.            e.printStackTrace();  

  12.        }  

  13.        TestOne two=new TestOne();  

  14.   System.out.println(one.getClass() == two.getClass());//比较两个TestOne对象的Class对象是否是同一个对象,在这里结果是true。说明如果两个对象的类型相同,那么它们会有相同的Class对象  

  15.     }  

  16. }  

  17.    

  18. class TestOne{  

  19.     static{  

  20.        System.out.println("静态代码块运行");  

  21.     }  

  22.     TestOne(){  

  23.        System.out.println("构造方法");  

  24.     }  

  25. }  


  以上代码过行的结果是:

静态代码块运行

***********

构造方法

构造方法


代码分析:

在进行Class.forName("com.TestOne")的时候,实际上是对com.TestOne进行类加载,这时候,会把静态属性、方法以及静态代码块都加载到内存中。所以这时候会打印出"静态代码块运行"。但这时候,对象却还没有产生。所以"构造方法"这几个字不会打印。当执行cla.newInstance()的时候,就是利用反射机制将Class对象生成一个该类的一个实例。这时候对象就产生了。所以打印"构造方法"。当执行到TestOne two=new TestOne()语句时,又生成了一个对象。但这时候类已经加载完毕,静态的东西已经加载到内存中,而静态代码块只执行一次,所以不用再去加载类,所以只会打印"构造方法",而"静态代码块运行"不会打印。

反射机制不但可以例出该类对象所拥有的方法和属性,还可以获得该类的构造方法及通过构造方法获得实例。也可以动态的调用这个实例的成员方法。

代码示例:

[java]  view plain copy

  1. "font-size:16px;">package reflect;  

  2.    

  3. import java.lang.reflect.Constructor;  

  4.    

  5.    

  6. /** 

  7.  * 

  8.  * 本类测试反射获得类的构造器对象, 

  9.  * 并通过类构造器对象生成该类的实例 

  10.  * 

  11.  */  

  12. public class ConstructorTest {  

  13.    

  14.     public static void main(String[] args) {  

  15.        try {  

  16.            //获得指定字符串类对象  

  17.            Class cla=Class.forName("reflect.Tests");  

  18.            //设置Class对象数组,用于指定构造方法类型  

  19.            Class[] cl=new Class[]{int.class,int.class};  

  20.             

  21.            //获得Constructor构造器对象。并指定构造方法类型  

  22.            Constructor con=cla.getConstructor(cl);  

  23.             

  24.            //给传入参数赋初值  

  25.            Object[] x={new Integer(33),new Integer(67)};  

  26.             

  27.            //得到实例  

  28.            Object obj=con.newInstance(x);  

  29.        } catch (Exception e) {  

  30.            e.printStackTrace();  

  31.        }  

  32.     }  

  33.    

  34. }  

  35.    

  36. class Tests{  

  37.     public Tests(int x,int y){  

  38.        System.out.println(x+"    "+y);  

  39.     }  

  40. }  

运行的结果是” 33    67。说明我们已经生成了Tests这个类的一个对象。 


三、Java类反射中所必须的类:
Java的类反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

四、Java的反射类能做什么:
看完上面的这么多我想你已经不耐烦了,你以为我在浪费你的时间,那么好吧!下面我们就用一些简单的小例子来说明它。
首先我们来看一下通过Java的反射机制我们能得到些什么。
首先我们来写一个类:

java 代码

 

  1. import  java.awt.event.ActionListener;  

  2. import  java.awt.event.ActionEvent;  

  3. class  A  extends  Object  implements  ActionListener{  

  4. private   int  a =  3 ;  

  5. public  Integer b =  new  Integer( 4 );  

  6. public  A(){}  

  7. public  A( int  id,String name){}  

  8. public   int  abc( int  id,String name){ return   0 ;}  

  9. public   void  actionPerformed(ActionEvent e){}  

  10. }  


你可能被我这个类弄糊涂了,你看不出我要做什么,那就不要看这个类了,这个类是用来测试的,你知道知道它继承了Object类,有一个接口是ActionListener,两个属性int和Integer,两个构造方法和两个方法,这就足够了。
下面我们把A这个类作为一个反射类,来过去A类中的一些信息,首先我们先来过去一下反射类中的属性和属性值。

java 代码

 

  1. import  java.lang.reflect.*;  

  2. class  B{  

  3. public   static   void  main(String args[]){  

  4. A r = new  A();  

  5. Class temp = r.getClass();  

  6. try {  

  7. System.out.println("反射类中所有公有的属性" );  

  8. Field[] fb =temp.getFields();  

  9. for ( int  j= 0 ;j

  10. Class cl = fb[j].getType();  

  11. System.out.println("fb:" +cl);  

  12. }  

  13.   

  14. System.out.println("反射类中所有的属性" );  

  15. Field[] fa = temp.getDeclaredFields();  

  16. for ( int  j= 0 ;j

  17. Class cl = fa[j].getType();  

  18. System.out.println("fa:" +cl);  

  19. }  

  20. System.out.println("反射类中私有属性的值" );  

  21. Field f = temp.getDeclaredField("a" );  

  22. f.setAccessible(true );  

  23. Integer i = (Integer)f.get(r);  

  24. System.out.println(i);  

  25. }catch (Exception e){  

  26. e.printStackTrace();  

  27. }  

  28. }  

  29.   

  30. }   


这里用到了两个方法,getFields()、getDeclaredFields(),它们分别是用来获取反射类中所有公有属性和反射类中所有的属性的方法。另外还有getField(String)和getDeclaredField(String)方法都是用来过去反射类中指定的属性的方法,要注意的是getField方法只能取到反射类中公有的属性,而getDeclaredField方法都能取到。
这里还用到了Field 类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问,默认为false。另外 Field类还有set(Object AttributeName,Object value)方法,可以改变指定属性的值。

下面我们来看一下如何获取反射类中的构造方法

java 代码

 

  1. import  java.lang.reflect.*;  

  2. public   class  SampleConstructor {  

  3. public   static   void  main(String[] args) {  

  4. A r = new  A();  

  5. printConstructors(r);  

  6. }  

  7.   

  8. public   static   void  printConstructors(A r) {  

  9. Class c = r.getClass();  

  10. //获取指定类的类名   

  11. String className = c.getName();  

  12. try  {  

  13. //获取指定类的构造方法   

  14. Constructor[] theConstructors = c.getConstructors();  

  15. for ( int  i= 0 ; i

  16. //获取指定构造方法的参数的集合   

  17. Class[] parameterTypes = theConstructors[i].getParameterTypes();  

  18.   

  19. System.out.print(className + "(" );  

  20.   

  21. for ( int  j= 0 ; j

  22. System.out.print(parameterTypes[j].getName() + " " );  

  23.   

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

  25.   

  26. }  

  27. }catch (Exception e) {  

  28. e.printStackTrace();  

  29. }  

  30. }  

  31. }  

这个例子很简单,只是用getConstructors()方法获取了反射类的构造方法的集合,并用Constructor类的getParameterTypes()获取该构造方法的参数。

下面我们再来获取一下反射类的父类(超类)和接口

java 代码

 

  1. import  java.io.*;  

  2. import  java.lang.reflect.*;  

  3.   

  4. public   class  SampleInterface {  

  5. public   static   void  main(String[] args)  throws  Exception {  

  6. A raf = new  A();  

  7. printInterfaceNames(raf);  

  8. }  

  9.   

  10. public   static   void  printInterfaceNames(Object o) {  

  11. Class c = o.getClass();  

  12. //获取反射类的接口   

  13. Class[] theInterfaces = c.getInterfaces();  

  14. for ( int  i= 0 ; i

  15. System.out.println(theInterfaces[i].getName());  

  16. //获取反射类的父类(超类)   

  17. Class theSuperclass = c.getSuperclass();  

  18. System.out.println(theSuperclass.getName());  

  19. }  

  20. }  


这个例子也很简单,只是用Class类的getInterfaces()方法获取反射类的所有接口,由于接口可以有多个,所以它返回一个 Class数组。用getSuperclass()方法来获取反射类的父类(超类),由于一个类只能继承自一个类,所以它返回一个Class对象。

下面我们来获取一下反射类的方法

java 代码

 

  1. import  java.lang.reflect.*;  

  2. public   class  SampleMethod {  

  3.   

  4. public   static   void  main(String[] args) {  

  5. A p = new  A();  

  6. printMethods(p);  

  7. }  

  8.   

  9. public   static   void  printMethods(Object o) {  

  10. Class c = o.getClass();  

  11. String className = c.getName();  

  12. Method[] m = c.getMethods();  

  13. for ( int  i= 0 ; i

  14. //输出方法的返回类型   

  15. System.out.print(m[i].getReturnType().getName());  

  16. //输出方法名   

  17. System.out.print(" " +m[i].getName()+ "(" );  

  18. //获取方法的参数   

  19. Class[] parameterTypes = m[i].getParameterTypes();  

  20. for ( int  j= 0 ; j

  21. System.out.print(parameterTypes[j].getName());  

  22. if (parameterTypes.length>j+ 1 ){  

  23. System.out.print("," );  

  24. }  

  25. }  

  26.   

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

  28. }  

  29.   

  30. }  

  31.   

  32. }  


这个例子并不难,它只是获得了反射类的所有方法,包括继承自它父类的方法。然后获取方法的返回类型、方法名和方法参数。

接下来让我们回过头来想一想,我们获取了反射类的属性、构造方法、父类、接口和方法,可这些东西能帮我们做些什么呢!!
下面我写一个比较完整的小例子,来说明Java的反射类能做些什么吧!!

java 代码

 

  1. import  java.lang.reflect.Constructor;  

  2. import  java.lang.reflect.Method;  

  3.   

  4. public   class  LoadMethod {  

  5. public  Object Load(String cName,String MethodName,String[] type,String[] param){  

  6. Object retobj = null ;  

  7. try  {  

  8. //加载指定的Java类   

  9. Class cls = Class.forName(cName);  

  10.   

  11. //获取指定对象的实例   

  12. Constructor ct = cls.getConstructor(null );  

  13. Object obj = ct.newInstance(null );  

  14.   

  15. //构建方法参数的数据类型   

  16. Class partypes[] = this .getMethodClass(type);  

  17.   

  18. //在指定类中获取指定的方法   

  19. Method meth = cls.getMethod(MethodName, partypes);  

  20.   

  21. //构建方法的参数值   

  22. Object arglist[] = this .getMethodObject(type,param);  

  23.   

  24. //调用指定的方法并获取返回值为Object类型   

  25. retobj= meth.invoke(obj, arglist);  

  26.   

  27. }  

  28. catch  (Throwable e) {  

  29. System.err.println(e);  

  30. }  

  31. return  retobj;  

  32. }  

  33.   

  34. //获取参数类型Class[]的方法   

  35. public  Class[] getMethodClass(String[] type){  

  36. Class[] cs = new  Class[type.length];  

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

  38. if (!type[i].trim().equals( "" )||type[i]!= null ){  

  39. if (type[i].equals( "int" )||type[i].equals( "Integer" )){  

  40. cs[i]=Integer.TYPE;  

  41. }else   if (type[i].equals( "float" )||type[i].equals( "Float" )){  

  42. cs[i]=Float.TYPE;  

  43. }else   if (type[i].equals( "double" )||type[i].equals( "Double" )){  

  44. cs[i]=Double.TYPE;  

  45. }else   if (type[i].equals( "boolean" )||type[i].equals( "Boolean" )){  

  46. cs[i]=Boolean.TYPE;  

  47. }else {  

  48. cs[i]=String.class ;  

  49. }  

  50. }  

  51. }  

  52. return  cs;  

  53. }  

  54.   

  55. //获取参数Object[]的方法   

  56. public  Object[] getMethodObject(String[] type,String[] param){  

  57. Object[] obj = new  Object[param.length];  

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

  59. if (!param[i].trim().equals( "" )||param[i]!= null ){  

  60. if (type[i].equals( "int" )||type[i].equals( "Integer" )){  

  61. obj[i]= new  Integer(param[i]);  

  62. }else   if (type[i].equals( "float" )||type[i].equals( "Float" )){  

  63. obj[i]= new  Float(param[i]);  

  64. }else   if (type[i].equals( "double" )||type[i].equals( "Double" )){  

  65. obj[i]= new  Double(param[i]);  

  66. }else   if (type[i].equals( "boolean" )||type[i].equals( "Boolean" )){  

  67. obj[i]=new  Boolean(param[i]);  

  68. }else {  

  69. obj[i] = param[i];  

  70. }  

  71. }  

  72. }  

  73. return  obj;  

  74. }  

  75. }  


这是我在工作中写的一个实现Java在运行时加载指定的类,并调用指定方法的一个小例子。这里没有main方法,你可以自己写一个。
Load方法接收的五个参数分别是,Java的类名,方法名,参数的类型和参数的值。



      Java中反射机制使用的还是比较广泛的,系统的灵活性、可扩展性大都都是通过反射等方式来加载外部插件,使得系统与插件解耦的同时,增加了功能。但是很多人都只是会用,却是不知道它的实现机制,今天就由我来带大家揭开反射机制的神秘面纱。

       Java中是用Class.forName(classname)来反射类。



  1. package com.java.reflecttest;  

  2.   

  3. import com.java.dbtest.DBTest;  

  4.   

  5.   

  6. /** 

  7.  * Java反射机制测试 

  8.  * @author Longxuan 

  9.  * 

  10.  */  

  11. public class ReflectTest {  

  12.   

  13.     /** 

  14.      * 测试反射类 

  15.      */  

  16.     public static void refTest(){  

  17.         String className = "com.java.dbtest.TestConnection";  

  18.         DBTest dbTest = null;  

  19.         try {  

  20.               

  21.             //通过反射机制,使用类装载器,装载该类  

  22.             Class tc = Class.forName(className);  

  23.               

  24.             //输出反射得到的类  

  25.             System.out.println(tc);  

  26.               

  27.             //创建该类的实例,转化为接口  

  28.             dbTest =(DBTest)tc.newInstance();  

  29.               

  30.             //通过接口,调用该类的方法  

  31.             dbTest.SelectUser();  

  32.               

  33.         } catch (ClassNotFoundException e) {  

  34.             e.printStackTrace();  

  35.         } catch (InstantiationException e) {  

  36.             e.printStackTrace();  

  37.         } catch (IllegalAccessException e) {  

  38.             e.printStackTrace();  

  39.         }  

  40.           

  41.     }  

  42.       

  43.     public static void main(String[] args){  

  44.         refTest();  

  45.     }  

  46. }  



       通过main函数的调试,已经通过,结果如图:

       

       经过调试,查资料,结合自己的推测和理解,似乎是明白了一些。现与大家分享讨论。

       先说执行过程:

       Class.forName(classname)方法,实际上是调用了Class类中的 Class.forName(classname, true, currentLoader)方法。参数:name - 所需类的完全限定名;initialize - 是否必须初始化类;loader - 用于加载类的类加载器。currentLoader则是通过调用ClassLoader.getCallerClassLoader()获取当前类加载器的。类要想使用,必须用类加载器加载,所以需要加载器。反射机制,不是每次都去重新反射,而是提供了cache,每次都会需要类加载器去自己的cache中查找,如果可以查到,则直接返回该类。


       有意思的是java的类加载器也有些门道。它分为BootStrap Class Loader(引导类加载器),Extensions Class Loader (扩展类加载器),App ClassLoader(或System Class Loader),当然少不了Custom ClassLoader(用户自定义类加载器)。其加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。类加载器的详细介绍会在接下来的博文中较深入的分析,欢迎期待。


       forName方法中,调用了ClassLoader.loadClass方法来完成类的反射。根据类加载器的特殊性,结合我的调试过程,画了一个简单的流程图,



       我的这幅图简单的说明了类加载器的类加载过程。先检查自己是否已经加载过该类,如果加载过,则直接返回该类,若没有则调用父类的loadClass方法,如果父类中没有,则执行findClass方法去尝试加载此类,也就是我们通常所理解的片面的"反射"了。这个过程主要通过ClassLoader.defineClass方法来完成。defineClass 方法将一个字节数组转换为 Class 类的实例(任何类的对象都是Class类的对象)。这种新定义的类的实例需要使用 Class.newInstance 来创建,而不能使用new来实例化。

 

      为什么说“任何类的对象都是Class类的对象”呢?在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类(.java文件),编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。


       其实说的简单通俗一点,就是在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象。


帅帅马
8楼 · 2021-01-10 16:14

1.反射机制定义

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改其本身状态或行为的一种能力。

在Java环境中,反射机制允许程序在执行时获取某个类自身的定义信息,例如熟悉和方法等也可以实现动态创建

类的对象、变更属性的内容或执行特定的方法的功能。从而使Java具有动态语言的特性,增强了程序的灵活性和

可移植性。

2.反射机制的作用

Java反射机制主要用于实现以下功能。

(1)在运行时判断任意一个对象所属的类型。

(2)在运行时构造任意一个类的对象。

(3)在运行时判断任意一个类所具有的成员变量和方法。

(4)在运行时调用任意一个对象的方法,甚至可以调用private方法。

注意:上述功能都是在运行时环境中,而不是在编译时环境中。

3.Java反射机制API

实现Java反射机制的API在Java.lang.reflect包下,具有以下几点。

(1)Class类:代表一个类。

(2)Filed类:代表类的成员变量。

(3)Method类:代表类的方法。

(4)Constructor类:代表类的构造方法。

(5)Array类:提供了动态创建数组及访问数组元素的静态方法。该类中的所有方法都是静态的。

4.应用示例

(1)根据类名获取类中定义的所有属性和方法,实例代码如下:

package day0105;import java.lang.reflect.Array;import java.lang.reflect.Field;import java.lang.reflect.Method;public class Reflect { /**  *   *打印出String类所有的属性和方法  */ public void test1(){  Class c = String.class;  Method[] methods = c.getMethods();  for(int i = 0;iStudent类的定义如下package day0105;public class Student { private String id;  private String name; 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 void show(){  System.out.println(id+":"+name); }} Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以普通方式与对象协作的库。反射在性能方面会有一定的损耗,用于字段和方法接入时反射要远慢于直接写代码。如果它作为程序运行中相对很少涉及的部分将不会造成影响,因为即使测试最坏情况下的计时图显示的反射操作也只耗用几微秒。


布啦啦
9楼 · 2021-01-11 10:18

AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。

Java反射机制主要提供了以下功能:在运行时判定任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判定任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。


相关问题推荐

  • 回答 156

    对于每一位才开始接触JAVA的新手来说,先不要管算法和数据结构,大多数简单的程序不需要用到算法和数据结构,所以当你真正需要时再去学习。编程一段时间以后,你就会知道在哪些地方用到他们。这时知道算法的名字并了解它们的功能,然后动手去实践。当我们在去...

  • 回答 93

    2个都很好就业,更关键的是要学得到东西

  • 回答 12
    已采纳

    获取Map集合中所有的key可以通过map集合的keySet()方法获取例如:    Map map = new HashMap();    map.put(xx,xx); //存放数据    //.... 省略    Set set = map.keySet();    //可以通过迭代器进行测试    Iterator iter = set.iter...

  • 回答 56
    已采纳

    不同年龄,不同掌握程度,学历,找工作城市,面试能力这是一个多方面影响的结果,如果是平均值的话,全国平均薪资14k左右

  • 回答 38

    具体学多久,根据自己的学习力,自律性、解决问题能力来决定若系统性学习,跟着讲师的节奏走,大概半年左右,有专业的讲师把课程进行规划,尽心系统学习,有问题,讲师会帮忙解决,学习的效率很高,避免了自学中出现各种问题解决不了,而耽误很多时间,可能会...

  • 回答 23
    已采纳

    (1)idea启动时会有两个快捷方式,安装完后默认生成在桌面的是32位的idea的快捷方式,如果我们使用这个快捷方式运行大项目,一般都会很卡。解决方法是找到idea的安装目录,然后进入bin文件夹,找到名称为idea64的应用程序,右键他生成桌面快捷方式。以后每次...

  • BIO与NIO、AIO的区别2020-05-19 15:59
    回答 4
    已采纳

    IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。一、BIO     在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要...

  • Java方法的命名规则2021-04-06 19:07
    回答 31

    ava是一种区分字母的大小写的语言,所以我们在定义变量名的时候应该注意区分大小写的使用和一些规范,接下来我们简单的来讲讲Java语言中包、类、变量等的命名规范。(一)Package(包)的命名Package的名字应该都是由一个小写单词组成,例如com、xuetang9、compan...

  • 回答 2

    public class Point {    private int x;    private int y;    public int getX() {        return x;    }    public void setX(int x) {        this.x = x;    }    public int getY() {        return y;    } ...

  • 回答 6

    经典版单例模式public class Singleton {        private static Singleton uniqueInstance;//利用一个静态常量来记录singleton类的唯一实例。     private Singleton() {     }     public static  Singleton getInstance()...

  • 回答 3

    哈希表的长度一般是定长的,在存储数据之前我们应该知道我们存储的数据规模是多大,应该尽可能地避免频繁地让哈希表扩容。但是如果设计的太大,那么就会浪费空间,因为我们跟不用不到那么大的空间来存储我们当前的数据规模;如果设计的太小,那么就会很容易发...

  • 回答 14

    1. DOM(Document Object Model)        DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才...

  • 回答 19

    1)作用不同: throw用于程序员自行产生并抛出异常; throws用于声明在该方法内抛出了异常2) 使用的位置不同: throw位于方法体内部,可以作为单独语句使用; throws必须跟在方法参数列表的后面,不能单独使用。3)内容不同: throw抛出一个异常对象,且只能是...

  • 回答 11

    基本执行过程如下:1)程序首先执行可能发生异常的try语句块。2)如果try语句没有出现异常则执行完后跳至finally语句块执行;3)如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。4)catch语句块可以有多个,分别捕获不同类型...

  • 回答 20

    100-199 用于指定客户端应相应的某些动作。 200-299 用于表示请求成功。 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。 400-499 用于指出客户端的错误。 400 语义有误,当前请求无法被服务器理解。 401 当前请求需要用户验证...

  • 回答 16

    异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译...

没有解决我的问题,去提问