天天看点

Java高级学习篇之反射

Java高级学习篇之反射

(一) 什么是反射?

          反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够获取这个类的所有属性和方法;对于任意一个对象,都能调用其任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。

说明:加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个

类只有一个Class对象),这个对象就包含了完整的类的结构信息。可以通过这个对象查看到所对应类的所有信息。

Java高级学习篇之反射

(二) 反射能做什么?

(1)在运行时判断任意一个对象所属的类

(2)在运行时构造任意一个类的对象

(3)在运行时判断任意一个类所具有的成员变量和方法

(4)在运行时获取泛型信息

(5)在运行时调用任意一个对象的成员变量和方法

(6)在运行时处理注解

(7)生成动态代理

(三) Class类

Java高级学习篇之反射

通过对象可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接

口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含

了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。

(1) Class本身也是一个类

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

(3) 一个加载的类在 JVM 中只会有一个Class实例

(4)一个Class对象对应的是一个加载到JVM中的一个.class文件

(5) 每个类的实例都会记得自己是由哪个 Class 实例所生成

(6)通过Class可以完整地得到一个类中的所有被加载的结构

(7)Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得         相应的

Class对象

(四) 实际应用​

I.获取Class类的实例

方式一:调用运行时类的属性

方式二:通过运行时类的对象,调用getClass()

方式三:调用Class的静态方法:formatName(String classPath)

方式四:使用类的加载器:ClassLoader

@Test
    public void test3() throws ClassNotFoundException {//获取运行时类的方式(前三种为重点)
        //方式一:调用运行时类的属性
        Class clazz = Person.class;
        System.out.println(clazz);
        //方式二: 通过运行时类的对象,调用getClass()
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        System.out.println(clazz2);
        //方式三:调用Class的静态方法:formatName(String classPath)
        Class clazz3 = Class.forName("practice.Person");
        System.out.println(clazz3);
        //判断是否相等
        System.out.println(clazz == clazz2);
        System.out.println(clazz2 == clazz3);
        //说明:更好地体现了动态性,在编译时无法判断出错误一旦运行,如果错误就直接报错

        //方式四;使用类的加载器:ClassLoader
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("practice.Person");
        System.out.println(clazz4);
        System.out.println(clazz3 == clazz4);
    }
      

补充:

(1)哪些对象可以有Class实例?

① class: 外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

② interface:接口

③ []:数组

④ enum:枚举

⑤ annotation:注解@interface

⑥ primitive type:基本数据类型

⑦ void

(2)类的加载器(ClassLoader)

Java高级学习篇之反射

II.读取配置文件(properties)

基本介绍:

    Java中的​​properties​​文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式.
@Test
    public void test1() throws Exception {
        Properties pros=new Properties();
        //此时的文件默认路径为当前的module下
        //也可以使用完整路径来寻找特定位置的properties文件
//        FileInputStream fis=new FileInputStream("src\\practice\\jdbc1.properties");
        FileInputStream fis=new FileInputStream("jdbc.properties");
        pros.load(fis);
        String user=pros.getProperty("user");
        String password=pros.getProperty("password");
        System.out.println("user = "+ user +"\npassword ="+ password);
    }
    /**
     * 读取配置文件(方式二)
     * */
    @Test
    public void test3() throws Exception {
        Properties pros3=new Properties();
        ClassLoader classLoader=ClassLoaderTest.class.getClassLoader();
        //使用绝对路径
        InputStream is=classLoader.getResourceAsStream("src\\practice\\jdbc1.properties");
        pros3.load(is);
        String name = pros3.getProperty("user");
        String password=pros3.getProperty("password");
        System.out.println("user= "+name+ ",password ="+password);

    }      

III.创建运行时类的对象

  • newInstance():调用此方法,创建运行时类的对象,内部调用了运行时类的空参构造器​
  • 此方法使用前提:
  • (1)运行时类必须提供空参构造器
  • (2)空参构造器的访问权限必须要够,通常为public
  • 在javabean中要求提供一个public的空参构造器
  • 原因如下:
  • (1) 便于通过反射,创建运行时类的对象
  • (2) 便于子类继承此运行时类的对象,默认调用super()时,保证父类由此构造器
public class NewInstanceTest {
    @Test
    public void test2() throws InstantiationException, IllegalAccessException {
        //(1)获取运行时类
        Class<Person> clazz=Person.class;
        //(2)方法1--->newInstance() :调用此方法,创建对应的运行时类的对象(调用了运行时类的空参构造器)
        Object obj=clazz.newInstance();
        System.out.println(obj);
    }
}      

IV.获取运行时类的完整结构

①. 实现的全部接口  

    public Class<?>[] getInterfaces()

    说明:确定此对象所表示的类或接口实现的接口。

具体代码:

@Test
    public void test3(){
        Class clazz= Person1.class;
        Class[] interfaces=clazz.getInterfaces();
        for(Class f:interfaces){
            System.out.println(f);
        }
        System.out.println();
        //获取运行时类父类的接口
        Class[]interfaces1=clazz.getSuperclass().getInterfaces();
        for(Class m:interfaces1){
            System.out.println(m);
        }
    }      

②. 所继承的父类

  public Class<? Super T> getSuperclass()                                         

    说明:返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的

Class。

/**
     * 获取运行时类的父类
     * */
    @Test
    public void test7(){
        Class clazz=Person1.class;
        Class superclass=clazz.getSuperclass();
        System.out.println(superclass);
    }
    /**
     * 通过反射获取带泛型的父类
     * */
    @Test
    public void test8(){
        Class clazz=Person1.class;
        Type generiSuperclass=clazz.getGenericSuperclass();

        ParameterizedType parameterizedType=(ParameterizedType) generiSuperclass;
        //获取泛型类型
        Type[] actualArguments=parameterizedType.getActualTypeArguments();
        System.out.println(actualArguments[0].getTypeName());
    }      

③. 全部的构造器     

   public Constructor<T>[] getConstructors()                                    

    说明:返回此 Class 对象所表示的类的所有public构造方法。

 public Constructor<T>[] getDeclaredConstructors()                        

    说明:返回此 Class 对象表示的类声明的所有构造方法。

Constructor类中

  public int getModifiers(); ----->说明 :取得修饰符                            

  public String getName(); ------>说明:取得方法名称                       

 public Class<?>[] getParameterTypes();--->说明: 取得参数的类型

代码实现:

@Test
    public void test1() throws NoSuchMethodException {
        Class clazz=Person1.class;
        //getConstructors():获取当前运行时类中声明为public 的方法
        Constructor[]constructors=clazz.getConstructors();
        for (Constructor e:constructors) {
            System.out.println(e);
        }
        System.out.println();
        //getDeclaredConstructor():获取当前类中所有声明的构造器
        Constructor[]declareConstructors=clazz.getDeclaredConstructors();
        for (Constructor e:declareConstructors) {
            System.out.println(e);
        }

    }      

④. 全部的方法

  public Method[] getDeclaredMethods()                                         

  说明:返回此Class对象所表示的类或接口的全部方法

 public Method[] getMethods()                                                        

 说明:返回此Class对象所表示的类或接口的public的方法

 Method类中:

 public Class<?>getReturnType()                                                      

  说明:取得全部的返回值

 public Class<?>[]getParameterTypes()                                            

 说明:取得全部的参数

 public int getModifiers() ;  --->取得修饰符                                     

 public Class<?>[]getExceptionTypes()取得异常信息                          

具体代码:

/**
     * 权限修饰符 数据类型  变量名
     * */
    @Test
    public void test2(){
        Class clazz=Person1.class;
        Field[]declareFields=clazz.getDeclaredFields();
        for(Field f :declareFields){
            System.out.println();
            System.out.println(f);
           //权限修饰符
           int modifier=f.getModifiers();
           //输出对应属性的权限及权限修饰符的等级
            System.out.println(Modifier.toString(modifier));
            System.out.println(modifier);

            //数据类型
            Class type=f.getType();
            System.out.println(type+"\t");

            //变量名
            String name=f.getName();
            System.out.println(name);

        }

    }      

⑤.全部的Field

 public Field[] getFields() ;                                                                

说明:返回此Class对象所表示的类或接口的public的Field。

 public Field[] getDeclaredFields() ;                                                  

说明:返回此Class对象所表示的类或接口的全部Field。

Field方法

 public int getModifiers() ;                                                                  

说明:以整数形式返回此Field的修饰符。

 public Class<?> getType() ;                                                                                 

说明:得到Field的属性类型

 public String getName()                                                                       

说明:返回Field的名称

具体代码

@Test
    public void test1(){
        Class clazz=Person1.class;
        //获取属性结构
        //getFields():获取当前运行时类及父类中声明为public访问权限的属性
        Field[]field=clazz.getFields();
        for(Field f:field){
            System.out.println(f);
        }
        System.out.println();
        //getDeclareFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
        Field[]declareFields=clazz.getDeclaredFields();
        for(Field f: declareFields){
            System.out.println(f);
        }
    }
          

⑥. Annotation相关

 get Annotation(Class<T> annotationClass)                                       

 getDeclaredAnnotations()                                                                  

代码实现:

@Test
    public void test9(){
        Class clazz=Person1.class;
        Annotation[]annotations=clazz.getAnnotations();
        for(Annotation s:annotations){
            System.out.println(s);
        }
    }
      

⑦.泛型相关

Type getGenericSuperclass()                                                               

说明:获取父类泛型类型

ParameterizedType                                                                             

说明:泛型类型

getActualTypeArguments()                                                                

说明:获取实际的泛型类型参数数组

⑧.类所在的包

Package getPackage()                                                                        

代码实现

@Test
    public void test5(){
        Class clazz=Person1.class;
        Package pack=clazz.getPackage();
        System.out.println(pack);
    }