JAVA反射基础

什么是反射?

反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

Oracle官方对反射的解释是:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to  operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or
 the members declared by a given class. It also allows programs to suppress default reflective access control.


反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

在这里先看一下Java反射API为我们提供了哪些类:

java.lang.Class;                
java.lang.reflect.AccessibleObject;
java.lang.reflect.Array;
java.lang.reflect.Constructor; 
java.lang.reflect.Field;        
java.lang.reflect.Method;
java.lang.reflect.Modifier;
java.lang.reflect.Proxy;

AccessibleObject类:
该类是域(field)对象、方法(method)对象、构造函数(constructor)对象的基础类。
它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。

Array类:
提供动态地生成和访问 JAVA 数组的方法。

Constructor类:
提供一个类的构造函数的信息以及访问类的构造函数的接口。

Field类:
提供一个类的域的信息以及访问类的域的接口。

Method类:
提供一个类的方法的信息以及访问类的方法的接口。

Modifier类:
提供了static 方法和常量,对类和成员访问修饰符进行解码。


Proxy类:
提供动态地生成代理类和类实例的静态方法。


Java反射框架主要提供以下功能:
1.在运行时判断任意一个对象所属的类 
2.在运行时构造任意一个类的对象
3.在运行时判段任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法) 
4.在运行时调用任一个对象的方法

5.生成动态代理


反射的基本使用:

在使用 Java 的反射功能时,基本首先都要获取类的 Class 对象,再通过 Class 对象进行各种操作。

1.获得Class对象 (Class对象表示正在运行的 Java 应用程序中的类和接口)

 有三种方法:

//第一种方式:  
Class c1 = Class.forName("Employee");
  
//第二种方式:  
//java中每个类型都有class 属性.  
Class c2 = Employee.class;
Class c3 = int.class;
Class c4 = Integer.class;  
   
//第三种方式:  
//java语言中任何一个java对象都有getClass 方法  
Employee e = new Employee();  
Class c5 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)  

2、判断是否为某个类的实例

一般地,我们用instanceof关键字来判断是否为某个类的实例。
同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例:

public boolean isInstance(Object obj);


3、创建实例
通过反射来生成对象主要有两种方式。
(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。

Class<?> c = String.class;
Object str = c.newInstance();
注意:Class的newInstance方法,只能创建只包含无参数的构造函数的类,
如果某类只有带参数的构造函数,那么就要使用第二种的方式:

fromClass.getDeclaredConstructor(String.class).newInstance("tengj");

完整代码:

public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");
            //获取构造函数
            Constructor constructor = c.getDeclaredConstructor(String.class);
            constructor.setAccessible(true);//设置是否允许访问,因为该构造器是private的,所以要手动设置允许访问,如果构造器是public的就不需要这行了。
            constructor.newInstance("tengj");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

获取构造函数的API如下:

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //  获得该类所有的构造器,不包括其父类的构造器
public Constructor<T> getConstructor(Class<?>... parameterTypes) // 获得该类所以public构造器,包括父类

//具体
Constructor<?>[] allConstructors = class1.getDeclaredConstructors();//获取class对象的所有声明构造函数 
Constructor<?>[] publicConstructors = class1.getConstructors();//获取class对象public构造函数 
Constructor<?> constructor = class1.getDeclaredConstructor(String.class);//获取指定声明构造函数 
Constructor publicConstructor = class1.getConstructor(String.class);//获取指定声明的public构造函数

4、获取方法

获取某个Class对象的方法集合,主要有以下几个方法:
getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
  public Method[] getDeclaredMethods() throws SecurityException


getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
  public Method[] getMethods() throws SecurityException

getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
  public Method getMethod(String name, Class<?>... parameterTypes)

写例子来理解下:

public class MainDemo {

    public int add(int a,int b) {
        return a+b;
    }
    public int sub(int a,int b) {
        return a+b;
    }

    public static void main(String[] args)
    {
        try {
            Class<?> c = MainDemo.class;
            Object object = c.newInstance();

            Method[] methods = c.getMethods();
            Method[] declaredMethods = c.getDeclaredMethods();
            //获取methodClass类的add方法
            Method method = c.getMethod("add", int.class, int.class);
            //getMethods()方法获取的所有方法
            System.out.println("----------- getMethods获取的方法 ----------------");
            for(Method m:methods) {
                System.out.println(m);
            }

            System.out.println("\n");

            //getDeclaredMethods()方法获取的所有方法
            System.out.println("*********** getDeclaredMethods获取的方法 **************");
            for(Method m:declaredMethods) {
                System.out.println(m);
            }

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }
    
}


5、获取类的成员变量(字段)信息

单独获取某个成员变量,通过Class类的以下方法实现:
//参数是成员变量的名字
public Field getDeclaredField(String name) // 获得该类自身声明的所有变量,不包括其父类的变量
public Field getField(String name) // 获得该类自所有的public成员变量,包括其父类变量

//具体实现
Field[] allFields = class1.getDeclaredFields();//获取class对象的所有属性 
Field[] publicFields = class1.getFields();//获取class对象的public属性 
Field ageField = class1.getDeclaredField("age");//获取class指定属性 
Field desField = class1.getField("des");//获取class指定的public属性

例子:
//获取单个变量
public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");
            //获取成员变量
            Field field = c.getDeclaredField("msg"); //因为msg变量是private的,所以不能用getField方法
            Object o = c.newInstance();
            field.setAccessible(true);//设置是否允许访问,因为该变量是private的,所以要手动设置允许访问,如果msg是public的就不需要这行了。
            Object msg = field.get(o);
            System.out.println(msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//获取所有成员变量的数组 
public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");
            Field[] fields = c.getDeclaredFields();
            for(Field field :fields){
                System.out.println(field.getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6、调用方法

当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为:

public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,InvocationTargetException
例子:

public class test1 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> klass = methodClass.class;
        //创建methodClass的实例
        Object obj = klass.newInstance();
        //获取methodClass类的add方法
        Method method = klass.getMethod("add",int.class,int.class);
        //调用method对应的方法 => add(1,4)
        Object result = method.invoke(obj,1,4);
        System.out.println(result);
    }
}
class methodClass {
    public final int fuck = 3;
    public int add(int a,int b) {
        return a+b;
    }
    public int sub(int a,int b) {
        return a+b;
    }
}

7、利用反射创建数组








  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值