1.Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API获得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 Class c = Class.forName("java.lang.String");
2.加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称为:反射。
正常方式: 引入需要的 "包类"名称---->通过new实例化----->获取实例化对象。
反射方式:实例化对象---->getClass方法----->得到完整的"包类"名称。
1.在运行时判断任意一个对象所属的类。
2.在运行时构造任意一个类的对象。
3.在运行时判断任意一个类所具有的成员变量和方法。
4.在运行时获取泛型信息。
5.在运行时调用任意一个对象的成员变量和方法。
6.在运行时处理注解。
7.生产动态代理。
某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。
一个类在内存中只存在一个Class对象,一个类被加载后,类的整个结构都会被封装到Class对象中。
1.Class本身也是一个类。
2.Class对象只能由系统建立对象。
3.一个加载的类在JVM中只会有一个Class实例。
4.一个Class对象对应的是一个加载到JVM中的一个.class文件。
5.每个类的实例都会记得自己是由哪个Class实例所生产。
6.通过Class可以完整地得到一个类中的所有被加载的结构。
7.Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应Class对象。
1、常用方法:
1.static Class> forName(String className):返回指定类名name的Class对象。
2.String getName():返回此Class对象所表示的实体(类、接口、数组类或void)的名称。
3. T newInstance():调用缺省构造函数,返回Class对象的一个实例。
4. Class super T> getSuperclass():返回当前Class对象的父类的Class对象。
5.Class>[] getInterfaces():获取当前Class对象的接口。
6.ClassLoader getClassLoader():返回该类的类加载器。
7.Constructor>[] getConstructors():返回一个包含某些Constructor对象的数组。
8.Method getMethod(String name, Class>... parameterTypes):返回一个Method对象。
9.Field[] getDeclaredFields():返回Filed对象的一个数组。
2、获取Class类的实例:
1.已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。
Class clazz = Person.class;。
2.已知某个类的实例,调用该类实例的getClass()方法获取Class对象。
Class clazz = person.getClass();。
3.已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取。
Class clazz = Class.forName("com.Person");。
4.内置基本数据类型可以直接用类名.Type(Integer.TYPE)。
5.利用ClassLoader获取。
代码示例:
public class ClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是:"+person.getName());
//方法一: 通过对象获取
Class extends Person> c1 = person.getClass();
System.out.println(c1.hashCode());//返回结果:933699219
//方式二: 通过forName获得
Class> c2 = Class.forName("com.ywl.controller.Student");
System.out.println(c2.hashCode());//返回结果:933699219
//方式三: 通过类名.class获取
Class c3 = Student.class;
System.out.println(c3.hashCode());//返回结果:933699219
//方式四: 基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);//返回结果:int
//获取父类类型
Class> superclass = c1.getSuperclass();
System.out.println(superclass);//返回结果:class com.ywl.controller.Person
}
}
class Person{
private String name;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student() {
this.setName("学生");
}
}
class Teacher extends Person{
public Teacher() {
this.setName("老师");
}
}
3、动态创建对象执行方法:
代码示例:
public class ClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
Class userClass = User.class;
//获取类名
System.out.println("包名+类名:"+userClass.getName());
System.out.println("类名:"+userClass.getSimpleName());
//获取类的所有属性(userClass.getFields()获取public属性)
Field[] fields = userClass.getDeclaredFields();
for (Field field : fields) {
System.out.println("getDeclaredFields:"+field);
}
//获取类的所有方法(userClass.getMethods()获取public方法)
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("getDeclaredMethods:"+declaredMethod);
}
//获取类所有的构造器
Constructor>[] declaredConstructors = userClass.getDeclaredConstructors();
for (Constructor> declaredConstructor : declaredConstructors) {
System.out.println("getDeclaredConstructors:"+declaredConstructor);
}
}
}
class User{
private String name;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
打印结果:
包名+类名:com.ywl.controller.User
类名:User
getDeclaredFields:private java.lang.String com.ywl.controller.User.name
getDeclaredMethods:public java.lang.String com.ywl.controller.User.getName()
getDeclaredMethods:public void com.ywl.controller.User.setName(java.lang.String)
getDeclaredConstructors : public com.ywl.controller.User()
4、创建类的对象:调用Class对象的newInstance()方法。
1.类必须有一个无参数的构造器。
2.类的构造器的访问权限需要足够。
3.调用指定的方法:Object invoke(Object obj,Object..... args)
(1).Object对应原方法的返回值,若原方法无返回值,此时返回null。
(2).若原方法为静态方法,此时形参Object obj可为null。
(3).若原方法形参列表为空,则Object[] args为null。
(4).若原方法声明为private,则需要在此调用此invoke()方法前,显示调用方法对象的setAccessible(true)方法,才可访问 private的方法。
4.setAccessible方法:
(1).Method和Field、Constructor对象都有setAccessible()方法。
(2).setAccessible作用是启动和禁用访问安全检查的开关。
(3).参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。使得原本无法访问的私有成员也可以访问。
(4).参数值为false则指示反射的对象应该实施Java语言访问检查。
代码示例:
public class ClassDemo {
public static void main(String[] args) throws Exception {
Class> userClass = Class.forName("com.ywl.controller.User");
//通过反射调用普通方法
User user = (User)userClass.newInstance();
//通过反射获取一个方法。
Method setName = userClass.getDeclaredMethod("setName", String.class);
setName.invoke(user,"张三");
System.out.println(user.getName());
//通过反射操作属性
Field name = userClass.getDeclaredField("name");
name.setAccessible(true);//关闭程序的安全检测才可以操作private属性
name.set(user,"李四");
System.out.println(user.getName());
}
}
class User{
private String name;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
打印结果:
张三
李四
1.加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象。
2.链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
(1).验证:确保加载的类信息符合JVM规范,没有安全方面的问题。
(2).准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
(3).解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
3.初始化:
1.执行类构造器
2.当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
3.虚拟机会保证一个类的
类加载器的作用是把类(class)装载进内存的。JVM规范定义了如下类型的类加载器:
1.引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来装载核心类库,该加载器无法直接获取。
2.扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库。
3.系统类加载器:负责java -classpath或-D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器。
代码示例:
public class ClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("获取系统类的加载器:"+systemClassLoader);
//获取系统类加载器的父类加载器-->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println("获取系统类加载器的父类加载器:"+parent);
//获取扩展类加载器的父类加载器-->根加载器(C/C++)
ClassLoader parent1 = parent.getParent();
System.out.println("获取扩展类加载器的父类加载器:"+parent1);
//获取当前类的类加载器
ClassLoader classLoader = Class.forName("com.ywl.controller.ClassDemo").getClassLoader();
System.out.println("获取当前类的类加载器:"+classLoader);
//获取JDK内部类加载器
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println("获取JDK内部类加载器:"+classLoader);
}
}
打印结果:
获取系统类的加载器:sun.misc.Launcher$AppClassLoader@2dda6444
获取系统类加载器的父类加载器:sun.misc.Launcher$ExtClassLoader@37a71e93
获取扩展类加载器的父类加载器:null
获取当前类的类加载器:sun.misc.Launcher$AppClassLoader@2dda6444
获取JDK内部类加载器:null