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就像动态语言一样..因此反射机制是很强大的一个东西...

原文地址:https://www.cnblogs.com/RGogoing/p/4507997.html