• JAVA 反射机制....


    PS:最近数据库算是学完了,总算是有时间回头复习一下以前学的东西了...最近这几天好好复习了一下反射机制,顺便也做个总结...JAVA的学习基本都没有去写...慢慢补上吧...

    学习内容:

    1.反射机制的概念...

    2.反射机制的作用...

    3.如何去使用反射机制...

    4.反射机制的优势...

    1.反射机制:

      反射机制,想必大家都不陌生,但是估计大家也就是知道个概念...那么到底什么是反射机制,估计大家对这个概念有点模糊不清...简单的概念就是:对于我们定义的每一个类,在任何的时刻,我们都能够知道这个类里面的属性和方法...对于任何一个对象,都能够调用这个类中的方法...这就是反射机制的基本概念..

    2.反射机制实现的功能:

    在运行时判断任意一个对象所属的类,在运行时构造任意一个类的对象,在运行时判断任意类所具有的方法和属性,在运行时调用任意一个对象的方法

    生成动态代理...

    3.如何使用反射机制:

    我们如何去使用反射机制呢?

    反射机制里一个特点就是实例化class对象,因为任意一个类对象都是class的实例...那么如何实例化class对象呢?三种方法:

    i.通过forname()方法...

    ii.对象.getclass();

    iii.类.class;

    在程序运行时通过实例化的对象,然后对象使用反射来调用类内的方法或者是属性...这样就实现了动态的获取信息...

    package Fanshe;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Scanner;
    
    class person{
        private String name;
        private String sex;
        private int age;
        
        person(){
            
        }
        public person(String name,String sex,int age){
            super();
            this.name=name;
            this.sex=sex;
            this.age=age;
        }
        private void setname(String name){
            this.name=name;
        }
        public String getsex(){
            return sex;
        }
        public void setsex(String sex){
            this.sex=sex;
        }
        public int getage(){
            return age;
        }
        public void setage(){
            this.age=age;
        }
        public String toString(){
            return "姓名 :"+name+"年龄: "+age;
        }
    }
    
    class reflectdemo{
         
          reflectdemo(){
             Scanner cin=new Scanner(System.in);
             String classpath=cin.nextLine();//需要输入类的完整路径...我的路径是Fanshe.person
             try {
                            //三种方式实现对象的实例化
                Class cla=Class.forName(classpath);
    //            Class cla_1=person.class;
    //            person p=new person();
    //            Class cla_2=p.getClass();
                Method [] method=cla.getDeclaredMethods();//定义一个数组来保存类中所有的方法...
                System.out.println("=====类中的方法有=====");
                for(Method meth:method){
                    System.out.println(meth.toString());
                }
                System.out.println("=====方法获取结束=====");
                Field [] field=cla.getDeclaredFields(); //保存类中所有属性
                System.out.println("=====类中内部的属性=====");
                for(Field fie:field){
                    System.out.println(fie.toString());
                }
                System.out.println("=====属性获取结束=====");
                Constructor [] con=cla.getDeclaredConstructors();//类中所有的构造函数...
                System.out.println("=====获取构造函数=====");
                for(Constructor c:con){
                    System.out.println(c.toString());
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                System.out.println("路径输入错误");
            }
          }
    }
    
    public class fanshe_2 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            reflectdemo ref=new reflectdemo();
        }
    
    }

    上述代码通过使用反射机制来获取类中的方法和属性...反射这东西我还是用代码说话更好一些,所以我还是都使用代码来让大家理解的更深刻一些...

    package Fanshe_cll;
    import java.lang.reflect.Method;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.annotation.Annotation;  
    
    class reflectdemo{
        
        //私有构造函数
        private reflectdemo(String name,int age){
        }
        reflectdemo(){
        }
        //公有构造函数
        public reflectdemo(String name){
        }
        public void info(){
        }
    public void info(String str){
        }
    private void set(){
    }
        class inner{
        }//内部类...
    }
    
    import Fanshe_cll.reflectdemo.inner;
    public class clear1 {
    
        public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            reflectdemo r=new reflectdemo();
            Class claz_1=r.getClass();
            System.out.println(claz_1.toString());
            Class<reflectdemo> cla=reflectdemo.class;  //使用泛型,用class来实例化对象..
            System.out.println(cla.toString());
            Class claz=Class.forName("Fanshe_cll.reflectdemo");
            System.out.println(claz.toString());
            System.out.println("=====类中的构造函数=====");
            //获取全部的构造函数....
            Constructor []constructor=cla.getDeclaredConstructors();//返回类中所有的构造函数,无论是公有的还是私有的...并且这个保存是按照倒序保存的..
    就是constructor[0]保存的是最后一个构造函数...而constructor[length-1]保存的是第一个构造函数...比如说我们有一个person类,类中有四个构造方法...
    public Person(){}
    public Person(String name){this.name=name;}
        public Person(int age){this.age=age;}
        public Person(String name,int age){this.age=age;this.name=name;}
    我们在主函数来调用这几种方法...
    Class<?> cla=Person.class;
            Constructor []con=cla.getDeclaredConstructors();
    Person per_1=(Person) con[0].newInstance("剑神",20);
           Person per_2=(Person) con[1].newInstance(20);
            Person per_3=(Person) con[2].newInstance("剑圣");
           Person per_4=(Person) con[3].newInstance(); 必须这样传参才行,如果把他们倒过来,那么必定会出现java.lang.illegalArgumentException非法参数异常..
    for(Constructor con:constructor){ System.out.println(con.toString()); } System.out.println("公有构造函数"); //获取公有的构造函数.... Constructor []constructor_1=cla.getConstructors();//这个就和上面不同了,这个保存着类中所有的公有构造函数 for(Constructor con_1:constructor_1){ System.out.println(con_1.toString()); } System.out.println("获取全部方法"); //获取全部的方法.... Method [] method =cla.getDeclaredMethods(); for(Method meth:method){ System.out.println(meth.toString()); } //获取公有的方法.... System.out.println("获取公有方法"); Method [] method_1=cla.getMethods(); for(Method meth_1:method_1){ System.out.println(meth_1.toString());//这个输出异常处理的函数..这说明有些方法是带有异常的... } //获取指定的某个方法.... System.out.println("获取某个指定的方法"); Method method_2=cla.getMethod("info",null);//获取参数为空的info方法.. System.out.println(method_2.toString()); Method method_3=cla.getMethod("info", String.class);//获取指定参数为字符串的方法... System.out.println(method_3.toString()); // Method method_4=cla.getMethod("info", reflectdemo.class); System.out.println("-----------------"); // System.out.println(method_4.toString()); System.out.println("-----------------"); //获取注释 System.out.println("获取注释"); Annotation []annotations =cla.getAnnotations(); for(Annotation ant:annotations){ System.out.println(ant.toString()); } //获取包信息 System.out.println("获取包信息"); Package package_1=cla.getPackage(); System.out.println(package_1.toString()); //获取内部类 System.out.println("获取内部类"); Class [] cla_1=cla.getDeclaredClasses(); for(Class clazz : cla_1){ System.out.println(clazz.toString()); } //调用父类 System.out.println("调用父类"); Class cla_2=cla.getSuperclass(); System.out.println(cla_2.toString()); //内部类对象... Class cla_3=Class.forName("Fanshe_cll.reflectdemo$inner"); // Class cla_4=inner.class; //获取内部类的外部类 System.out.println("使用内部类来获取外部类信息"); System.out.println(cla_3.getDeclaringClass()); System.out.println("--------------"); System.out.println(cla_3.getPackage()); System.out.println(cla_3.getSuperclass()); } }

    我们上面只是返回类中的方法...基本没有进行调用,那么下面就对上面的那些方法进行调用...

    package Fanshe_c;
    import java.lang.reflect.Method;
    class person{         //这个类大家基本不用看,是一个很普通的类,之所以粘出来是因为自己定义了好几个person类,怕产生混淆....
        private String name;
        private String sex;
        private int age;
        
        person(){
            
        }
        public person(String name,String sex,int age){
            super();
            this.name=name;
            this.sex=sex;
            this.age=age;
        }
        public void setname(String name){
            this.name=name;
        }
        public String getname(){
            return name;
        }
        public String getsex(){
            return sex;
        }
        public void setsex(String sex){
            this.sex=sex;
        }
        public int getage(){
            return age;
        }
        public void setage(int age){
            this.age=age;
        }
        public String toString(){
            return "姓名 :"+name+"年龄: "+age;
        }
    }
    public class cll_2 {
    
        public static void main(String[] args) throws Exception{
            // TODO Auto-generated method stub
            Class cla=person.class;
            person p=new person();//定义一个对象..使用new关键字..
            Method method=cla.getMethod("setname",String.class);
            method.invoke(p, "剑神");//这句话还可以写成 method.invoke(cla.newInstance(),"剑神");下面凡是和这句话类似的都可以使用这种方法,使用newInstance()的默认构造函数去实例化一个对象..
            Method method_1=cla.getMethod("setage",int.class);
            method_1.invoke(p, 20);
            Method method_2=cla.getMethod("setsex", String.class);
            method_2.invoke(p, "男");
            //调用输出方法...
            Method method_3=cla.getMethod("getname", null);
            System.out.println((method_3.invoke(p, null)).toString());
            Method method_4=cla.getMethod("getsex", null);
            System.out.println((method_4.invoke(p,null)).toString());
            Method method_5=cla.getMethod("getage", null);
            System.out.println((method_5.invoke(p, null)).toString());
        }
    
    }

    通过上面的代码,大家难免会产生一个疑问,就是使用new和newInstance去创建对象到底有什么区别呢??这个我也在这里进行下解释...

    new与newInstance()的区别

    首先一个是关键字,一个是方法...new是一个关键字,使用关键字来新建一个对象的时候没有过多的限制...而newInstance()是一个方法,使用newInstance()创建对象的时候,类一定要有一个默认的无参构造方法...并且这个类必须要被加载,否则的话JVM首先会将这个类进行加载后,然后我们才能使用newInstance()来新建一个对象...那么大家就会问了,那给出两个创建对象的方法,是不是有点多此一举了呢?这个当然是否定的...使用newInstance()...其实在一定情况下是很有好处的...大家来看:

    Class c = Class.forName("darker");
    factory = (AInterface)c.newInstance();
    其中AInterface是darker的接口,在看下面
    String className = "darker";
    Class c = Class.forName(className);
    factory = (AInterface)c.newInstance();
    进一步的进行扩展...
    String className = readfromXMlConfig;//从xml 配置文件中获得字符串
    Class c = Class.forName(className);
    factory = (AInterface)c.newInstance();
    上面代码把类名darker彻底的去掉了,这个优点估计大家都看出来了,这样当我们的darker类做怎样的修该,我们这句话永远保持不变...如果使用new就没办法了吧??
                

    这就是newInstance()在一定的地方使用的好处...

    简单的介绍一下setAccessible()函数...

    package Fanshe_fuzhi;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Calendar;
    class Person {   //这个代码目的是为了简单的介绍一下setAccessible()函数。。
        private String name;
        private String gender;
        private int age;
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getGender() {
            return gender;
        }
        public void setGender(String gender) {
            this.gender = gender;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        
        public String getSay(){
            return"姓名:"+this.name+" 	性别:"+this.gender+"	年龄:"+this.age;
        }
    }
    public class Fanshe_quanxian {
    
        public static void main(String[] args) throws Exception{
            // TODO Auto-generated method stub
            Class<?> cla=Person.class;
            Field name=cla.getDeclaredField("name");
            System.out.println(name);
            name.setAccessible(true);   //这个函数的参数是boolean类型,当值为true的时候,那么JVM将忽略访问时的权限...如果为false,那么就不进行忽略...
            name.set(cla.newInstance(),"三丰");
            Field gender=cla.getDeclaredField("gender");
            gender.setAccessible(true);
            gender.set(cla.newInstance(),"重阳");
            Field age=cla.getDeclaredField("age");
            age.setAccessible(true);
            age.setInt(cla.newInstance(), 20);
            Method getsay=cla.getMethod("getSay");
            Object obj=getsay.invoke(cla.newInstance());
            System.out.println(obj.toString());
        }
    
    }

    Modifyers函数...很简单,没什么东西...

    package Fanshe_modifier;
    
    import Fanshe_Person.Person;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    
    public class Modify {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Class<?> cla = Person.class;
            Field[] field = cla.getDeclaredFields();
            for (int i = 0; i < field.length; i++) {
                int mo = field[i].getModifiers();
                System.out.println(mo);
                String priv = Modifier.toString(mo);
                System.out.println(priv);
                Class<?> type =field[i].getType();
                System.out.println(type.getName());
                System.out.println(field[i].getName());
                /*
                 * 直接toString就可以返回方法的名字...
                 * field[i].toString
                 * */
            }
        }
    
    }

    动态创建和访问数组...

    package Array;
    import java.lang.reflect.Array;
    public class Array_1 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Object obj=Array.newInstance(int.class,3);
            /*
             *一维数组的创建与赋值..
             */
            Array.set(obj, 0, 20);
            Array.set(obj, 1, 30);
            int obj_1=Array.getLength(obj);
            System.out.println(obj_1);
            Object obj_2=Array.get(obj, 0);
            System.out.println(obj_2);
            Array.set(obj, 2, 40);
            int obj_3=Array.getLength(obj);
            System.out.println(obj_3);
    
    
            Object two_arr=Array.newInstance(int.class, 10,10);
            /*
             * 二维数组的赋值:先找到第一维的下标值..然后再传参..
             * */
            Object firstindex=Array.get(two_arr, 0);
            Array.set(firstindex, 0, 20);
            
        }
    
    }

    动态修改数组的大小...

    package Array;
    import java.lang.reflect.Array;
    public class Array_xiugailength {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            int temp[]={0,1,2,3,4,5,6,7,8,9};
            int newtemp[]=(int [])arrayinc(temp,15);
            for(int i=0;i<newtemp.length;i++){
                System.out.println(newtemp[i]);
            }
        }
        public static Object arrayinc(Object obj,int len){
            Class<?>arr=obj.getClass().getComponentType();
            Object newArr=Array.newInstance(arr, len);
            return newArr;
        }
    }

    4.反射机制的应用场合:

    大家不禁会这样问,什么时候能够使用到反射机制呢,并且它的应用场合是什么...并且它的优势到底在哪里呢?

    package Fanshefactory;
    interface factory_1{
        public abstract void show();
    }
    class A implements factory_1{
        public void show(){
            System.out.println("A");
        }
    }
    class B implements factory_1{
        public void show(){
            System.out.println("B");
        }
    }
    /*
     * 当增添类去实现接口的时候,我们就需要改变factory,当我们添加的类过多的时候
     * 我们的修改量就会很大...可以使用反射进行解决...
     * */
    class Factory{
        public static factory_1 getInstance(String fname){
            factory_1 f=null;
            if("A".equals(fname)){
                f=new A();
            }
            if("B".equals(fname)){
                f=new B();
            }
            return f;
        }
    }
    public class Fanshe_factory_1 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            factory_1 f=Factory.getInstance("A");
            f.show();
        }
    
    }
    
    
    package Fanshe_factory1;
    interface factory_2{
        public abstract void show();
    }
    class AA implements factory_2{
        public void show(){
            System.out.println("A");
        }
    }
    class BB implements factory_2{
        public void show(){
            System.out.println("B");
        }
    }
    
    class Factory_1{
        public static factory_2 getInstance(String fname){
              factory_2 f=null;
              try {
                Class cla=Class.forName(fname);
                f=(factory_2)cla.newInstance();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
              return f;
        }
    }
    public class Fanshe_factory_2 {
    
        public static void main(String[] args) throws Exception{
            // TODO Auto-generated method stub
            factory_2 f=Factory_1.getInstance("Fanshe_factory1.AA");
                    if(f!=null){
                     f.show();
                    }
        }
    
    }

      这两个代码形成对比,一个是未使用反射机制的工厂模式,一个是使用了反射机制的工厂模式...估计大家看完没什么过多的感觉...但是这里比如说我们要添加更多的类去实现我们暴露出的接口,那么我们Factory类里的判断部分也要进行大量的修改...这么做会代码冗余...那么用了反射的我们就没必要进行修改了,因为我们是使用class实例化的对象,class是字节码文件,无论类如何变,这个字节码文件只有一个,那么这样就可以直接实例化对象....我们没必要进行一个一个判断了....这就是反射的优势,在一定程度上解决代码冗余,并且可以动态的去获取类的信息...这样我们就感觉java就像动态语言一样..因此反射机制是很强大的一个东西...

  • 相关阅读:
    java核心学习(十六) javaIO框架---Process类的流,读写其他进程
    java核心学习(十五) IO框架---重定向标准输入输出
    java核心学习(十四) IO框架---推回输入流
    java核心学习(十三) IO框架---转换流和缓冲流
    java核心学习(十二) IO框架---理解IO流
    递推+矩阵快速幂 HDU 2065
    树形DP hdu1520
    二分图之最小路径覆盖 HDU1151
    二分图之最小独立集 HDU 2768
    最短路 POJ2267
  • 原文地址:https://www.cnblogs.com/RGogoing/p/4507997.html
Copyright © 2020-2023  润新知