文章目录

  • 反射
  • 反射概述
  • 获取Class对象的三种方法:
  • 通过Class.forName()获取class对象,它会把参数指定的类加载到内存中
  • 反射类class的信息
  • class对象方法 - 01
  • 获取反射类的代码示例
  • 通过反射技术访问类的字段(属性方法)并赋值
  • class对象方法 - 02
  • 通过反射技术反射类的字段(属性)
  • 通过反射技术反射方法
  • Class对象方法 - 03
  • 通过反射技术反射类的方法


反射

反射概述

反射就是根据字节码文件(Class),反射类的信息、字段、方法、构造方法等类的内容,然后根据字节码文件来创建对象,调用方法的技术

没有源码,只有字节码文件也能够运行

反射的基础前提,是Class对象!【记住这个非常非常非常重要,反射都是基于类Class对象的】

什么是Class类:

比如小猫可以抽象为Cat类,小狗抽象为Dog类,小猪抽象为Pig类,人可以抽象为Person类,字符串抽象为String类,然后在将这些抽象的Cat/Dog/Pig/Person/String等所有的类再抽象为一个Class类。

Class类描述所有类的共同特征。

获取Class对象的三种方法:

  1. 每个通过class属性获取。【类名.class
  2. 每个对象通过getClass()方法获取。【对象.getClass()
  3. 通过**Class.forName(“类的完整名”)**获取,需要捕获异常。【Class.forName(“类的完整名”)
/*
* 获取class对象的方法
* */
public class GetClasssObject {
    public static void main(String[] args) {
        //1、每个类通过class属性 获取
        Class classObject1 = GetClasssObject.class;

        //2、每个对象通过getClass()方法获取。
        Class classObject2 = new GetClasssObject().getClass();

        //通过Class.forName("类的完整名")获取 需要抛出异常
        Class classObject3 = null;
        try {
            classObject3 = Class.forName("com.xgf.reflect.GetClasssObject");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //获取int Integer的class对象
        Class intClass = int.class;
        Class integerClass1 = Integer.class;


        System.out.println("classObject1 : " + classObject1);
        System.out.println("classObject2 : " + classObject2);
        System.out.println("classObject3 : " + classObject3);
        System.out.println("intClass : " + intClass);
        System.out.println("integerClass1 : " + integerClass1);

    }
}

运行结果:

java 通过反射 判断是不是字符串 反射判断字段类型_java 通过反射 判断是不是字符串

发现三种方式都可以获取类的对象,结果相同!

通过Class.forName()获取class对象,它会把参数指定的类加载到内存中

package com.xgf.bean;
public class User {
    static {
        System.out.println("我是User的一个静态代码块");
    }
}
/*
* 通过Class.forName()获取class对象,它会把参数指定的类加载到内存中
*   通过测试是否运行了类的static静态代码块来判断是否加载到内存中
* */
public class ClassFormName {

    public static void main(String[] args) {

        System.out.println(" 1、类.Class ");
        Class<User> userClass = User.class;
        System.out.println();//换行

        System.out.println(" 2、 Class.forName(完整类名) ");
        try {
            Class<?> aClass = Class.forName("com.xgf.bean.User");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

运行结果(只有class.forName()方法运行了User类的静态代码块)

java 通过反射 判断是不是字符串 反射判断字段类型_jvm_02

总结:

1. 类名.class  不将类加载到内存,Class.forName()会将类加载到内存
2. 对象.getClass()创建对象就会加载到内存中去

反射类class的信息

class对象方法 - 01

class对象方法

描述

int getModifiers()

获取反射类的修饰符,需要通过Modifier.toString()将其转化为字符串

getName()

返回完整类名(java.lang.String)

getSimpleName()

返回简易类名(String)

getSuperclass()

获取反射类的父类

getInterfaces()

获取反射类的接口数组,如果没有实现接口,返回长度为0

获取反射类的代码示例

public class ReflectParentClass {
    public static void main(String[] args) {
        //1、通过类名获取Calss对象
        Class<String> stringClass = String.class;

        StringBuilder sb = new StringBuilder();//字符串拼接

        //2、通过class对象获取反射类的信息
        //2.1 getModifiers()获取反射类的修饰符
        int modifiers = stringClass.getModifiers();
        //Modifier.toString()将其转化为字符串,拼接到StringBuilder
        sb.append(Modifier.toString(modifiers));


        //2.2 getName()获取反射类的类名
        sb.append(" class ");//public final class java.lang.String 需要拼接class
        //getName()返回完整类名 : java.lang.String
        sb.append(stringClass.getName());
        //getSimpleName()返回简易类名 String
        //sb.append(stringClass.getSimpleName());

        //2.3 getSuperclass()获取反射类的父类
        Class superclass = stringClass.getSuperclass();
        sb.append(" extends ");//拼接关键字
        sb.append(superclass);

        //2.4 getInterfaces() 获取反射类的接口,如果没有实现接口,返回长度为0
        Class<?>[] interfaces = stringClass.getInterfaces();
        if( interfaces.length > 0){
            sb.append(" implements ");
            //遍历接口数组
            for(int i = 0; i<interfaces.length; i++){
                sb.append(interfaces[i].getSimpleName());//获取接口简易名
                //不是最后一个接口需要用逗号,隔开
                if(i != interfaces.length-1){
                    sb.append(",");
                }
            }
        }
        //输出拼接的类信息
        System.out.println(sb);
    }
}

运行结果:这里的接口我用了getSimpleName()获取的是它们的简易名

java 通过反射 判断是不是字符串 反射判断字段类型_java 通过反射 判断是不是字符串_03

通过反射技术访问类的字段(属性方法)并赋值

class对象方法 - 02

方法名

描述

Field getField(string fields, mixed condition, string spea)

获取反射的字段。fields 必须有,需要查询的字段名称,可以是一个或多个字段。condition 可选,查询条件,可以是字符或数组。spea 多个字段数据生成关联数组时,数据间隔符号,默认为空格。 如果输入的字段名称fields在反射类中找不到就会抛出NoSuchFieldException异常这个方法只能访问公共字段(public),但是可以通过setAccessible(true)方法设置访问权限,就可以访问private的字段了

Field 、getDeclaredField()

该方法可以访问所有的字段,包括私有字段(private)

Object newInstance()

通过反射对象创建类的实例,默认调用类的无参构造方法创建对象

Field方法

描述

field.set(对象名,字段值)

给object对象的field字段赋值

field.get(对象名)

返回字段的值

field.setAccessible(true)

设置字段的访问属性,比如getField()获取的字段只能访问public的,可以通过该方法设置为true访问

通过反射技术反射类的字段(属性)

public class User {

    static {
        System.out.println("我是User的一个静态代码块");
    }
    public String userName;
    public int userAge;

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", userAge=" + userAge +
                '}';
    }
}
/*
* 通过反射技术反射类的字段(属性) -- 反射User类
*   并给字段赋值
* */
public class ReflectClassField {
    public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
        //1、通过类名获取User的Calss对象 反射的前提是Class对象
        Class<User> userClass = User.class;

        System.out.println(" === 给user对象的userName赋值 ===");
       //2、getField()获取 反射User的字段username 反射字段要与类字段一致,否自会报NoSuchFieldException
        Field userNameField = userClass.getField("userName");
        
		//getDeclaredField()方法能访问所有的字段,包括私有的
        //Field declaredField = userClass.getDeclaredField("userName");
        
        //3、设置字段的值(给字段赋值),对对象赋值,就需要创建对象
        //3.1 newInstance()通过反射技术创建对象的实例,默认调用类的无参构造方法
        User user = userClass.newInstance();    //相当于new User()

        //3.2 field.set(对象名,字段值) 设置字段的值 赋值
        userNameField.set(user,"我通过userNameField字段设置了userName的值");
        System.out.println(user);
        
        //3.3 field.get(对象名)返回字段的值
        System.out.println(userNameField.get(user));

        System.out.println("\n === 给user对象的setAge赋值 ===");
        Field userAgeField = userClass.getField("userAge");//获取字段
        userAgeField.set(user,20);//赋值
        System.out.println(user);

    }
}

运行结果:

java 通过反射 判断是不是字符串 反射判断字段类型_java反射基础_04



通过反射技术反射方法

Class对象方法 - 03

方法名

描述

getMethod(方法名, 方法参数类型列表)

反射指定方法签名的公共public方法

Method.invoke(对象实例名,方法参数列表)

通过invoke调用方法

通过反射技术反射类的方法

public class User {

    static {
        System.out.println("我是User的一个静态代码块");
    }
    public String userName;
    public int userAge;

    /* 有参构造方法 */
    public void set(String userName,int userAge){
        this.userName = userName;
        this.userAge = userAge;
        System.out.println("调用set方法");
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", userAge=" + userAge +
                '}';
    }
}
public class ReflectClassMenthod {
    public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1、通过类名获取User的Calss对象 反射的前提是Class对象
        Class<User> userClass = User.class;

        //2、getMethod(方法名, 方法参数类型列表)  反射指定方法签名的公共public方法
        //反射toString方法  -- 无参构造方法
        Method toStringMethod = userClass.getMethod("toString", null);

        //3、 newInstance()通过反射技术创建对象的实例,默认调用类的无参构造方法
        User user = userClass.newInstance();//相当于new User()

        //4、 调用方法 方法.invoke(对象实例名,方法实参列表)
        toStringMethod.invoke(user,null);

        //5、反射有参构造方法set
        Method setMethod = userClass.getMethod("set", String.class, int.class);
        setMethod.invoke(user,"set对象设置userName",21);

        System.out.println(user);

    }
}

运行结果

java 通过反射 判断是不是字符串 反射判断字段类型_java_05