java 反射

本文围绕Java反射展开,介绍了反射获取类的几种方式,如Class.forName、对象.getClass等。还阐述了通过反射给对象赋值、调用方法、使用构造器等操作。此外,提及内省、BeanUtils、注解的相关知识,并给出实现简单ORMapping框架的案例,最后指出可结合Aop和注解实现ORm。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  Spring中往往一个注解(如@Controller@Service)就可以完成一些复杂的操作。注解应用于反射之上,反射是java的重中之重。反射强调的是运行时状态,获取类的方法和属性的一些信息。

一、获取类

  通过反射获取类的几种方式:

1、通过Class.forName

        Class<?> clazz =  Class.forName("java.lang.String");
        //获取所有的方法
        Method[] methods = clazz.getDeclaredMethods();
        for(Method method : methods){
            System.out.println(method);
        }

        System.out.println("-------------");

        //获取所有public的方法
        Method[] publicMethods = clazz.getMethods();
        for(Method method : publicMethods){
            System.out.println(method);
        }
        System.out.println("-------------");

        //获取所有属性
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            System.out.println(field);
        }
        System.out.println("-------------");

        //获取所有public的属性
        Field[] pubilcFields = clazz.getFields();
        for(Field field : pubilcFields){
            System.out.println(field);
        }
        System.out.println("-------------");

        //获取构造方法
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors){
            System.out.println(constructor);
        }
2、对象.getClass
        String str = "sss";
        Class<?> clazz = str.getClass();
3、类.class
        Class<?> clazz = String.class;

二、给对象赋值

1、通过反射给对象赋值。

  定义一个对象:

public class Student {
    private String name;
    private String sex;
    private Integer age;

    public Student(String name, String sex, Integer age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public Student() {
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }

    public String doNothing(Integer a){
        System.out.println(a);
        return "nothing";
    }
}
        Class<?> clazz = Class.forName("reflection.Student");

        //创建一个对象
        Student student = (Student)clazz.newInstance();
        //设置名字属性
        Field field = clazz.getDeclaredField("name");
        //强制写入private对象
        if(!field.isAccessible()) {
            field.setAccessible(true);
        }
        field.set(student,"娃哈哈");
        System.out.println(student);
2、调用方法
        Class<?> clazz = Class.forName("reflection.Student");

        //创建一个对象
        Student student = (Student) clazz.newInstance();
        //得到方法
        Method method = clazz.getDeclaredMethod("doNothing", Integer.class);

        String str = (String) method.invoke(student,100);
        System.out.println(str);
3、构造器的使用
        Class<?> clazz = Class.forName("reflection.Student");
        //得到构造器
        Constructor constructor = clazz.getConstructor(String.class, String.class, Integer.class);
        Student student = (Student)constructor.newInstance("娃哈哈", "男", 100);
        System.out.println(student);
4、构造器的小应用

  一般的情况下,List中存放的是一个同一数据类型的数据,现在要求将不同数据类型的数据放在同一个List中。这种要求可定需要使用反射来完成。

List<String> students = new ArrayList<String>();
        students.add("娃哈哈同学");
        students.add("康师傅同学");
        //报错
//        students.add(1234);

        Class<?> clazz = students.getClass();
        Method method = clazz.getMethod("add", Object.class);
        method.invoke(students, 1234);
        for (Object object: students){
            System.out.println(object);
        }

三、内省

  内省是Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。

        Student student = (Student.class).newInstance();
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor("age", Student.class);
        Method method = propertyDescriptor.getWriteMethod();//setAge
        method.invoke(student,100);
        System.out.println(student);

  这种方式要求属性值要分装有get/set方法。

四、BeanUtils

  这种方式常见于Spring Web中,获取URL后面所带参数。这个带上Bean所以属性值也是要带上set/get方法。需要导入commons-beanutils包。

Student student = (Student.class).newInstance();
//Date需要手工转化
BeanUtils.setProperty(student,"name","娃哈哈");
System.out.println(student);

  常见的用法,这样就把URL的参数都设置进去了。

Map<String, Object> map = new HashMap<String, Object>();
map.put("name","娃哈哈");
map.put("age", 20);
map.put("sex","女");
Student student = (Student.class).newInstance();
BeanUtils.populate(student,map);

System.out.println(student);

五、注解

  注解就是放在类名、属性、方法上的标注,这个标注用于之后业务代码的处理。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyBean {
    String table();
    
    String auth() default "娃哈哈";
}

  Target表示该注解能放在类上,属性上,还是方法上。Retention表示存活周期,一般是运行时。Inherited表示这个注解可以用于子类中。

@MyBean(table = "animal")
public class Animal {
    @MyField("name")
    private String name;
}
Class<?> clazz = Class.forName("annotation.Animal");
if (clazz.isAnnotationPresent(MyBean.class)) {
    MyBean myBean = clazz.getAnnotation(MyBean.class);
    System.out.println(myBean.table());
}

六、案例

  根据上面讲的,自己实现一个关系型数据库的简单ORMapping框架。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyBean {
    String table();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyField {
    String value();
}
@MyBean(table = "animal")
public class Animal {

    @MyField("nick_name")
    private String name;

    @MyField("real_age")
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class AnimalUtils {
    public static String getTableName(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }
        MyBean myBeanAnnotation = clazz.getAnnotation(MyBean.class);
        if (myBeanAnnotation != null) {
            return myBeanAnnotation.table();
        } else {
            return clazz.getSimpleName().toLowerCase();
        }
    }

    public static String getColumnName(Field field) {
        if (field == null) {
            return null;
        }
        MyField myFieldAnnotation = field.getAnnotation(MyField.class);
        if (myFieldAnnotation != null) {
            return myFieldAnnotation.value();
        } else {
            return field.getName();
        }
    }

    public static String getMethodName(Field field, String type) {
        String name = field.getName();
        return type + name.substring(0, 1).toUpperCase()
                + name.substring(1);
    }

    public static <T extends Object> String getDbSaveSql(T t) {
        StringBuilder sb = new StringBuilder();
        Class<?> clazz = t.getClass();
        sb.append(" insert into ");
        //表名
        String tableName = getTableName(clazz);
        sb.append(tableName).append(" ( ");
        //字段名
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (!"id".equals(field.getName())) {
                String columnName = getColumnName(field);
                sb.append(columnName).append(",");
            }
        }
        sb.deleteCharAt(sb.toString().length() - 1)
                .append(" ) values (");

        for (Field field : fields) {
            if (!"id".equals(field.getName())) {
                sb.append("?").append(",");
            }
        }
        sb.deleteCharAt(sb.toString().length() - 1)
                .append(" )");

        return sb.toString();
    }

    public static <T extends Object> List<Object> getValues(T t) throws Exception {
        List<Object> columnValues = new ArrayList<Object>();
        Class<?> clazz = t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String methodName = getMethodName(field, "get");
            Method method = clazz.getDeclaredMethod(methodName);
            columnValues.add(method.invoke(t));
        }
        return columnValues;
    }
}
public class AnnotationApp {
    public static void main(String[] args) throws Exception {
        Animal animal = new Animal();
        animal.setName("娃哈哈");
        animal.setAge(12);
        String sql = AnimalUtils.getDbSaveSql(animal);
        List<Object> valus = AnimalUtils.getValues(animal);

        Connection connection = DbUtils.getConnection();
        PreparedStatement pstmt = connection.prepareStatement(sql);
        int index = 1;
        for (Object culomnValue : valus) {
            pstmt.setObject(index++, culomnValue);
        }
        int rowCount = pstmt.executeUpdate();
    }
}

七、后续

  以上的代码看着比较难过,还可以使用Aop和注解相互结合实现ORm。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值