Java学习总结-反射

1、反射的概念。

是Java语言提供的一种机制,并不是所有语言都具备;反射可以实现在.java文件编译时,可以不明确类的具体类型,而在.class文件运行再去检查和明确这个类。

2、反射的原理。

  • 首先要了解一下java程序的运行步骤,源(.java)文件经过javac.exe编译后生成二进制(.class)文件,编译主要工作就是语法检查,然后通过java.exe去执行二进制文件,这时jvm会通过类加载器把二进制文件装入方法区,同时在堆中会创建一个描述这个类的对象,类型为java.lang.Class(注意是大写)。

  • 这个类描述的内容无非是装载类的基本属性:

class Class{

名称(类名)

字段(成员变量)

构造函数

一般函数(成员函数)

}

 


通过这个类可以获取到字节码文件的所有信息,而反射的就是依赖的这个字节码文件对象。


  • 也许你有疑问,获取这些信息能干什么呢?

1.  有了构造函数,你可以创建这个类的新的实例(对象)。

2.  可以返回字段值。

3.   执行一般函数等。

所有的工作都可以做,跟你拿到这个类的源代码是同样的效果。下面的工作就是怎么获取一个类的二进制文件的对象。


3、获取Class对象的三种方式

1、  通过Object类提供的getClass()方法。

2、  通过所有类都具备的静态属性.class。

3、  通过java.lang.Class的forName(String className)方法(重点)。

 

packageitcast.reflect.demo;
 
publicclass ReflectDemo {
         public static void main(String[] args)throws Exception{
                   //getClassObject_1()
                   //getClassObject_2()
                   getClassObject_3();
         }
         /*
          *1、Object类的getClass()方法。必须要明确具体的类,并创建对象
          */
         public static void getClassObject_1(){
                   Person p = new Person();
                   Class clazz = p.getClass();
                  
                   Person p1 = new Person();
                   Class clazz1 = p1.getClass();
                  
                   System.out.println(clazz ==clazz1);
         }
         /*
          *2、任何数据类型都具备一个静态属性.class来获取起对应的class对象
          */
         public static void getClassObject_2(){
                   Class clazz = Person.class;
                  
                   Class clazz1 = Person.class;
                  
                   System.out.println(clazz ==clazz1);
         }
         /*
          *3、通过java.lang.Class类的forName,根据类名的字符串形式,获取该类的二进制文件对象,这种方式只需名称即可,扩展性更强。
          */
         public static void getClassObject_3()throws Exception{
                   String name ="itcast.reflect.demo.Person";
                   Class clazz =Class.forName(name);
                   System.out.println(clazz);
         }
        
}
packageitcast.reflect.demo;
 
publicclass Person {
         private int age;
         private String name;
        
         public Person(String name,int age){
                   super();
                   this.age = age;
                   this.name = name;
                  
                   System.out.println("Personparam run..."+this.name+":"+this.age);
         }
        
         public Person(){
                   super();
                  
                   System.out.println("personrun");
         }
 
         public void show(){
                   System.out.println(name+"...showrun..."+age);
         }
        
         private void privateMethod(){
                   System.out.println("privateMethodrun");
         }
        
         public void paraMethod(String str,intnum){
                   System.out.println("paraMethodrun...."+str+":"+num);
                  
         }
         public static void staticMethod(){
                   System.out.println("staticmethod run....");
         }
}


4、获取构造函数(创建实例)

1、  如果是构建一个无参的实例,通过Class调用newInstance()方法。

2、  如果是构建一个有参数的实例,通过Class的getConstructor(Class<?>... parameterTypes)方法,根据传入的参数列表的类型去返回对象的构造函数对象,然后再调用newInstance(Object... initargs)方法创建实例。

 

packageitcast.reflect.demo;
 
importjava.lang.reflect.*;
 
publicclass ReflectDemo2 {
         public static void main(String[] args)throws Exception {
                   createNewObject_2();
         }
        
         public static void createNewObject()throws Exception{
                   //早期:new时候,先根据被new的名称找寻该类的字节码文件,并加载进内存,
                   //并创建该自己吗文件对象,并接着创建该字节文件的对应的Person对象
                   //itcast.bean.Person p = newcn.itcast.bean.Person();
                  
                   //现在:
                   String name ="itcast.reflect.demo.Person";
                   //找寻该名称类文件,并加载进内存,并产生Class对象
                   Class clazz =Class.forName(name);
                   //如何产生该类的对象呢
                   Object obj =clazz.newInstance();
                  
                  
         }
        
    public static void createNewObject_2()throws Exception{
                  
                   /*
                    * 当获取指定名称对应类中的所体现的对象是
                    * 而该对象初始化不适用空参数构造该怎么办呢
                    * 既然是通过指定的构造函数进行初始化,所以应该先获取该构造函数。
                    * 通过字节码文件对象就可以获得,指定的:getConstructor(Class<?>...parameterTypes) 全部:getConstructors() 全部(包含私有):getDeclareConstrunctors()
                    *
                    */
                    
                   String name ="itcast.reflect.demo.Person";
                   Class<?> clazz =Class.forName(name);
                   //获取到了指定的构造函数对象
                   Constructor constructor =clazz.getConstructor(String.class,int.class);
                   //通过该构造器对象的newInstance方法进行对象的初始化
                   Object obj =constructor.newInstance("小强",23);
                  
         }
}

5、返回Class中字段

  1. 公有的字段,通过Class的getField(String name),根据字段名去获取。
  2. 私有的,通过Class的getDeclaredField(String name)获取,又叫暴力获取。
  3. 以上返回Field对象,其中该对象的set(Object obj,Object value)方法可以修改对象中值。

packageitcast.reflect.demo;
 
importjava.lang.reflect.*;
 
publicclass ReflectDemo3 {
         public static void main(String[] args)throws Exception {
                   getFieldDemo();
         }
        
        
         public static void getFieldDemo()throws Exception {
                   Class<?> clazz =Class.forName("itcast.reflect.demo.Person");
                   //私有成员变量无法获取
                   //Field field=clazz.getField("age");
                   //暴力获取私有成员变量
                   Field field =clazz.getDeclaredField("age");
                  
                  
                   //获取指定参数的构造函数
                   Constructor constructor =clazz.getConstructor(String.class,int.class);
                  
                   //调用构造的函数传入参数,创建实例
                   Object obj  = constructor.newInstance("小强",23);
                  
                   //get(Object obj)返回指定对象上Field表示字段的值
                   //私有成员不能获取,通过SetAccessible()设置
                   field.setAccessible(true);
                  
                   field.set(obj,89);
                   Object value =field.get(obj);
                  
 
                  
                   System.out.println(value);
         }
 
}
 

6、 获取Class中方法

  1. 通过Class的getMethods()获取所有的公共方法,包括父类的。
  2. 通过Class的getDeclaredMethods()获取本类的方法,包括私有。
  3. 通过Class的getDeclaredMethod(String name,Class<?>... parameterTypes)获取单个方法,name表示函数名,parameterTypes表示参数。
  4. 以后返回Method对象,通过invoke(Object obj,Object... args),传入对象和参数值,执行该方法。

package itcast.reflect.demo;
 
import java.lang.reflect.*;
 
public class ReflectDemo4 {
     public static void main(String[] args) throws Exception {
              getMethodDemo_2();
     }
     /*
      * 获取指定Class中的公共函数
      */
    
     public static void getMethodDemo() throws Exception {
             
              Class clazz =Class.forName("itcast.reflect.demo.Person");
             
              Method[] methods = clazz.getMethods();//获取的都是公有的方法
             
              methods = clazz.getDeclaredMethods();//获取本类的所有方法
             
              for(Method method : methods){
                       System.out.println(method);
              }
 
     }
    
     public static void getMethodDemo_2() throws Exception {
              Class<?> clazz = Class.forName("itcast.reflect.demo.Person");
             
              Method method =clazz.getMethod("staticMethod",null);
             
              //Constructor constructor =clazz.getConstructor(String.class,int.class);
             
              //Object obj  =constructor.newInstance("小强",23);
             
              method.invoke(null,null);
     }
 
}


7、  反射的应用

通过读取配置文件,获取加载的类文件对象,然后动态执行程序,编码程序的修改。

 

packageitcast.reflect.test;
 
importjava.lang.reflect.*;
importjava.io.*;
importjava.util.*;
 
publicclass ReflectTest {
         public static void main(String[] args)throws Exception {
                   Mainboard mb = newMainboard();
                   mb.run();
                  
                   //每次添加一个设备都需要修改代码传递一个新创建的对象
                   //mb.usePCI(new SoundCard());
                   //能不能不修改代码就可以完成这个动作
                   //不用new来完成,而是值获取起class文件。
                  
                   File configFile = newFile("pci.properties");
                  
                   Properties prop = newProperties();
                  
                   FileInputStream fis = newFileInputStream(configFile);
                  
                   prop.load(fis);
                  
                   for(intx=0;x<prop.size();x++){
                            String pciName =prop.getProperty("pci"+(x+1));
                            Class clazz =Class.forName(pciName);
                            Object obj =clazz.newInstance();
                           
                            PCI p =(PCI)clazz.newInstance();
                           
                            mb.usePCI(p);
                   }
                  
                   fis.close();
         }
 
}

packageitcast.reflect.test;
 
//importitcast.reflect.test.PCI;
 
publicclass Mainboard {
        
         public void run() {
                   System.out.println("mainborad run...");
         }
        
         /*public void useSound(SoundCard c){
                   c.open();
                   c.close();
         }*/
        
         public void usePCI(PCI p){
                   if(p!=null){
                            p.open();
                            p.close();                   
                   }
 
         }
}

packageitcast.reflect.test;
 
publicinterface PCI {
        
         public void open();
        
         public void close();
}
 
packageitcast.reflect.test;
 
publicclass SoundCard implements PCI {
        
         public void open() {
                   System.out.println("soundopen");
         }
        
         public void close() {
                   System.out.println("soundclose");
         }
}

packageitcast.reflect.test;
 
publicclass NetCard implements PCI {
        
         public void open() {
                   System.out.println("netopen");
         }
        
         public void close() {
                   System.out.println("netclose");
         }
}
 

文件名:pci.properties:

pci1=itcast.reflect.test.SoundCard
pci2=itcast.reflect.test.NetCard

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值