正常的方式:引入“包类”名称 ——> new关键字实例化 ——> 获得实例化对象
反射的方式:实例化对象 ——> getClass()方法 ——> 得到完整的“包类”名称
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构
。
主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。
静态语言 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、 C++。 补充:动态语言 vs 静态语言 Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动 态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。 Java的动态性让编程的时候更加灵活!
- Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
- 反射相关的主要类
java.lang.Class:
代表一个类java.lang.reflect.Method
:代表类的方法java.lang.reflect.Field
:代表类的成员变量java.lang.reflect.Constructor
:代表类的构造器
Class类是用来描述类的类,如我们创建的或使用的Person类、Student类、Object类、String类等等都属于一类事物,而描述它们就使用到了Class类。
在Object类中定义了以下的方法,此方法 将被所有子类继承:
public final Class getClass()
:返回值的类型是一个Class类, 此类是Java反射的源头,实际上所谓反射 从程序的运行结果来看也很好理解,即: 可以通过对象反射求出类的名称。
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对象的数组Field[] getDeclaredFields()
: 返回Field对象的一个数组Method getMethod(String name,Class … paramTypes)
:返回一个Method对象,此对象的形参类型为paramType
public Constructor[] getConstructors()
:返回此 Class 对象所表示的类的所有public构造方法。public Constructor[] getDeclaredConstructors()
:返回此 Class 对象表示的类声明的所有构造方法。public int getModifiers()
;public String getName()
;public Class>[] getParameterTypes()
;示例:
package b_reflect.constructor;
public class Person {
//只写构造方法
public Person() {
System.out.println("Person的无参构造执行了,对象产生了~");
}
protected Person(int age) {
System.out.println("Person的带 " + age + " 参构造执行了,对象产生了~");
}
Person(String name) {
System.out.println("Person的带 " + name + " 参构造执行了,对象产生了~");
}
private Person(String name, int age) {
System.out.println("Person的带 " + name + " , " + age + " 参构造执行了,对象产生了~");
}
}
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 获取Person类的Class对象
Class<?> clazz = Class.forName("cn.pdsu.edu.reflect.Person");
// 获取Person类的实例
Person person = (Person) clazz.newInstance();
// 获取类中的所有的构造方法
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println("declaredConstructor = " + declaredConstructor);
}
System.out.println("=====================");
// 获取指定的构造方法
// 无参构造
Constructor d1 = clazz.getDeclaredConstructor();
System.out.println("d1 = " + d1);
System.out.println("====================");
// 有参构造,一个为int类型的参数
Constructor d2 = clazz.getDeclaredConstructor(int.class);
System.out.println("d2 = " + d2);
System.out.println("=========================");
// 有参构造,参数为String类型
Constructor d3 = clazz.getDeclaredConstructor(String.class);
System.out.println("d3 = " + d3);
System.out.println("========================");
// 有参构造,连个参数
Constructor d4 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println("d4 = " + d4);
System.out.println("========================");
// 调用对应的构造方法对象创建Person类实例
// 无参构造创建对象
Person p1 = (Person) d1.newInstance();
System.out.println("p1 = " + p1);
System.out.println("==================");
// 参数为int类型的构造创建对象
Person p2 = (Person) d2.newInstance(22);
System.out.println("p2 = " + p2);
System.out.println("====================");
// 参数为String类型的构造创建对象
Person p3 = (Person) d3.newInstance("张三");
System.out.println("p3 = " + p3);
System.out.println("===========================");
// 参数为String和int的构造方法创建对象
Person p4 = (Person) d4.newInstance("张三", 22); // 报错位置
System.out.println("p4 = " + p4);
System.out.println("=====================");
}
}
在Person类中存在一个私有的构造方法,所以,按照上面的代码写的去运行会报错:java.lang.IllegalAccessException
非法访问异常,我们需要在访问私有修饰的构造方法前加上一句代码:d4.setAccessible(true);
全部的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的名称。示例:
public class Teacher {
public String name;
protected int age;
String gender;
private double salary;
}
public class Demo1 {
public static void main(String[] args) throws Exception{
// 获取类的字节码文件对象
Class<?> clazz = Class.forName("cn.pdsu.edu.reflect.field.Teacher");
// 创建类对象
Teacher teacher = (Teacher) clazz.newInstance();
// 获取类中所有的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("declaredField = " + declaredField);
}
System.out.println("========================");
// 获取指定的属性,方法内参数为属性名
Field name = clazz.getDeclaredField("name");
// 为属性设置值,两个参数
// Object obj 是要为哪个对象的属性赋值
// Object value 是属性值
name.set(teacher , "张三");
// 获取属性值,参数为要获取哪个对象的name属性值
String name1 = (String) name.get(teacher);
System.out.println("name1 = " + name1);
System.out.println("========================");
// 获取属性age
Field age = clazz.getDeclaredField("age");
// 设置属性值
age.set(teacher , 22);
// 获取属性值age
int age1 = (int) age.get(teacher);
System.out.println("age1 = " + age1);
System.out.println("========================");
// 获取属性gender
Field gender = clazz.getDeclaredField("gender");
// 设置属性值
gender.set(teacher , "男");
// 获取属性值gender
String gender1 = (String) gender.get(teacher);
System.out.println("gender1 = " + gender1);
System.out.println("========================");
// 获取属性salary
Field salary = clazz.getDeclaredField("salary");
// 设置属性值,由于salary属性是私有的,所以需要先设置其为可访问的
salary.setAccessible(true);
salary.set(teacher , 12000);
// 获取属性值salary
double salary1 = (double) salary.get(teacher);
System.out.println("salary1 = " + salary1);
}
}
public Method[] getDeclaredMethods()
:返回此Class对象所表示的类或接口的全部方法public Method[] getMethods()
:返回此Class对象所表示的类或接口的public的方法public Class> getReturnType()
:取得全部的返回值public Class>[] getParameterTypes()
:取得全部的参数public int getModifiers()
:取得修饰符public Class>[] getExceptionTypes()
:取得异常信息示例:
public class Student {
public void study(){
System.out.println("学生对象在学习~");
}
protected void eat(String food){
System.out.println("学生对象在吃 " + food);
}
String sleep(){
System.out.println("sleep方法执行了");
return "学生对象在休息~";
}
private String playGame(String name){
System.out.println("学生对象在玩 " + name);
return "真好玩~";
}
}
public class Demo1 {
public static void main(String[] args) throws Exception{
// 获取类的字节码文件对象
Class clazz = Class.forName("cn.pdsu.edu.reflect.method.Student");
// 创建Student类对象
Student student = (Student) clazz.newInstance();
// 获取类中的所有的成员方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("declaredMethod = " + declaredMethod);
}
System.out.println("=========================");
// 获取类中是定的成员方法
// 连个参数分别为:方法名、参数的类型
// 无形参方法
Method study = clazz.getDeclaredMethod("study");
// 方法对象调用invoke()方法,表明调用了该方法
// 两个参数,第一个为调用该方法的对象,第二各位参数列表
study.invoke(student) ;
System.out.println("=========================");
// 无返回值,一个参数的方法
Method eat = clazz.getDeclaredMethod("eat", String.class);
// 调用方法
eat.invoke(student , "米饭");
System.out.println("=========================");
// 有返回值,无参数
Method sleep = clazz.getDeclaredMethod("sleep");
// 调用方法并接收返回值
Object invoke = sleep.invoke(student);
System.out.println("invoke = " + invoke);
System.out.println("=========================");
// 有返回值,有参数
Method playGame = clazz.getDeclaredMethod("playGame", String.class);
// playGame()方法是私有的,先设置权限
playGame.setAccessible(true);
Object invoke1 = playGame.invoke(student, "王者荣耀");
System.out.println("invoke1 = " + invoke1);
System.out.println("=========================");
}
}
类的加载(Load):将类的class文件读取内存,并为之创建一 个java.lang.Class对 象。此过程由类加载 器完成
——>
类的链接(Link):将类的二进制数 据合并到JRE中
——>
类的初始化(Initialize):JVM负责对类 进行初始化
类加载器ClassLoader,它的作用是将类装载进内存的,JVM规定了如下类型的加载器:
引导类加载器
:用C++编写的,是JVM自带的类 加载器,负责Java平台核心库,用来装载核心类 库。该加载器无法直接获取
扩展类加载器
:负责jre/lib/ext目录下的jar包或 – D java.ext.dirs 指定目录下的jar包装入工作库
系统类加载器
:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工 作 ,是最常用的加载器
- 常用方法
static ClassLoadergetSystemClassLoader()
:返回用于委派的系统类加载器。ClassLoadergetParent()
:返回父类加载器进行委派。InputStreamgetResourceAsStream(String name)
:返回用于读取指定资源的输入流。
实例:
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, IOException {
// 获取系统类加载器
ClassLoader classloader = ClassLoader.getSystemClassLoader();
System.out.println(classloader);
// 获取系统类加载器的父类加载器,即扩展类加载器
ClassLoader classloaderParent = classloader.getParent();
System.out.println(classloaderParent);
// 获取扩展类加载器的父类加载器,即引导类加载器
ClassLoader classloaderParentParent = classloaderParent.getParent();
System.out.println(classloaderParentParent); // null
// 获取当前类由哪个类加载器进行加载
Class clazz = Class.forName("_classloader.Demo3");
ClassLoader classLoader = clazz.getClassLoader();
System.out.println(classLoader);
// 获取Object类的类加载器
ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader1); // null
// 获取类路径下指定文件的输入流
InputStream is = Class.forName("_classloader.Demo3").getClassLoader().getResourceAsStream("_classloader\\file.properties");
byte[] bytes = new byte[1024] ;
int len = is.read(bytes);
System.out.println(new String(bytes , 0 , len));
}
}