Java-reflax 反射

  1. 概念
  2. 逐步分析
    1. 1.Class
    2. 2.反射获取类对象的三种方式(通过一个Junit测试来说明)
      1. 2.1 直接通过类名.Class的方式得到
      2. 2.2 通过对象的getClass()方法获取,这个使用的少
      3. 2.3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常
      4. 注意:
    3. 3.利用newInstance创建对象:调用的类必须有无参的构造器
    4. 4.ClassLoader类加载器
      1. 4.1.获取一个系统的类加载器
      2. 4.2.获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader))
      3. 4.3、获取扩展类加载器的父类加载器,输出为Null,无法被Java程序直接引用
      4. 4.4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器
      5. 4.5、测试JDK提供的Object类由哪个类加载器负责加载的,输出为Null,无法被Java程序直接引用
    5. 5.反射机制通过加载器获取流对象:getResourceAsStream方法
  3. 6.反射机制获取类中的方法:Method: 对应类中的方法
    1. (1)反射机制获取类中的方法:获取本类方法
      1. 6.1 获取方法:默认只能获取public修饰的方法
      2. 6.2 获取方法:所有修饰权限的方法都可以获得
      3. 6.3获取方法:获取指定的方法(所有修饰权限)
      4. 6.4执行方法:
    2. (2)反射机制获取接口或者父类的方法:
      1. A : Method: 对应基类或接口中的方法
      2. B : 通过当前反射对象,拿到父类反射对象
    3. 7.反射机制获取类中的字段属性:Field字段

参考网址

概念

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

逐步分析

1.Class

(1).Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性

(2).对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。

(3).对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。 一个 Class 对象包含了特定某个类的有关信息。

(4).Class 对象只能由系统建立对象

(5).一个类在 JVM 中只会有一个Class实例

2.反射获取类对象的三种方式(通过一个Junit测试来说明)

2.1 直接通过类名.Class的方式得到

@Test
public void getClassByClass(){
    Class c = Demo.class;
    System.out.println("通过类名获取 : "+c);
}

2.2 通过对象的getClass()方法获取,这个使用的少

(一般是传的是Object,不知道是什么类型的时候才用)

@Test
public void getClassByObject(){
    Demo demo = new Demo();//此处会调用无参构造方法
    Class<? extends Demo> class1 = demo.getClass();
    System.out.println("通过对象获取 : "+class1);
}

2.3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常

@Test
public void getClassByAllClass() throws ClassNotFoundException{
    Class<?> forName = Class.forName("reflax.Demo");
    System.out.println("通过全类型获取 : "+forName);
}

注意:

1 直接通过类名.Class的方式得到

Class c = Demo.class;

3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常

Class<?> forName = Class.forName("reflax.Demo");

3.利用newInstance创建对象:调用的类必须有无参的构造器

public void testNewInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
        Class<?> forName = Class.forName("reflax.Demo");
        Object newInstance = forName.newInstance();
        System.out.println(newInstance);
    }

若删除了Demo的无参构造,会出错。

4.ClassLoader类加载器

4.1.获取一个系统的类加载器

ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("系统类加载器"+systemClassLoader);

4.2.获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader))

ClassLoader parent = ClassLoader.getSystemClassLoader().getParent();
System.out.println("扩展类加载器"+parent);

4.3、获取扩展类加载器的父类加载器,输出为Null,无法被Java程序直接引用

ClassLoader parent2 = ClassLoader.getSystemClassLoader().getParent().getParent();
System.out.println("启动类加载器"+parent2);

4.4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器

ClassLoader classLoader = Class.forName("reflax.Demo").getClassLoader();
System.out.println("当前类由哪个类加载器进行加载-->"+classLoader);  

4.5、测试JDK提供的Object类由哪个类加载器负责加载的,输出为Null,无法被Java程序直接引用

ClassLoader classLoader2 = Class.forName("java.lang.Object").getClassLoader();
System.out.println("JDK提供的Object类由哪个类加载器加载-->" + classLoader2);  

5.反射机制通过加载器获取流对象:getResourceAsStream方法

//特别说明: getResourceAsStream(“path”),path的路径和new Demo()的位置有关

//Demo  路径   reflax/Demo.java
//test.properties  路径  reflax/test.properties

    InputStream resourceAsStream = new Demo().getClass().getClassLoader().getResourceAsStream("reflax/test.properties");
    System.out.println(resourceAsStream);
    Properties properties = new Properties();
    properties.load(resourceAsStream);
        System.out.println("文件内容"+resourceAsStream);
        System.out.println(properties.get("name"));        
        System.out.println(properties.get("age"));

6.反射机制获取类中的方法:Method: 对应类中的方法

(1)反射机制获取类中的方法:获取本类方法

6.1 获取方法:默认只能获取public修饰的方法

Class classzz = Class.forName("reflax.MethodDemo");
Method[] methods = classzz.getMethods();

6.2 获取方法:所有修饰权限的方法都可以获得

Class classzz = Class.forName("reflax.MethodDemo");
Method[] declaredMethods = classzz.getDeclaredMethods();

6.3获取方法:获取指定的方法(所有修饰权限)

Class classzz = Class.forName("reflax.MethodDemo");

6.3.1 获取指定方法名的 无参方法

Method declaredMethod = classzz.getDeclaredMethod("method_public");

6.3.2 获取指定方法名的 有参方法

Method declaredMethod2 = classzz.getDeclaredMethod("method_public_2", String.class,int.class,char.class);

6.4执行方法:

执行方法:invoke(方法对象,方法实际参数) 
    Object newInstance = classzz.newInstance();

6.4.1 执行 无参方法

declaredMethod.invoke(newInstance);

6.4.2 执行 有参方法

declaredMethod2.invoke(newInstance, "TEST",122,'r');

代码示例:

package reflax;

public class MethodDemo {

/**
Java权限有四个,分别为public,protected,默认,private,其开放程度依次降低
 *    public可供所有类访问
 *    protected继承可见
 *    private只能类本身内部的方法可以访问
 */    

public void method_public(){
    System.out.println("method_public");
}
public void method_public_2(String name,int age,char sex){//public  带参数
    System.out.println("method_public_2");
    String info="Demo{" +  
    "name='" + name + '\'' +  
    ", age=" + age  +  
    ", sex='" + sex + '\'' +  
    '}';
    System.out.println(info);
}
protected void method_protected(){
    System.out.println("method_protected");
}
protected void method_protected_2(String info){//protected  带参数
    System.out.println("method_protected_2:"+info);
}
void method_default(){
    System.out.println("method_default");
}
void method_default_2(String info){//默认修饰符   带参数
 System.out.println("method_default_2:"+info);
}
private void method_private(){
    System.out.println("method_private");
}
private void method_private_2(String info){//private  带参数
    System.out.println("method_private_2:"+info);
}

}

测试:

@Test
public void testMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
    Class classzz = Class.forName("reflax.MethodDemo");

//1、得到clazz 对应的类中有哪些方法,不能获取private方法 
    Method[] methods = classzz.getMethods();
    for(Method method:methods){
//            System.out.println(method.getName());
    }

//2、获取所有的方法(且只获取当前类声明的方法,包括private方法)
    Method[] declaredMethods = classzz.getDeclaredMethods();
    for(Method method :declaredMethods){
        System.out.println(method);
    }

//3、获取指定的方法  
 Class<?>... parameterTypes:一个或多个方法参数的类型,注意要一一对应。

//3.1 获取指定方法名的  无参方法
    Method declaredMethod = classzz.getDeclaredMethod("method_public");
    System.out.println(declaredMethod);

//3.2 获取指定方法名的  有参方法
    Method declaredMethod2 = classzz.getDeclaredMethod("method_public_2", String.class,int.class,char.class);
    System.out.println(declaredMethod2);

//4、执行方法!  执行方法:invoke(方法对象,方法实际参数) 
    Object newInstance = classzz.newInstance();
    declaredMethod.invoke(newInstance);
    declaredMethod2.invoke(newInstance, "TEST",122,'r');
}

(2)反射机制获取接口或者父类的方法:

A : Method: 对应基类或接口中的方法

(只可以获取到接口或父类的public方法)
//    反射机制获取类中的方法:Method: 对应基类或接口中的方法

    Class forName = Class.forName("reflax.Demo");
    Method[] methods = forName.getMethods();
    for(Method method:methods){
        System.out.println(method);    
    }
    //获取当前类实现的接口中的方法  
    Method method = forName.getMethod("play_public_2", String.class);

    //执行
    Demo newInstance = Demo.class.newInstance();
    method.invoke(newInstance, "ddddd");

B : 通过当前反射对象,拿到父类反射对象

(可以获取到接口或父类的所有方法)
通过子类的反射对象和拿到的父类反射对象,也仅仅只能执行public方法,不能执行private,protected和default默认修饰的方法

    Class classzz = Class.forName("reflax.Demo");

    //获取父类的class
    Class superclasszz = classzz.getSuperclass();

    //获取父类方法的public权限方法
    Method[] methods = superclasszz.getMethods();
    for(Method method : methods){
        System.out.println(method);
    }

    //仅仅获取父类声明的全部方法
    Method[] declaredMethods = superclasszz.getDeclaredMethods();
    for(Method method : declaredMethods){
        System.out.println(method);
    }

7.反射机制获取类中的字段属性:Field字段

Class classzz = Class.forName("reflax.Demo");

//获取被public修饰的属性
Field[] fields = classzz.getFields();
for(Field field : fields){
    System.out.println(field.getName());
}

// 获取Field的数组,私有字段也能获取
Field[] declaredFields = classzz.getDeclaredFields();
for(Field field : declaredFields){
    System.out.println(field.getName()+"类型"+field.getType());
}

//获取指定对象的Field的值
Field declaredField = classzz.getDeclaredField("sex");
Demo demo = (Demo) classzz.newInstance();
char object = (char) declaredField.get(demo);
System.out.println(object);

//设置指定对象的Field的值
declaredField.set(demo, 'T');
System.out.println(demo.getSex());

//若该字段是私有的,需要调用setAccessible(true)方法
Field privateField2 = classzz.getDeclaredField("age");
privateField2.setAccessible(true);
privateField2.set(demo, 14);
System.out.println(demo.getAge());

文章标题:Java-reflax 反射

发布时间:2019-11-29, 14:30:08

最后更新:2019-11-29, 14:30:08