Java反射学习记录

Java反射产生的背景:Java一开始是静态语言,静态语言就是程序在运行时,可以根据某些条件改变自身结构。Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

加载完类之后,在堆内存的方法区中就产生了一个Class类型(这个也叫运行时类)的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。

Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!

1.使用反射访问对象的属性,方法,创建对象。

Class clazz = Person.class;//这个就叫运行时类,每个类只有一个运行时类
//1.通过反射,创建Person类的对象
Constructor cons = clazz.getConstructor(String.class,int.class);
Object obj = cons.newInstance("Tom", 12);
Person p = (Person) obj;
//上面两步可以合并为一步,如下
//Person person = (Person)clazz.getConstructor(String.class, int.class).newInstance("Tom", 12);
//上面是通过带参构造器使用反射创建的对象,对于无参构造器,如下:
Person person = (Person)clazz.getConstructor().newInstance();//该方法要求实体类中必须存在无参构造器
System.out.println(p.toString());
//2.通过反射,调用对象指定的属性、方法
//调用属性
Field age = clazz.getDeclaredField("age");
age.set(p,10);
System.out.println(p.toString());
//调用方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(p);
System.out.println("*******************************");
//通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
//调用私有的构造器
Constructor cons1 = clazz.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person p1 = (Person) cons1.newInstance("Jerry");
System.out.println(p1);
//调用私有的属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(p1,"HanMeimei");
System.out.println(p1);
//调用私有的方法
Method showNation = clazz.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String nation = (String) showNation.invoke(p1,"中国");//相当于String nation = p1.showNation("中国")
System.out.println(nation);
//调用私有属性,方法等需要设置访问权限为true
//调用方法:首先用反射得到一个Method对象,用该方法调用invoke(),如果有参数就把参数放入invoke()中,但是invoke()方法第一个参数必须是对象

2.理解Class类

Object类中有一个方法public final Class getClass();该方法返回一个Class类的对象,Class类是Java反射的源头。通过对象反射求出类的名称。

对于每个类而言,JRE 都为其保留一个不变的Class 类型的对象。一个Class 对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。

Class本身也是一个类,Class对象只能由系统建立对象,一个加载的类在JVM 中只会有一个Class实例,每个类的实例都会记得自己是由哪个Class 实例所生成,通过Class可以完整地得到一个类中的所有被加载的结构,

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

Class类的常用方法:

static Class forName(String name):返回指定类名name的Class对象

Object newInstance():调用无参构造器,返回该Class对象的一个实例

getName():返回此Class对象所表示的实体(类,接口,数组类,基本类型或void)名称

Class getSuperClass():返回当前Class对象的父类的Class对象

Class[] getInterfaces():获取当前Class对象的接口

ClassLoader getClassLoader():返回该类的类加载器

Class getSuperclass():返回表示此Class所表示的实体的超类的Class。

Constructor[] getConstructors():返回一个包含某些Constructor对象的数组

Constructor getConstrucetor(Class..clazz):返回指定参数类型的构造器

Field[] getDeclaredFields():返回Field对象的一个数组

Field getDeclaredField(String name):返回指定name的属性

Method getMethods(String name, Class... paramType):返回一个Method对象,此对象的形参类型为paramType

3.获取Class类的实例

1).Class clazz = String.class;

2).Class clazz = "www.atguigu.com".getClass();

3).Class clazz = Class.forName("www.atguigu.com");

4).Class clazz = this.getClass().getClassLoader().loadClass("类的全类名");

4.类的加载过程

程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。

接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例

换句话说,Class的实例就对应着一个运行时类

加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。

通过反射创建对应的运行时类的对象

newInstance():调用此方法,创建对应的运行时类的对象,内部调用了运行时类的空参的构造器。

要想此方法正常的创建运行时类的对象,要求:

(1)运行时类必须提供空参的构造器

(2)空参的构造器的访问权限得够,通常设置为public

在javabean中要求提供一个public的空参构造器。原因:

(1)便于通过反色和,创建运行时类的对象

(2)便于子类继承此运行时类时,默认调用super()时,保证弗雷有此构造器

ClassLoader

猜你喜欢

转载自www.cnblogs.com/ifreewolf/p/12783857.html