前面我们讲了反射对象的获取和类的加载过程,接下来我们得讲下如何使用反射的class对象!
通过反射可以获取运行时类的完整结构:
①FIeld(属性)
②Method(方法)
③Constructor(构造器)
④Superclass(超类)
⑤Interface(接口)
⑥Annotation(注解)
示例代码如下:
Person类:
import lombok.Data;
@Data
public class Person extends Object{
private String name;
private int high;
private String like;
public Integer age;
public Person(){
}
private void priTest(String name){
}
public Person(String name){
}
}
测试代码:
public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
Class c1 = Class.forName("com.dbright.Java反射.Person");//forName获取
Person person = new Person();
Class c2 = person.getClass();//对象.class获取
Class c3 = Person.class;//类.对象
//获取类的名字
System.out.println("c1"+c1.getName());
System.out.println("c2"+c2.getName());
System.out.println("c3"+c3.getName());
System.out.println("简单:"+c1.getSimpleName());
System.out.println("* ****************************************************");
//获取类的属性
Field[] fields = c1.getFields();//只能获取public属性
for (Field field : fields) {
System.out.println("getFields:"+field);
}
Field[] fields1 = c1.getDeclaredFields();//获取所有属性
for (Field field : fields1) {
System.out.println("getDeclaredFields:"+field);
}
//获取指定名称的属性
System.out.println("getDeclaredField:"+c1.getDeclaredField("name"));
System.out.println("* ****************************************************");
//获得类的方法--包含父类的方法
Method[] methods = c1.getMethods();//只能获得公共方法
for (Method method : methods) {
System.out.println("getMethods:"+method);
}
Method[] methods1 = c1.getDeclaredMethods();//获得所有方法
for (Method method : methods1) {
System.out.println("getDeclaredMethods"+method);
}
//获得指定方法
Method method = c1.getMethod("getName",null);//无参直接传个null即可
Method method1 = c1.getMethod("setName", String.class);//带参传参数的对象即可
System.out.println("获得指定方法1:"+method);
System.out.println("获得指定方法2:"+method1);
System.out.println("* ****************************************************");
//获得构造器,注释不再加,和上面一致,公共和私有
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("getConstructors:"+constructor);
}
Constructor[] constructors1 = c1.getDeclaredConstructors();
for (Constructor constructor : constructors1) {
System.out.println("getDeclaredConstructors:"+constructor);
}
//获取指定的构造器--根据参数来确定是哪一个构造器
System.out.println("获取指定的构造器:"+c1.getConstructor());
System.out.println("获取指定的构造器:"+c1.getConstructor(String.class));
}
}
上面介绍了如何通过反射获取类的属性、方法和构造器等。那么如何动态的创建对象并且 执行 方法呢?
1、创建类的对象:调用Class对象的newInstance()方法
2、只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作
3、调用指定的方法:通过反射调用类中的方法,通过Method类完成
4、Object invoke(Object obj, Object … args)
5、setAccessible
代码示例:
前置代码:
import lombok.Data;
@Data
public class Person extends Object{
private String name;
private int high;
private String like;
public Integer age;
public Person(){
}
private void priTest(String name){
}
public Person(String name){
this.name = name;
}
}
测试代码:
/**
* 通过反射动态的创建对象
*/
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得class对象
Class c = Class.forName("com.dbright.Java反射.Person");
//构造一个对象,本质上是调用了无参构造器
Person person = (Person) c.newInstance();
System.out.println("person:"+person);
//通过有参构造器创建对象
Constructor constructor = c.getDeclaredConstructor(String.class);
Person person1 = (Person) constructor.newInstance("ding");//需要重写tostring方法
System.out.println("person1:"+person1);
//通过反射获取和操作方法
System.out.println("************************************************************");
Person person2 = (Person) c.newInstance();
Method setLike = c.getDeclaredMethod("setLike", String.class);
setLike.invoke(person2,"钓鱼");
System.out.println("person2:"+person2);
//通过反射操作属性
System.out.println("************************************************************");
Person person3 = (Person) c.newInstance();
Field name = c.getDeclaredField("name");
//关掉权限检测:不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法
name.setAccessible(true);
name.set(person3,"丁大大");
System.out.println("name:"+name.getName());
}
}
那么这两种方法有什么区别呢?
public class Test02 {
public static void main(String[] args) throws NoSuchMethodException {
test1();
test2();
test3();
}
/**
*普通方式调用
*/
public static void test1(){
Person person = new Person();
//获取当前系统时间
long startTime = System.currentTimeMillis();
for (int i=0; i<2000000000; i++){
person.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式调用所需时间:"+(endTime-startTime)+"ms");
}
/**
*反射方式调用
*/
public static void test2() throws NoSuchMethodException {
Person person = new Person();
Class c = person.getClass();
Method getName = c.getDeclaredMethod("getName",null);
//获取当前系统时间
long startTime = System.currentTimeMillis();
for (int i=0; i<2000000000; i++){
getName.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式调用所需时间:"+(endTime-startTime)+"ms");
}
/**
*反射方式调用 关闭检测
*/
public static void test3() throws NoSuchMethodException {
Person person = new Person();
Class c = person.getClass();
Method getName = c.getDeclaredMethod("getName",null);
//获取当前系统时间
long startTime = System.currentTimeMillis();
getName.setAccessible(true);//关闭安全检测
for (int i=0; i<2000000000; i++){
getName.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式调用所需时间:"+(endTime-startTime)+"ms");
}
}
执行结果如下:
结论: 使用反射调用时效率比较低,如果需要频繁使用反射调用的前提,请关闭安全检测!!!
测试代码如下:
public class Test03 {
//通过反射获取泛型
public void test01(Map<String, Person> map, List<Person> list){
System.out.println("test01");
}
public Map<String, Person> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test03.class.getMethod("test01", Map.class, List.class);
Type[] geners = method.getGenericParameterTypes();
for (Type gener : geners) {
System.out.println("*" + gener);
if (gener instanceof ParameterizedType){
Type[] actuals = ((ParameterizedType)gener).getActualTypeArguments();
for (Type actual : actuals) {
System.out.println(actual);
}
}
}
method = Test03.class.getMethod("test02", null);
Type geners1 = method.getGenericReturnType();
if (geners1 instanceof ParameterizedType){
Type[] actuals = ((ParameterizedType)geners1).getActualTypeArguments();
for (Type actual : actuals) {
System.out.println(actual);
}
}
}
}
前面我们学习了注解,接下来就看下注解和反射怎么使用?
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c = Person1.class;
//通过反射获取注解
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("annotation:"+annotation);
}
//获取注解的value的值
classAno classAno1 = (classAno) c.getAnnotation(classAno.class);
String value = classAno1.value();
System.out.println("value:"+value);
//获得类的指定注解
Field field = c.getDeclaredField("name");
methodAno methodAno1 = field.getAnnotation(methodAno.class);
System.out.println("name:"+methodAno1.name());
System.out.println("type:"+methodAno1.type());
System.out.println("length:"+methodAno1.length());
}
}
/**
* 测试类
*/
@Data
@classAno("Person1")
class Person1{
@methodAno(name = "丁大大",type = "超人类",length = 2)
private String name;
private int high;
private String like;
public Integer age;
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface classAno{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface methodAno{
String name();
String type();
int length();
}
执行结果:
第一遍看完可能有点懵,多看几遍加深理解吧!
在实际项目中多多使用,看看框架的底层加强自身的理解,冰冻三尺非一日之寒,有个大概的理解和印象即可!后面在实际中逐渐加强理解,这样才能融会贯通!
Java注解和反射扩展:Java注解和反射学习汇总
路漫漫其修远兮,吾必将上下求索~
如果你认为i博主写的不错!写作不易,请点赞、关注、评论给博主一个鼓励吧**转载请注明出处哦**