Java高级学习篇之反射

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java高级学习篇之反射相关的知识,希望对你有一定的参考价值。

Java高级学习篇之反射_反射

(一) 什么是反射?

Java高级学习篇之反射_反射_02

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

说明加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。可以通过这个对象查看到所对应类的所有信息。

Java高级学习篇之反射_Class类_03

(二) 反射能做什么?

Java高级学习篇之反射_Class类_04

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

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

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

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

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

(6)在运行时处理注解

(7)生成动态代理

(三) Class类

Java高级学习篇之反射_Class类_05

通过对象可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接 口。对于每个类而言,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高级学习篇之反射_Class类_06

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


以上是关于Java高级学习篇之反射的主要内容,如果未能解决你的问题,请参考以下文章

Java高级学习篇之IO流

Java高级学习篇之网络编程

Java 基础篇之反射

Java进阶篇之反射

Java进阶篇之反射

Java进阶篇之反射