反射的基本概念

  • 什么是反射:反射就是把java中的各个部分,映射成一个个的java对象,也可以理解为这是一种创建对象的方式,然后利用这个对象来做一些事情。既然说反射是反射java类中的各个组成部分,那么一个类的组成部分都有些啥呢,例如一个类中有:成员方法、成员变量、构造方法等信息。利用反射技术咱们可以把这些组成部分映射成一个个对象。
  • Class ;一个类对象
  • Constuructor;类中的构造方法
  • Method;类中的方法
  • Field;类中的属性
获取class文件的三种方式
  1. 使用Class类中的静态方法forName(“文件名”)来获取class文件。(假如是java原生态的类,就要写上在那个包里面)
  2. 直接用文件名获取
  3. 调用Object里面的getclass()方法。 引用.getclass();
@java
    public class Test01 {

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

         //第一种获取class文件的方式
         Class c1 = Class.forName("java.util.Date");
         
         //第二种获取class文件的方式。
        Class c2  = Date.class;
        
        //第三种获取class文件的方式
        Date date = new Date();    
        Class c3 =date.getClass();
        
        System.out.println(c1==c2);
        System.out.println(c2==c3);

    }

}

验证获取的是不是同一个class文件,就去判断是否指向同一个内存地址。
运行结果:

@java

true
true

Process finished with exit code 0
利用反射创建实例

newInstance();创建此类对象表示类的新实例。就是创建一个无参的构造方法。
如果此类对象没有无参的构造方法,会报java.lang.InstantiationException(类实例化失败)异常。

@java
      public class ReflectTest01 {

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

              //执行了静态块,A这个类加载了,说明这个方法可以将A类扔到java虚拟机里面。
//            Class.forName("com.qh.利用反射创建实例.A");



//            不执行静态块
//            Class c1= A.class;



              //newInstance ;创建一个新的实例
              Object o = Class.forName("com.qh.利用反射创建实例.A").newInstance();
              if (o instanceof A){
                  A a = (A)o;
                  a.m1();
              }
          }
      }

      class A{
          //静态块,类加载的时候加载,而且只加载一次
          static <u>{</u>
              System.out.println("Just I miss you !");
          }

          public void m1(){
              System.out.println("张三!");
          }
      }

利用可变参数创建多个类的实例

@java
      public class ReflectTest02 {

          public static void m1(Class...c) throws Exception{

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

                  Object o = c[i].newInstance();

                  System.out.println(o);

              }

          }

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

              <u>Class</u> a = <u>Date</u>.class;

              <u>Class</u> b= Exception.class;

              m1(a,b);

          }

      }

运行结果

@java
Thu Oct 08 15:42:25 CST 2020
java.lang.Exception

Process finished with exit code 0
通过反射机制获取类的属性(Field)
  1. Class类Api:

String getSimplename();返回源代码中给出的基础类的简单名称。
int getModifiers()返回此类或接口的Java语言修饰符,以整数编码。
Field getDeclaredField(String name)返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。
Field [] getDeclaredFields()返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。
Field getField(String name)返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段类对象。
Field[] getFields()返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共成员字段类对象。

  1. Field类Api:

String getName();返回由此 Field对象表示的字段的名称。
Class<?> getType()返回一个类对象标识了此表示的字段的声明类型 Field对象。
int getModifiers()返回此类或接口的Java语言修饰符,以整数编码。

  1. Modifier类Api:

String toString()返回对象的字符串表示形式。

反编译一个类的所有属性包括修饰符、声明类型


@java
      public class ReflectTest03 {

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

              //1.获取一个类
              Class c = Class.forName("java.util.Date");
              //2.利用类获取一个属性数组
              <u>Field</u>[] fie = c.getDeclaredFields();
              StringBuffer sb = new StringBuffer();
              sb.append(<u>Modifier</u>.toString(c.getModifiers())+" class 
"+c.getSimpleName());
              sb.append("{\n");
              for (<u>Field</u> field:
                   fie) {
                  //3. 获取属性的修饰符
                  sb.append("\t"+<u>Modifier</u>.toString(field.getModifiers())+" 
");
                  //4.获取属性的类型
                  sb.append(field.getType().getSimpleName()+" ");
                  //5.获取属性的名字
                  sb.append(field.getName()+"\n");
              }
              sb.append("}");
              System.out.println(sb.toString());
          }
      }

      class Person {
          private String <u>name</u> ;
          public int age;
          protected String sex;
          boolean hird;
      }

运行结果:

public class Date{
    private static final BaseCalendar gcal
    private static BaseCalendar jcal
    private transient long fastTime
    private transient Date cdate
    private static int defaultCenturyStart
    private static final long serialVersionUID
    private static final String[] wtb
    private static final int[] ttb
}

利用反射机制获取类的单个属性:

  1. Field类Api:

void set(Object o,Object valut);给对象的属性赋值
Object get(Object o);查看这个对象的属性值

  1. Field继承AccessibleObject类Api:

void setAccessible(boolean b);打破属性的封装性。

@java
public class ReflectFieldTest01 {
    public static void main(String[] args) throws Exception {
        Properties p = new Properties();
        Reader rea = new FileReader("D:\\Fieldreflect.properties");
        p.load(rea);
        rea.close();
        String fieldName = p.getProperty("FieldName");
        
        //获取一个类
        Class c = Class.forName("com.qh.利用反射获得类中的属性.Persion");
        Field field = c.getDeclaredField(fieldName);
        Object o = c.newInstance();
        
        //打破属性的封装性
        field.setAccessible(true);
        
        //给o对象里面的属性赋值。
        Scanner input = new Scanner(System.in);
        System.out.println("请为该属性赋值:");
        field.set(o,input.next());
        
        //输出o对象里面的field属性值
        System.out.println("该属性的值:"+field.get(o));
    }
}

运行结果:

请为该属性赋值:
男
该属性的值:男
利用反射机制获取一个类的方法(Method)

1. 利用反射机制获取一个类的所有方法
Class类Api:
Method[] getDeclaredMethods();返回一个Method类型的数组
Method getDeclaredMethod(String name, 类<?>... parameterTypes);返回一个 方法对象,它反映此表 示的类或接口的指定声明的方法 类对象。
Method getMethod(String name, 类<?>... parameterTypes)返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 类对象。
Method getMethods();返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
Method类Api:
int Modifiers();返回一个方法修饰符所代表的int类型的值
String getname();返回方法的名字
String getReturnType();返回方法的返回值
String getParameterTypes();返回一个方法内的形式参数类型数组

@java

public class MethodReflectTest01 {
    public static void main(String[] args) throws Exception {
        //获取一个类
        Class c= Class.forName("com.qh.利用反射获得类中的方法.Register");
        //通过一个类获取所有方法
        Method[] m = c.getDeclaredMethods();
        //将所有的方法遍历
        for (Method me:
             m) {
            //方法的修饰符
            int modifiers = me.getModifiers();
            System.out.println(Modifier.toString(modifiers));
            //方法的返回值
            Class returnType = me.getReturnType();
            System.out.println(returnType.getSimpleName());
            //方法名字
            System.out.println(me.getName());
            //方法的参数类型
            Class[] parameterTypes = me.getParameterTypes();
            for (Class parameterType:
                 parameterTypes) {
                System.out.println(parameterType.getSimpleName());
            }
        }
    }
}

运行结果:

public
void
love
public
boolean
login
String
String

通过反射机制获取特定的指定方法:
Object invoke(Object o,Object..age);运行o对象的方法,传入age参数,返回一个Object结果。

@java

public class MethodReflectTest03 {
    public static void main(String[] args) throws Exception {
        //获取一个类
        Class c= Class.forName("com.qh.利用反射获得类中的方法.Register");
        //获取指定的方法,与获取属性不同的是,属性特殊的属性名,而调用单个方法是方法名和形参列表
        Method m = c.getDeclaredMethod("login",String.class,String.class);
        //运行login方法
        Object autonomo = m.invoke(c.newInstance(), "Autonomo", "123");
        System.out.println(autonomo);
    }
}

里面的方法名,传入的参数都可以写一个properties配置文件来代替,这样写不会吧代码写死,反射就是讲究代码的灵活性。
运行结果:

true

运行了login方法

利用反射机制获取一个类的构造方法(Constuructor)

反编译一个类的所有构造方法
所用的方法与Method类里面的一样

@java

public class ConstructorReflectTest02 {
    public static void main(String[] args) throws Exception {
        //获取一个类
        Class c = Class.forName("java.lang.String");
        //获取这个类里面所有的构造方法,返回一个Constructor类型的数组
        Constructor[] co = c.getDeclaredConstructors();
        //创建一个StringBuffer进行连续的字符串拼接
        StringBuffer sb = new StringBuffer();
        sb.append(Modifier.toString(c.getModifiers())+ " class "+c.getSimpleName()+"{\n");
        for (Constructor con:
             co) {
            sb.append("\t");
            //获取方法的修饰符
            sb.append(Modifier.toString(con.getModifiers())+" ");
            //获取方法名,方法名就是类名,可以直接获取类名
            sb.append(c.getSimpleName()+"(");
            //形参列表类型
            Class[] parameterTypes = con.getParameterTypes();
            for (int i = 0; i < parameterTypes.length; i++){
                if (i<parameterTypes.length-1){
                    sb.append(parameterTypes[i].getSimpleName()+",");
                }else{
                    sb.append(parameterTypes[i].getSimpleName());
                }
            }
            sb.append("){}\n");
        }
        sb.append("}");
        System.out.println(sb.toString());
    }
}

这里是输出了String类里面所有的构造方法,只输出了结构,并没有输出具体内容
运行结果:

public final class String{
    public String(byte[],int,int){}
    public String(byte[],Charset){}
    public String(byte[],String){}
    public String(byte[],int,int,Charset){}
    public String(byte[],int,int,String){}
     String(char[],boolean){}
    public String(StringBuilder){}
    public String(StringBuffer){}
    public String(byte[]){}
    public String(int[],int,int){}
    public String(){}
    public String(char[]){}
    public String(String){}
    public String(char[],int,int){}
    public String(byte[],int){}
    public String(byte[],int,int,int){}
}

获取一个类特有的构造方法
Constructor: Object newInstance(Object...args);使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
(调用了构造方法就是调用了tostring方法)

@java

public class ConstructorReflectTest03 {
    public static void main(String[] args) throws Exception {
        //获取一个类
        Class c = Class.forName("com.qh.利用反射获得类中的构造方法.Person");
        //获取指定的构造方法,构造方法名字都一样,只是参数不一样
        Constructor con = c.getDeclaredConstructor(String.class,int.class);
        //
        Object con1 = con.newInstance("张三", 15);
        System.out.println(con1);
 

运行结果

Person{name='张三', age=15}
利用反射机制获取类的父接口和父类

Class类:
Class getSuperclass(); 返回 类表示此所表示的实体(类,接口,基本类型或void)的超类 类 。
Class[] getInterfaces();确定由该对象表示的类或接口实现的接口。

@java

public class ConstructorReflectTest03 {
    public static void main(String[] args) throws Exception {
        //获取一个类
        Class c = Class.forName("com.qh.利用反射获得类中的构造方法.Person");
        //获取指定的构造方法,构造方法名字都一样,只是参数不一样
        Constructor con = c.getDeclaredConstructor(String.class,int.class);
        //
        Object con1 = con.newInstance("张三", 15);
        System.out.println(con1);
    }
}

运行结果:

继承的父类:Object
实现的父接口:
Serializable
Comparable
CharSequence

Autonomy
15 声望2 粉丝