目录
(1)ClassNotFoundException:没有找到类异常;在类名与类路径书写错误的时候,会报这个异常。
(2)IllegalAccessException:非法访问异常;比如在程序外侧访问程序内部私有方法,或者访问作用域外方法的时候,就会抛出这个异常;
(3)InstantiationException:实例化异常;对象无法被实例化的时候会抛出这个异常;
反射的核心类:有四个。本篇博客主要介绍Class类。
这四个类正好构建出一个类的完整结构。一个类中有构造方法,方法,成员变量。反射就是基于这四个类,来完成在运行时动态创建对象、执行方法、访问成员变量这些操作的。
Class类:
说明:
(1)java中的类包括【构造函数,方法,各种成员变量】等,通过这些组织起了一个标准的类;这些类在JVM中就通过Class来指代。即Class和以前理解的类(标准意义上的类)一样,只是这个Class类是对在JVM中的“类和接口”这种特殊的对象的抽象。换句话说,比如Employee类一般是用来描述员工信息的类,Class类是专门用来描述“类和接口”的类;
(2)Class类的实例对象(就是Class对象啦):是包含了某个具体的特定类的结构信息。。。以Employee员工类为例,在JVM中Class类会实例化一个Class对象,这个Class对象就对应了Employee类,这个Class对象本质就是描述这个Employee类有哪些成员变量,有哪些具体的方法,有哪几种构造函数。。。。即Class对象包含的就是对应特定类的结构信息;
(3)通过Class对象(如指向Employee类的Class对象)可以获取Employee类的构造方法,方法,成员变量等结构信息。Class对象就是描述其他类的一个对象。
……………………………………………………
Class类核心方法:
说明:
(1)Class.forName():参数是具体类的完整路径字符串,就可以获取指定类的Class对象;然后通过指定类的Class对象,就可以获取这个指定类的信息了;
返回值是一个Class对象,这儿用classObj指代了。
forName()方法是Class类的静态方法了,可以直接Class类去调用;
( JDBC中就用到了,用于加载JDBC的驱动程序)
(2)newInstance():通过默认的构造方法创建新的对象;其本质和使用new关键字创建对象十分相似;返回值类型是Object(因为这是一个抽象化的方法。不是针对具体的某一个类型。所以返回的是所有类的最终父类Object类的对象,而不是具体的某一个类的对象。)
(3)getConstructor():返回的Constructor对象就是构造方法的指代;(自然一个类可能有很多构造方法,那么这个类的Class对象的getConstructor()方法返回的Constructor对象中也会包含这个类的所有public构造方法。)
(4)getMethod():原理同上;
(5)getField():原理同上;
……………………………………………………
案例:
(1)案例内容
创建一个工程,创建两个类
Employee类:
package com.imooc.reflect.entity;
public class Employee {
static {
System.out.println("Employee的初始化静态代码块,只有Employee类被" +
"加载的时候,这个代码块才会执行性。");
}
private Integer eno;
private String ename;
private Float salary;
private String dname;
public Employee() {
System.out.println("Employee的默认构造方法。");
}
public Integer getEno() {
return eno;
}
public void setEno(Integer eno) {
this.eno = eno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Float getSalary() {
return salary;
}
public void setSalary(Float salary) {
this.salary = salary;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
}
ClasssSample类:
package com.imooc.reflect;
import com.imooc.reflect.entity.Employee;
/**
* Class类示例。利用反射机制,通过Class类加载EMployee类,同时实例化Employee类的对象
*/
public class ClasssSample {
public static void main(String[] args) {
try {
// 类的路径字符串要正确;需要捕捉ClassNotFoundException
// Class.forName():将指定的类加载到JVM中,并返回指定类的Class对象
// Class.forName():就是将指定的字节码文件class加入到JVM内存中;只
// 有Employee的类的字节码文件被加入到JVM中后,才能基于这个类进行实例化的工作。
Class employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
System.out.println("Employee已经被加载JVM中。");
Employee employee = (Employee) employeeClass.newInstance();
System.out.println(employee);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
(2)正常运行ClasssSample类:结果
(3)分析:三个异常
(1)ClassNotFoundException:没有找到类异常;在类名与类路径书写错误的时候,会报这个异常。
一旦报了这个异常,就要去确认Class.forName()参数的字符串是否正确;
(2)IllegalAccessException:非法访问异常;比如在程序外侧访问程序内部私有方法,或者访问作用域外方法的时候,就会抛出这个异常;
完整的异常信息:
java.lang.IllegalAccessException: Class com.imooc.reflect.ClasssSample can not access a member of class com.imooc.reflect.entity.Employee with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.Class.newInstance(Class.java:436)
at com.imooc.reflect.ClasssSample.main(ClasssSample.java:18)
(3)InstantiationException:实例化异常;对象无法被实例化的时候会抛出这个异常;
一旦报了InstantiationException异常的时候,就要看下Class.forName()中的那个类是否允许被实例化;
注解:上面classObj.newInstance()是调用默认的构造方法;例如,当类有多个构造方法的时候,如何按照带参构造实例化对象?这是个问题,下篇博客会介绍。