java反射机制浅析

1.反射机制的概念:
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。

  反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!


  类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字。
2.反射机制的作用
在运行时判断任意一个对象所属的类;
在运行时获取类的对象;
在运行时访问java对象的属性,方法,构造方法等。
(所有类都是class实例)


3.反射机制的优缺点
首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。

反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

  比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。

反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。


反射机制的示例:

所列都是class的实例

package reflect;

/**
 * 获得一个对象完整的包名和类名
 */
 class Reflect {
     //example code
 }
class Demo {

    public static void main(String[] args) {
        //初始化Reflect
        Reflect reflect = new Reflect();
        //获取Reflect对象的包名和类名
        System.out.println(reflect.getClass().getName());

    }
}
运行结果:

reflect.Reflect



----------
2.实例化class对象(获取类对象的三种方式)

package reflect;

/**
* 实例化类对象,获取类对象的三种方式
*/
class Reflect {
//example code
}
class Demo {

public static void main(String[] args) {
    Class<?> demo1 = null;
    Class<?> demo2 = null;
    Class<?> demo3 = null;

    //第一种方式
    String className = "reflect.Reflect";
    try {
        demo1 = Class.forName(className);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    //第二种方式
    demo2 = new Reflect().getClass();

    // 第三种方式
    demo3 = Reflect.class;


    // 打印结果
    System.out.println("第一种"+demo1.getName());
    System.out.println("第二种"+demo2.getName());
    System.out.println("第三种"+demo3.getName());

}

}

运行结果:
第一种reflect.Reflect
第二种reflect.Reflect
第三种reflect.Reflect

注释: 准确的讲是一个ClassLoader下,一种类,只会有一个类对象存在,3种方式
1. Class.forName
2. Hero.class
3. new Hero().getClass()

在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。


3.通过Class实例化其他类的对象
实例化Person对象初始化Person对象,并对Person属性进行操作
注:Class.newInstance只能调用无参构造
    Constructor.newINstance只能调用有参构造

测试类代码:

package reflect;

/**
* 通过反射获取Person的属性
*
* @author BxTizen
*/
public class PersonReflect {
public static void main(String[] args) {

    // 建立Class模型对象
    Class<?> demo = null;

    //获取Person类对象,同时会初始化类的属性
    try {
        demo = Class.forName("reflect.Person");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    //准备一个Person类的属性,指向null
    Person person = null;

    //通过 newInstance实例化对象
    try {
        person = (Person) demo.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    //给实例化对象赋值
    person.setAge(23);
    person.setName("23333");

    //打印person的属性
    System.out.println(person);
}

}



----------


Person实体类:
package reflect;

/**
 * 通过反射获取Person的属性
 *
 * @author BxTizen
 */
public class PersonReflect {
    public static void main(String[] args) {

        // 建立Class模型对象
        Class<?> demo = null;

        //获取Person类对象,同时会初始化类的属性
        try {
            demo = Class.forName("reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //准备一个Person类的属性,指向null
        Person person = null;

        //通过 newInstance实例化对象
        try {
            person = (Person) demo.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        //给实例化对象赋值
        person.setAge(23);
        person.setName("23333");

        //打印person的属性
        System.out.println(person);
    }
}
运行的结果:
Person{name='23333', age=23}


----------
4.通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)

首先,了解一下构造器
获取类的构造器 
首先介绍一下Constructor类,这个类用来封装反射得到的构造器,Class有四个方法来获得Constructor对象
public Constructor<?>[] getConstructors() 返回类中所有的public构造器集合,默认构造器的下标为0
public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回指定public构造器,参数为构造器参数类型集合
public Constructor<?>[] getDeclaredConstructors() 返回类中所有的构造器,包括私有
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回任意指定的构造器

获取类的成员变量 
成员变量用Field类进行封装,主要的方法非常的类似:
public Field getDeclaredField(String name) 获取任意指定名字的成员
public Field[] getDeclaredFields() 获取所有的成员变量
public Field getField(String name) 获取任意public成员变量
public Field[] getFields() 获取所有的public成员变量

获取类的方法 
public Method[] getMethods() 获取所有的共有方法的集合
public Method getMethod(String name,Class<?>... parameterTypes) 获取指定公有方法 参数1:方法名 参数2:参数类型集合 
public Method[] getDeclaredMethods() 获取所有的方法
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 获取任意指定方法
(以上的了解一下,可以查询javaAPI文档详细的)



Constructor<?> cons[]=demo.getConstructors();

//无参构造函数
Object object0 = (Object)cons[0].newInstance();
Object object1 = (Object)cons[1].newInstance(parameter);
//多参构造函数
Object object2 = (Object)cons[2].newInstance(parameter1,parameter);

构造函数取出来是有顺序的,Constructor<?> cons[]=cls.getConstructors()的cons[]数组下标对应的对象类里面的构造函数顺序相反,如上例中:最后一个构造方法Person(String name, int age)对应于cons[0],第一个构造方法Person()对应于cons[3];顺序不对会造成参数不正确的异常:

接下来看代码示例:

package reflect;

import java.lang.reflect.Constructor;

public class PersonReflect2 {
public static void main(String[] args) {
Class


实体类:

package reflect;

public class Person {
private int age;
private String name;

public Person() {

}

public Person(String name) {
    this.name = name;
}
public Person(int age) {
    this.age = age;
}
public Person(String name, int age) {
    this.name = name;
    this.age = age;
}

public int getAge() {
    return age;
}

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

public String getName() {
    return name;
}

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

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

}


运行结果:
Person{age=0, name='null'}
Person{age=0, name='Rollen'}
Person{age=20, name='null'}
Person{age=20, name='Rollen'}


----------
5.返回一个构造类的实接口
接口类:

package reflect1;

public interface China {
public static final String name = “Rollen”;
public static int age = 20;

public void sayChina();

public void sayHello(String name, int age);

}

接口实现实体类:

package reflect1;

public class Person implements China {
private String sex;

public String getSex() {
    return sex;
}

public void setSex(String sex) {
    this.sex = sex;
}

public Person() {
}

@Override
public void sayChina() {
    System.out.println("hello ,china");
}

@Override
public void sayHello(String name, int age) {
    System.out.println(name + "  " + age);
}

}

测试类:

package reflect1;

public class Hello {
public static void main(String[] args) {
Class



----------


6.取得其他类中的父类

package reflect1;

public class Hello {
public static void main(String[] args) {
Class



----------


7.获得其他类中的全部构造函数

package reflect1;

import java.lang.reflect.Constructor;

public class Hello {
public static void main(String[] args) {
Class

运行结果:
构造方法:  public reflect1.Person()


----------


获取构造方法的全部:

package reflect1;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class Hello {
public static void main(String[] args) {
Class

运行结果:
构造方法:  public reflect1.Person(){}


----------


8.取得其他类的全部属性,将这些整理在一起,也就是通过class取得一个类的全部框架

package reflect1;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Hello {
public static void main(String[] args) {

    Class<?> demo = null;
    try {
        demo = Class.forName("reflect1.Person");
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("===============本类属性========================");
    // 取得本类的全部属性
    Field[] field = demo.getDeclaredFields();
    for (int i = 0; i < field.length; i++) {
        // 权限修饰符
        int mo = field[i].getModifiers();
        String priv = Modifier.toString(mo);
        // 属性类型
        Class<?> type = field[i].getType();
        System.out.println(priv + " " + type.getName() + " "
                + field[i].getName() + ";");
    }
    System.out.println("===============实现的接口或者父类的属性========================");
    // 取得实现的接口或者父类的属性
    Field[] filed1 = demo.getFields();
    for (int j = 0; j < filed1.length; j++) {
        // 权限修饰符
        int mo = filed1[j].getModifiers();
        String priv = Modifier.toString(mo);
        // 属性类型
        Class<?> type = filed1[j].getType();
        System.out.println(priv + " " + type.getName() + " "
                + filed1[j].getName() + ";");
    }
}

}

运行结果:

===============本类属性========================
private java.lang.String sex;
===============实现的接口或者父类的属性========================
public static final java.lang.String name;
public static final int age;


----------
9.通过反射调用其他类中的方法

package reflect1;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Hello {
public static void main(String[] args) {
Class


运行结果:
hello ,china
Rollen  20


----------
10.调用其他类的setget方法

package reflect1;

import java.lang.reflect.Method;

public class Hello {
public static void main(String[] args) {
Class


运行结果:
男


----------
11.通过反射操作属性

package reflect1;

import java.lang.reflect.Field;

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


运行结果:
男


----------
12.通过反射取得并修改数组的信息

package reflect1;

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public class Hello {
public static void main(String[] args) {
int[] temp={1,2,3,4,5};
Class

运行结果:
数组类型: int
数组长度  5
数组的第一个元素: 1
修改之后数组第一个元素为: 100


----------
13.修改数组大小通过反射

package reflect1;

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public class Hello {
public static void main(String[] args) {
int[] temp={1,2,3,4,5,6,7,8,9};
int[] newTemp=(int[])arrayInc(temp,15);
print(newTemp);
System.out.println(“=====================”);
String[] atr={“a”,”b”,”c”};
String[] str1=(String[])arrayInc(atr,8);
print(str1);
}
/**
* 修改数组大小
* */
public static Object arrayInc(Object obj,int len){
Class

运行结果:
数组长度为: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
数组长度为: 8
a b c null null null null null 
Process finished with exit code 0


----------
14.获取类加载器
实体类

package reflect2;

public class Demo {
//test
}

测试类:

package reflect2;

public class DemoTest {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(“类加载器”+demo.getClass().getClassLoader().getClass().getName());
}
}

“`

发布了17 篇原创文章 · 获赞 3 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览