反射
课程简介
基于韩顺平老师的课程,课程 链接.
快速入门
classPath=reflection.Cat
method=sleep
package reflection;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.Random;
public class Reflection01 {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
Properties properties = new Properties();
//获取配置文件
properties.load(new FileInputStream("G:\\heimaxuexi\\java基础\\javabase\\day02\\src\\reflection\\test.properties"));
String classPath = (String) properties.get("classPath");
String method = (String) properties.get("method");
System.out.println(classPath);
System.out.println(method);
//根据全类型动态加载指定类
Class<?> aClass = Class.forName(classPath);
//根据class对象获取该对象的实例
Cat cat = (Cat) aClass.newInstance();
//通过class对象获取该对象的方法
try {
Method method1 = aClass.getMethod(method);
method1.invoke(cat);
}catch (NoSuchMethodException e){
System.out.println("没有该方法");
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
使用这种方式可以在不改动源码的情况下,只需修改配置文件就可以加载指定的类
反射机制
- 通过javac编译java源代码
- 由类加载器将字节码文件以二进制的方式加载到JVM中,存放到方法区并且,在堆中生成一个该类的class对象
package reflection;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 基本使用
*/
public class Reflection02 {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Properties properties = new Properties();
properties.load(new FileInputStream("G:\\heimaxuexi\\java基础\\javabase\\day02\\src\\reflection\\test.properties"));
String classPath = (String) properties.get("classPath");
String method = (String) properties.get("method");
Class<?> catClass = Class.forName(classPath);
Object o = catClass.newInstance();
//获取nameField,注意该方法只能获取public修饰的Field
Field nameField = catClass.getField("name");
//获取private修饰的Field
Field ageField = catClass.getDeclaredField("age");
ageField.setAccessible(true); //暴力反射
Object ageNum = ageField.get(o);
System.out.println(ageNum);
System.out.println(nameField.get(o));
//获取无参构造器
Constructor<?> constructor1 = catClass.getConstructor();
System.out.println(constructor1);
//获取有参构造器
Constructor<?> constructor2 = catClass.getConstructor(String.class, String.class);
System.out.println(constructor2);
}
}
反射优化
package reflection;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 测试使用反射和传统方式的性能
*/
public class Reflection03 {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
reflection1();
System.out.println("===========");
reflection2();
System.out.println("===========");
traditional();
}
public static void reflection1() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> aClass = Class.forName("reflection.Cat");
Object o = aClass.newInstance();
Method eat = aClass.getMethod("eat");
long l = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
eat.invoke(o);
}
long l1 = System.currentTimeMillis();
System.out.println("利用反射1:"+(l1 - l));
}
//反射+调优
public static void reflection2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> aClass = Class.forName("reflection.Cat");
Object o = aClass.newInstance();
Method eat = aClass.getMethod("eat");
//关闭访问检查
eat.setAccessible(true);
long l = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
eat.invoke(o);
}
long l1 = System.currentTimeMillis();
System.out.println("利用反射+调优:"+(l1 - l));
}
public static void traditional(){
Cat cat = new Cat();
long l = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
cat.eat();
}
long l1 = System.currentTimeMillis();
System.out.println("传统方法用时:"+(l1 - l));
}
}
结果:
利用反射1:70
===========
利用反射+调优:30
===========
传统方法用时:10
class类分析
package reflection;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 加载类的工作流程
*/
public class Reflection04 {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Cat cat = new Cat();
Class<? extends Cat> aClass = cat.getClass();
Class<?> aClass1 = Class.forName("reflection.Cat");
Class<Cat> aClass2 = Cat.class;
System.out.println(aClass.hashCode());
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
}
}
结果:
793589513
793589513
793589513
无论是哪一种方式都是由ClassLoader类来加载的,并且只会存在一个Class对象
class的常用方法
package reflection;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试class的常用方法
*/
public class Reflection06 {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
String classPath = "reflection.Cat";
Class<?> cls = Class.forName(classPath);
//输出该class对象是哪一个类的class对象
System.out.println(cls);
//获取该类的运行时对象
System.out.println(cls.getClass());
System.out.println(new Cat().getClass());
//获取包名
System.out.println(cls.getPackageName());
//获取类的全类名
System.out.println(cls.getName());
//获取实例
Cat cat = (Cat) cls.newInstance();
System.out.println(cat);
//获取public修饰的 name 属性
Field name = cls.getField("name");
System.out.println(name.get(cat));
/**
* 注意:
* 1.getField()方法只能获取public修饰的属性,获取不到private修饰的属性
* 2.getDeclaredField()方法可以获取private和public修饰的属性,如果是private
* 修饰的属性,无法直接获取该值,可以通过暴力反射来获取改值
*/
//获取private修饰的age
Field age = cls.getDeclaredField("age");
age.setAccessible(true);
System.out.println(age.get(cat));
//通过反射给属性赋值
Field name1 = cls.getField("name");
name1.set(cat,"加菲猫");
System.out.println(name1.get(cat));
//获取所有的属性,包括private修饰的属性
System.out.println("======获取所有的属性=======");
Field[] declaredFields = cls.getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
System.out.println(declaredField.get(cat));
}
}
}
获取class的六种方式
package reflection;
/**
* 演示获取class对象的六种方式
*/
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
//1.Class.forName
String classPath = "reflection.Person"; //可以通过读取配置文件的方式来获取
Class<?> aClass1 = Class.forName(classPath);
System.out.println(aClass1);
//2.类名.class,应用场景,用于参数传递
Class<Person> aClass2 = Person.class;
System.out.println(aClass2);
//3.对象.getClass(),有对象实例
Person person = new Person();
Class<? extends Person> aClass3 = person.getClass();
System.out.println(aClass3);
//4.通过类加载器
//(1)先得到类加载器 car
ClassLoader classLoader = person.getClass().getClassLoader();
//(2)通过类加载器得到class对象
Class<?> aClass4 = classLoader.loadClass(classPath);
System.out.println(aClass4);
//aClass1,aClass2,aClass3,aClass4是同一个对象
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass3.hashCode());
System.out.println(aClass4.hashCode());
//5.基本数据类型(int,char,boolean,double,byte,long,short)获取class对象
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
Class<Boolean> booleanClass = boolean.class;
System.out.println(integerClass);//自动拆箱和封箱
//6.获取包装类的class对象
Class<Integer> type1 = Integer.TYPE;
Class<Character> type2 = Character.TYPE;
System.out.println(type1);
//底层int和Integer是一样的
System.out.println(integerClass.hashCode() == type1.hashCode());
}
}
结果
class reflection.Person
class reflection.Person
class reflection.Person
class reflection.Person
495053715
495053715
495053715
495053715
int
int
true
那些类有class对象
package reflection;
import java.util.List;
/**
* 演示哪些类型有class对象
*/
public class AllTypeClass {
public static void main(String[] args) {
Class<String> stringClass = String.class;//外部类
Class<List> listClass = List.class;//接口
Class<Integer[]> aClass = Integer[].class;//数组
Class<Character[][]> aClass1 = Character[][].class;//二维数组
Class<Thread.State> stateClass = Thread.State.class;//枚举
Class<Override> overrideClass = Override.class;//注解
Class<Long> longClass = long.class;//基本数据类型
Class<Void> voidClass = void.class;//void
Class<Class> classClass = Class.class;//class
System.out.println(stringClass);
System.out.println(stateClass);
System.out.println(listClass);
System.out.println(aClass);
System.out.println(aClass1);
System.out.println(overrideClass);
System.out.println(longClass);
System.out.println(voidClass);
System.out.println(classClass);
}
}
class java.lang.String
class java.lang.Thread$State
interface java.util.List
class [Ljava.lang.Integer;
class [[Ljava.lang.Character;
interface java.lang.Override
long
void
class java.lang.Class
动态与静态加载
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
public class ClassLoad_ {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("please input Key");
String key = sc.next();
switch(key){
case "1":
//静态加载,编译期间就需要加载该类
Dog dog = new Dog();
dog.sleep();
break;
case "2":
//动态加载,只有运行期间执行下列语句才会加载Person类
Class<?> aClass = Class.forName("Person");
Object o = aClass.getDeclaredConstructor().newInstance();
Method hello = aClass.getMethod("hello");
hello.invoke(o);
System.out.println("ok");
break;
default:
System.out.println("do nothing");
}
}
}
class Dog {
public void sleep(){
System.out.println("sleep...");
}
}
class Person{
public void hello() {
System.out.println("hello");
}
}
类加载
对于类加载感兴趣可以查看周志明老师的JVM虚拟机
1.加载阶段和链接阶段都是由JVM完成的,程序员无法干预,而初始化阶段成程序员可以干预
加载阶段
链接
验证
准备
package classload;
/**
* 类加载-准备阶段
*/
public class ClassLoad01 {
public static void main(String[] args) {
}
}
class A {
//属性-成员变量-字段 三个叫法一样
/**
* n1是实例属性,不是静态变量,和类没有关系,因此在准备阶段,是不会分配内存
* n2 是静态变量,分配内存,赋默认值 0,而不是20
* n3 是常量在编译期间,则会直接被编译器优化,然后给分配了内存并赋了初值,在准备阶段赋与给定得值
*/
public int n1 = 10; //成员变量
public static int n2 = 20; //静态变量
public static final int n3 = 30; //常量
}
各种值在内存中的位置
解析
符号引用:即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。
直接引用:可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;
在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。
举个例子来说,现在调用方法hello(),这个方法的地址是1234567,那么hello就是符号引用,1234567就是直接引用。
初始化
Java在编译之后会在字节码文件中生成方法,称之为类构造器,类构造器同实例构造器一样,也会将静态语句块,静态变量初始化,收敛到方法中,收敛顺序为:
- 静态变量初始化
- 静态代码块
package reflection;
public class Person {
public static String name = "张国荣";
public int age = 65;
static {
name = "周星驰";
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void hello(){
System.out.println("hello");
}
public static void main(String[] args) {
System.out.println(Person.name);
}
}
package classload;
/**
* 分析类加载阶段
*/
public class ClassLoad02 {
public static void main(String[] args) {
//分析
//1.加载B类,并生成B的class对象
//2.链接 num = 0;
//3.初始化阶段
/**
* 收集静态变量的赋值动作和静态代码块中的语句,并合并
* 收集后
* clinit() {
* System.out.println("B 静态代码块被执行");
* num = 300;
* num =100;
* }
* 合并后
* clinit() {
* System.out.println("B 静态代码块被执行");
* num =100;
* }
*/
//4."B() 构造器被执行"
//类加载
//new B();
System.out.println(B.num);//直接使用类的静态变量也会导致类的加载
}
}
class B {
static {
System.out.println("B 静态代码块被执行");
num = 300;
}
static int num =100;
public B(){
System.out.println("B() 构造器执行");
}
}
加载类的安全机制
ClssLoader类中的该方法,保证了某个类在内存中只有一个class对象
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
获取类的结构信息
Class类
package reflection;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* 演示通过反射获取类的结构信息
*/
public class GetClassStructionInfo {
Class<?> studnetClass;
@Before
public void setUp() throws ClassNotFoundException {
studnetClass= Class.forName("reflection.Student");
}
@After
public void tearDown(){
studnetClass = null;
}
//第一组方法
@Test
public void api_01() throws ClassNotFoundException {
//获取全类名
String name = studnetClass.getName();
System.out.println(name);
//获取简单类名
System.out.println(studnetClass.getSimpleName());
//获取public修饰的field,包含父类的和本类的
Field[] fields = studnetClass.getFields();
for (Field field : fields) {
System.out.println("本类以及父类的属性:"+field.getName());
}
//获取本类中的所有属性
Field[] declaredFields = studnetClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
//获取注解
Annotation[] annotations = studnetClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
......
不在演示请查阅API
}
}
class C {
public String hobby;
public void aa(){}
}
@Deprecated
class Student extends C {
//属性
public String name;
protected int age;
String job;
private double salary;
//方法
public void m1(){}
protected void m2(){}
void m3(){}
private void m4(){}
}
Field类
package reflection;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* 演示通过反射获取类的结构信息
*/
public class GetClassStructionInfo02 {
Class<?> teacherClass;
@Before
public void setUp() throws ClassNotFoundException {
teacherClass= Class.forName("reflection.Teacher");
}
@After
public void tearDown(){
teacherClass = null;
}
//第一组方法
@Test
public void api_01() throws ClassNotFoundException {
Field[] declaredFields = teacherClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类中所有属性="+declaredField.getName()+",该属性的修饰符"+declaredField.getModifiers()+"类型为:"+declaredField.getType());
}
}
}
class D {
public String hobby;
public void aa(){}
}
class Teacher extends D {
//属性
public String name;
protected int age;
String job;
private double salary;
public static final String country = "中国" ;
//方法
public void m1(){}
protected void m2(){}
void m3(){}
private void m4(){}
}
本类中所有属性=name,该属性的修饰符1类型为:class java.lang.String
本类中所有属性=age,该属性的修饰符4类型为:int
本类中所有属性=job,该属性的修饰符0类型为:class java.lang.String
本类中所有属性=salary,该属性的修饰符2类型为:double
本类中所有属性=address,该属性的修饰符25类型为:class java.lang.String
Method对象
请查阅API不再演示
@Test
public void api_02() {
Method[] declaredMethods = teacherClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("方法名:"+declaredMethod.getName()+",返回类型:"+declaredMethod.getReturnType()+",参数数量"+declaredMethod.getParameterCount());
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("参数的类型:"+parameterType.getName());
}
System.out.println("=====");
}
}
方法名:m2,返回类型:void,参数数量0
=====
方法名:m1,返回类型:class java.lang.String,参数数量1
参数的类型:java.lang.String
=====
方法名:m3,返回类型:void,参数数量0
=====
方法名:m4,返回类型:void,参数数量0
constructor对象
请查阅API
通过反射创建对象
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 通过反射创建对象
*/
public class GetObjectByReflection {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//1.获取Woker对象的Class对象
Class<?> workerClass = Class.forName("reflection.Worker");
//1.无参构造器创建对象
Object o = workerClass.newInstance();
System.out.println(o);
//2.1获取public的无参构造器
Constructor<?> constructor1 = workerClass.getConstructor(String.class);
/*
constructor1对象就是
public Worker(String name) {
this.name = name;
}
*/
//2.2创建对象,传入参数
Object zsh = constructor1.newInstance("张国荣");
System.out.println(zsh);
//3.1获取非public构造器
Constructor<?> declaredConstructor = workerClass.getDeclaredConstructor(String.class, int.class);
//3.2进行爆破
declaredConstructor.setAccessible(true);//不进行无法访问
//3.3创建对象,传入参数
Object zxx = declaredConstructor.newInstance("周星星", 33);
System.out.println(zxx);
}
}
class Worker{
public String name = "zs";
public int age = 21;
//有参构造
private Worker(String name, int age) {
this.name = name;
this.age = age;
}
//无参构造
public Worker() {
}
//有参构造
public Worker(String name) {
this.name = name;
}
@Override
public String toString() {
return "Worker{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Worker{name='zs', age=21}
Worker{name='张国荣', age=21}
Worker{name='周星星', age=33}
通过反射操作类中的属性
package reflection;
import org.junit.BeforeClass;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* 通过反射创建对象
*/
public class GetObjectByReflection {
public static Class<?> workerClass;
public static Worker worker;
@BeforeClass
public static void beforeClass() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
workerClass = Class.forName("reflection.Worker");
Constructor<?> constructor = workerClass.getConstructor();
worker = (Worker)constructor.newInstance();
}
@Test
public void Field() throws NoSuchFieldException, IllegalAccessException {
//获取public的属性
Field name = workerClass.getField("name");
Object o = name.get(worker);
System.out.println(o);
//设置name属性的值
name.set(worker,"古天乐");
System.out.println(name.get(worker));
System.out.println("=========");
//获取private修饰的属性
Field age = workerClass.getDeclaredField("age");
age.setAccessible(true);
System.out.println(age.get(worker));
age.set(worker,30);
System.out.println(age.get(worker));
System.out.println("=========");
//对于类变量get()和set()的对象可以为null
Field address = workerClass.getDeclaredField("address");
System.out.println(address.get(null));
address.set(null,"china");
System.out.println(address.get(null));
}
}
class Worker{
public String name = "zsh";
private int age = 21;
public static String address = "中国";
private Worker(String name, int age) {
this.name = name;
this.age = age;
}
public Worker() {
}
public Worker(String name) {
this.name = name;
}
@Override
public String toString() {
return "Worker{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
zsh
古天乐
=========
21
30
=========
中国
china
通过反射获取方法及使用
package reflection;
import org.junit.BeforeClass;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 通过反射创建对象
*/
public class GetObjectByReflection {
public static Class<?> workerClass;
public static Worker worker;
@BeforeClass
public static void beforeClass() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
workerClass = Class.forName("reflection.Worker");
Constructor<?> constructor = workerClass.getConstructor();
worker = (Worker)constructor.newInstance();
}
@Test
public void method() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//获取public + static的方法
Method eat = workerClass.getMethod("eat");
//对于静态方法invoke该方法,不需要传入该对象实例
eat.invoke(null);
}
}
class Worker{
public String name = "zsh";
private int age = 21;
public static String address = "中国";
private Worker(String name, int age) {
this.name = name;
this.age = age;
}
public Worker() {
}
public Worker(String name) {
this.name = name;
}
public void work(){
System.out.println("工作...");
}
public static void eat(){
System.out.println("吃饭...");
}
private void sleep(){
System.out.println("睡觉...");
}
@Override
public String toString() {
return "Worker{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
使用方法和Field一样,不再详细展开
练习
package reflection;
import java.lang.reflect.Field;
public class PrivateTest {
private String name = "hellokitty";
public String getName() {
return name;
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
PrivateTest privateTest = new PrivateTest();
Class<? extends PrivateTest> aClass = privateTest.getClass();
Field name = aClass.getDeclaredField("name");
name.set(privateTest,"小叮当");
System.out.println(name.get(privateTest));
}
}