java反射机制

对于反射机制,学了有两遍,实际工作中用的不多,但是用来理解框架还是很有帮助的,打算花点时间把java基础的一些内容总结一遍,然后把框架再仔细搞搞。

 

一、反射机制概述

JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能知道这个类所有的属性和方法。

对于任意一个对象,都能够调用它的任意一个方法和属性。

这种动态获取的信息以及动态调用对象的方法的功能成为java语言的反射机制。

 

其实就是:动态获取类中的信息。可以理解为对类的解剖。

 

反射的应用场景:spring框架中是有大量用到反射技术的;其次在完成的应用中,可以通过配置文件,将要新增功能的类名提供给应用,然后应用通过反射机制获取这个类,并使用这个功能。

 

 

二、类加载机制初步

小写class表示是一个类类型,大写Class表示这个类的名称。Class是一个类,封装了当前对象所对应的类的信息;对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。

 

1,获取Class对象的三种方式

 

(1)通过类名获取 类名.class

// 1.通过类名

clazz = Person.class;

(2)通过对象获取 对象名.getClass()

 

// 2.通过对象名

// 这种方式是用在传进来一个对象,却不知道对象类型的时候使用

Person person = new Person();

clazz = person.getClass();

// 上面这个例子的意义不大,因为已经知道person类型是Person类,再这样写就没有必要了

// 如果传进来是一个Object类,这种做法就是应该的

Object obj = new Person();

clazz = obj.getClass();

(3)通过全类名获取 Class.forName(全类名)

 

// 3.通过全类名(会抛出异常)

// 一般框架开发中这种用的比较多,因为配置文件中一般配的都是全类名,通过这种方式可以得到Class实例

String className = "zday06_reflect.Person";

clazz = Class.forName(className);

 

 

2,类加载类ClassLoader

 

类装载器是用来把类(class)装载进 JVM 的。

JVM 规范定义了两种类型的类装载器:启动类装载器(bootstrap)

和用户自定义装载器(user-defined class loader)。

 

测试代码:

// 1. 获取一个系统的类加载器(可以获取,当前这个类ClassTest就是它加载的)

ClassLoader classLoader = ClassLoader.getSystemClassLoader();

System.out.println(classLoader);

 

// 2. 获取系统类加载器的父类加载器(扩展类加载器,可以获取).

classLoader = classLoader.getParent();

System.out.println(classLoader);

 

// 3. 获取扩展类加载器的父类加载器(引导类加载器,不可获取).

classLoader = classLoader.getParent();

System.out.println(classLoader);

 

// 4. 测试当前类由哪个类加载器进行加载(系统类加载器):

classLoader = Class.forName("zday06_reflect.ClassTest").getClassLoader();

System.out.println(classLoader);

 

// 5. 测试 JDK 提供的 Object 类由哪个类加载器负责加载(引导类)

classLoader = Class.forName("java.lang.Object").getClassLoader();

System.out.println(classLoader);

 

首先,系统类加载器可以加载当前项目src目录下面的所有类,

如果文件也放在src下面,也可以用类加载器来加载

3,加载类的过程

// 为了使用类而做的准备工作一般有以下3个步骤:

// 加载:由类加载器完成,找到对应的字节码,创建一个Class对象

// 链接:验证类中的字节码,为静态域分配空间

// 初始化:如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块

// 不会初始化静态块

Class clazz1 = Base.class;

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

// 会初始化

Class clazz2 = Class.forName("zday06_reflect.Base");

Base base = new Base();

System.out.println(clazz2);

System.out.println(base.getClass());

 

三、反射技术的相关操作

 

1.获取与操作方法

 

测试类:Person:

//Java让我们在运行时识别对象和类的信息,主要有2种方式:

//一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;

//另一种是反射机制,它允许我们在运行时发现和使用类的信息。

public class Person implements Serializable {

 

private String name;

private int age;

// get/set方法

 

public Person(String name, int age) {

this.name = name;

this.age = age;

}

 

public Person() {

}

 

public String getName() {

 

return name;

}

 

public void setName(String name) {

 

this.name = name;

}

 

public int getAge() {

 

return age;

}

 

public void setAge(int age) {

 

this.age = age;

}

 

private void privateMethod() {

 

System.out.println("privateMethod");

}

 

@Override

public String toString() {

 

return "name : " + name + ";age=" + age;

}

}

 

1.1 获取取clazz对应类中的所有方法--方法数组(一)

 

不能获取private方法,且获取从父类继承来的所有方法

Method[] methods = clazz.getMethods();

for (Method method : methods) {

System.out.print(" " + method.getName());

}

1.2.获取所有方法,包括私有方法 --方法数组(二)

// 所有声明的方法,都可以获取到,且只获取当前类的方法

methods = clazz.getDeclaredMethods();

for (Method method : methods) {

System.out.print(" " + method.getName());

}

System.out.println();

 

1.3.获取指定的方法

 

// 需要参数名称和参数列表,无参则不需要写

// 对于方法public void setName(String name) { }

Method method = clazz.getDeclaredMethod("setName", String.class);

System.out.println(method);

// 而对于方法public void setAge(int age) { }

method = clazz.getDeclaredMethod("setAge", int.class);

System.out.println(method);

// 这样写是获取不到的,如果方法的参数类型是int型

// 如果方法用于反射,那么要么int类型写成Integer: public void setAge(Integer age) { }

// 要么获取方法的参数写成int.class

1.4执行方法

 

// invoke第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的参数

Object obje = clazz.newInstance();

method.invoke(obje, 2);

 

总结:

// 这种反射实现的主要功能是可配置和低耦合。只需要类名和方法名,

// 而不需要一个类对象就可以执行一个方法。

// 如果我们把全类名和方法名放在一个配置文件中,

// 就可以根据调用配置文件来执行方法

 

2,操作属性、私有属性

 

String className = "zday06_reflect.Person";

Class clazz = Class.forName(className);

 

2.1 获取所有字段 -- 字段数组

// 可以获取公用和私有的所有字段,但不能获取父类字段

Field[] fields = clazz.getDeclaredFields();

for (Field field : fields) {

System.out.print(" " + field.getName());

}

System.out.println();

 

2.2获取指定字段

Field field = clazz.getDeclaredField("name");

System.out.println(field.getName());

 

Person person = new Person("ABC", 12);

 

2.3获取指定对象的指定字段的值

Object val = field.get(person);

System.out.println(val);

 

2.4设置指定对象的指定对象Field值

field.set(person, "DEF");

System.out.println(person.getName());

 

2.5 如果字段是私有的,不管是读值还是写值,都必须先调用setAccessible(true)方法

// 比如Person类中,字段name字段是公用的,age是私有的

field = clazz.getDeclaredField("age");

field.setAccessible(true);

System.out.println(field.get(person));

 

3,操作构造函数

 

3.1 获取全部构造函数

Constructor<Person>[] constructors = (Constructor<Person>[]) Class.forName(className).getConstructors();

 

for (Constructor<Person> constructor : constructors) {

System.out.println(constructor);

}

 

3.2获取某一个,需要参数列表

Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);

System.out.println(constructor);

 

3.3 调用构造器的 newInstance() 方法创建对象

Object obj = constructor.newInstance("zhagn", 1);

 

4,获取注解

 

相关注解类:

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

@Retention(RetentionPolicy.RUNTIME)

@Target(value={ElementType.METHOD})

public @interface AgeValidator {

public int min();

public int max();

}

测试方法:

String className = "com.atguigu.java.fanshe.Person";

 

Class clazz = Class.forName(className);

Object obj = clazz.newInstance();

 

Method method = clazz.getDeclaredMethod("setAge", int.class);

int val = 6;

 

// 获取指定名称的注解

Annotation annotation = method.getAnnotation(AgeValidator.class);

if (annotation != null) {

if (annotation instanceof AgeValidator) {

AgeValidator ageValidator = (AgeValidator) annotation;

if (val < ageValidator.min() || val > ageValidator.max()) {

throw new RuntimeException("年龄非法");

}

}

}

method.invoke(obj, 20);

System.out.println(obj);

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值