Java反射机制详解

262 阅读5分钟

静态VS动态语言

动态语言(弱类型语言)是运行时才确定数据类型的语言,变量在使用之前无需申明类型,通常变量的值是被赋值的那个值的类型。比如Php、Asp、JavaScript、Python、Perl等等。

var s ="hello";
var i = 0;
var b = true;

静态语言(强类型语言)是编译时变量的数据类型就可以确定的语言,大多数静态语言要求在使用变量之前必须生命数据类型。比如Java、C、C++、C#等。

String s="hello";    //String 类型的变量
boolean b=true;    //boolean 类型的变量
int i=0;    //int 类型的变量

弱类型语言是数据类型可以被忽略的语言。它与强类型语言相反,一个变量可以赋不同数据类型的值。一个变量的类型是由其上下文决定的,效率更高。

强类型语言是必须强制确定数据类型的语言,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这种数据类型。一个变量的类型是申明的时候就已经确定的,更安全。

静态语言由于强制声明数据类型,让开发工具(IDE)对代码有很强的判断能力,在实现复杂的业务逻辑和开发大型商业系统、以及那些声明周期很长的应用中,开发者可以依托强大的IDE来更高效、更安全地开发。

动态语言思维不受约束,可以任意发挥,把更多的精力放在产品本身上;集中思考业务逻辑实现,思考过程就是实现过程。

反射(Reflection)

什么是反射?

反射的概念:在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

一般而言,说到动态语言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言。但JAVA它却有着一个非常突出的动态相关机制:反射。通过反射,Java可以于运行时加载、探知和使用编译期间完全求和的类、生成其对象实体,调用其方法或者对属性设值。所以Java算是一个半动态的语言吧。

Class c = Class.forName("java.lang.String");

加载完类之后,在堆内存的方法区中就会产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了类的结构信息,我们可以通过这个对象看到类的信息。这个对象就像一面镜子,透过这个镜子看到类的信息,所以我们形象的称之为:反射:

动态性质

  • 运行时生成对象实例;
  • 运行期间调用方法;
  • 运行时更改属性

反射机制能实现的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意怀个类所具有的方法和属性
  • 在运行时调用任意一个对象的方法
  • 生成动态代理

优缺点

  • 优点:可以实现动态创建对象和编译,体现出很大的灵活性
  • 缺点:对性能有影响。使用反射基本上是一种解释操作,我们告诉JVM,我们需要做什么并且它会满足我们的要求,这类操作总是慢于 直接执行相同的操作

应用

  • 创建一个实体类User
public class User {

    private String name;
    private int id;
    private int age;

    public User() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }
}
  • 获取Class类的实例的几种方法
    //若已知具体的类,通过类的class属性获取
    Class c1 = User.class;
    //已知某个类的实例,通过该实例的getClass()方法获取Class对象
    Class c2 = user.getClass();
    //已知一个类的全名,且该类在类路径下,通过Class.forName("")获取,可能抛出ClassNotFoundException
    Class c3 = Class.forName("org.example.reflection.User");
  • 获取类运行时结构
   public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c = Class.forName("org.example.reflection.User");
        System.out.println(c.getName()); //包名+类名
        System.out.println(c.getSimpleName());//类名
        System.out.println("----------------------------");
        //获取类的属性
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("----------------------------");
        //获取本类中指定的属性
        Field name = c.getDeclaredField("name");
        System.out.println(name);
        System.out.println("-----------------------------");
        //获取类的方法
        Method[] methods = c.getMethods();//获取本类以及父类的public方法
        for (Method method : methods) {
            System.out.println("method:"+method);
        }
        System.out.println("----------------------------------");
        Method[] declaredMethods = c.getDeclaredMethods();//获取本类的所有的方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println("declaredMethod:"+declaredMethod);
        }
        System.out.println("------------------------------");
        //获取构造方法
        Constructor[] constructors = c.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
    }
  • 动态的创建对象
   public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获取class实例
        Class c = Class.forName("org.example.reflection.User");
        //通过newInstance() 构造一个User对象
        User user = (User) c.newInstance();//调用了无参构造器
        System.out.println(user);
        System.out.println("-------------------");
        //通过构造器创建一个对象
        Constructor constructor = c.getDeclaredConstructor(String.class,int.class,int.class);
        User user1 = (User) constructor.newInstance("马云", 001, 55);
        System.out.println(user1);
        System.out.println("--------------------");
        //通过反射构造一个对象
        User user2 = (User) c.newInstance();
        //通过反射获取一个方法
        Method setName = c.getDeclaredMethod("setName",String.class);
        //invoke激活的意思
        setName.invoke(user2,"马云");
        System.out.println(user2.getName());
        System.out.println("------------------");
        User user3 = (User) c.newInstance();
        //通过反射获取一个属性
        Field name = c.getDeclaredField("name");
        //不能直接操作私有属性,关闭程序的安全检测setAccessible(true),默认是false
        name.setAccessible(true);
        name.set(user3,"雷军");
        System.out.println(user3.getName());
    }
  • 获取注解的信息
public class Test {
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //获取class实例
        Class c = Class.forName("org.example.reflection.Student");
        //通过反射获取注解
        Annotation[] annotations = c.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //通过反射获取注解的value的值
        TableAnnotation table = (TableAnnotation) c.getAnnotation(TableAnnotation.class);
        String[] value = table.value();
        for (String s : value) {
            System.out.println(s);
        }
        //获取类指定的注解
        Field f = c.getDeclaredField("name");
        FieldAnnotation annotation = f.getAnnotation(FieldAnnotation.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }
}

@TableAnnotation("db_student")
class Student{

    @FieldAnnotation(columnName = "db_name",type = "varchar",length = 10)
    private String name;
    @FieldAnnotation(columnName = "db_age",type = "int",length = 3)
    private int age;
    @FieldAnnotation(columnName = "db_id",type = "int",length = 10)
    private int id;

    public Student() {
    }

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

    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;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

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

//类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableAnnotation {

    String[] value() default "";//默认为空
}

//属性注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface FieldAnnotation {
    String columnName();//属性名
    String type();//属性类型
    int length();//字段长度
}