(一) 什么是反射?
反 射 就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够获取这个类的所有属性和方法;对于任意一个对象,都能调用其任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫 Java的反射机制 。
说明: 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。可以通过这个对象查看到所对应类的所有信息。
(二) 反射能做什么?
(1)在运行时判断任意一个对象所属的类
(2)在运行时构造任意一个类的对象
(3)在运行时判断任意一个类所具有的成员变量和方法
(4)在运行时获取泛型信息
(5)在运行时调用任意一个对象的成员变量和方法
(6)在运行时处理注解
(7)生成动态代理
(三) Class类
通过对象可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接 口。对于每个类而言,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 )
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); }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/94713.html