1.一个需求引出反射
Cat类
public class Cat {
private String name="招财猫";
public int age=10;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
public void hi(){ //常用方法
//System.out.println("hi"+name);
}
public void cry(){
System.out.println(name+"喵喵叫");
}
}
2.反射引出的问题
public class ReflectionQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//根据配臀文件re,properties指定信总,创建Cat对象并调川方法hi
//老韩同忆
//传统的方式new对象-》调用方法
Cat cat=new Cat();
cat.hi();
//我们尝试做一做 ->明白反射
//1.使用Properties 类 ,可以读写配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("src/main/java/com/ReflexReview/re.properties"));
//就是getproperty底层还是get方法
String classfullpath=properties.get("classfullpath").toString();
String methodName=properties.get("method").toString();
System.out.println("classfullpath="+classfullpath);
System.out.println("method="+methodName);
//即通过外部文件配置 在不修改源码的情况下 来控制程序 也符合设计模式OCP原则(开闭原则:不修改源码 ,来扩展功能)
//3.使用反射机制解决
//(1)加载类 ,返回Class类型的对象cls
Class cls=Class.forName(classfullpath); //Class就是一个类 类的名字叫Class
//(2) 通过cls得到加载的类 com.ReflexReview.hspedu.Cat的对象实例
// Cat o=(Cat)cls.newInstance();
Object o=cls.newInstance();
System.out.println("o的运行时类型"+o.getClass()); //Object方法返回该类运行时类
//(3)通过cls 通过cls得到加载的类 com.ReflexReview.hspedu.Cat 的 methodName"hi"方法对象
// 即 :在反射中,可以把方法视为对象(万物皆为对象)
Method method1=cls.getMethod(methodName);
//(4) 通过method1调用方法 即通过方法对象来实现调用方法
System.out.println("=================");
method1.invoke(o);//专统方法对象,方法(),反射机制方法.invoke(对象)
}
}
3.反射快速入门
forname方法会导致类的加载
package com.ReflexReview.hspedu.reflectionquestion;
import com.ReflexReview.hspedu.Cat;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 反射问题的引入
*/
public class ReflectionQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//根据配臀文件re,properties指定信总,创建Cat对象并调川方法hi
//老韩同忆
//传统的方式new对象-》调用方法
Cat cat=new Cat();
cat.hi();
//我们尝试做一做 ->明白反射
//1.使用Properties 类 ,可以读写配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("src/main/java/com/ReflexReview/re.properties"));
//就是getproperty底层还是get方法
String classfullpath=properties.get("classfullpath").toString();
String methodName=properties.get("method").toString();
System.out.println("classfullpath="+classfullpath);
System.out.println("method="+methodName);
//即通过外部文件配置 在不修改源码的情况下 来控制程序 也符合设计模式OCP原则(开闭原则:不修改源码 ,来扩展功能)
//3.使用反射机制解决
/* forName
public static 类<?> forName(String className)
throws ClassNotFoundException
返回与给定字符串名称的类或接口相关联的类对象。 调用此方法相当于:
Class.forName(className, true, currentLoader)
其中currentLoader表示当前类的定义类加载器。*/
//(1)加载类 ,返回Class类型的对象cls
//Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。
Class cls=Class.forName(classfullpath); //Class就是一个类 类的名字叫Class
//(2) 通过cls得到加载的类 com.ReflexReview.hspedu.Cat的对象实例
// Cat o=(Cat)cls.newInstance();
Object o=cls.newInstance();
System.out.println("o的运行时类型"+o.getClass()); //Object方法返回该类运行时类
//(3)通过cls 通过cls得到加载的类 com.ReflexReview.hspedu.Cat 的 methodName"hi"方法对象
// 即 :在反射中,可以把方法视为对象(万物皆为对象)
// forName
// public static 类<?> forName(String className)
// throws ClassNotFoundException
// 返回与给定字符串名称的类或接口相关联的类对象。 调用此方法相当于:
// Class.forName(className, true, currentLoader)
// 其中currentLoader表示当前类的定义类加载器。
Method method1=cls.getMethod(methodName);
//(4) 通过method1调用方法 即通过方法对象来实现调用方法
System.out.println("=================");
method1.invoke(o);//专统方法对象,方法(),反射机制方法.invoke(对象)
}
}
4.反射机制
package com.ReflexReview.hspedu;
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 Reflection01 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//1.使用Properties 类 ,可以读写配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("src/main/java/com/ReflexReview/re.properties"));
//就是getproperty底层还是get方法
String classfullpath=properties.get("classfullpath").toString();
String methodName=properties.get("method").toString();
//3.使用反射机制解决
//(1)加载类 ,返回Class类型的对象cls
//返回与给定的字符串名称的类或接口相关的 类对象。调用此方法等效于
Class cls=Class.forName(classfullpath); //Class就是一个类 类的名字叫Class
//(2) 通过cls得到加载的类 com.ReflexReview.hspedu.Cat的对象实例
// Cat o=(Cat)cls.newInstance();
Object o=cls.newInstance();
System.out.println("o的运行时类型"+o.getClass()); //Object方法返回该类运行时类
//(3)通过cls 通过cls得到加载的类 com.ReflexReview.hspedu.Cat 的 methodName"hi"方法对象
// 即 :在反射中,可以把方法视为对象(万物皆为对象)
Method method1=cls.getMethod(methodName);
//(4) 通过method1调用方法 即通过方法对象来实现调用方法
System.out.println("=================");
method1.invoke(o);//专统方法对象,方法(),反射机制方法.invoke(对象)
//java,Lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
//得到name字段 得不到报异常。因为name是private私有属性
/* Field name=cls.getField("name");
异常了
Exception in thread "main" java.lang.NoSuchFieldException: name
at java.lang.Class.getField(Class.java:1703)
at com.ReflexReview.hspedu.Reflection01.main(Reflection01.java:36)
Disconnected from the target VM, address: '127.0.0.1:10997', transport: 'socket'
Process finished with exit code 1*/
//getField不能得到私有的属性
Field nameFileld=cls.getField("age");
System.out.println(nameFileld);
System.out.println(nameFileld.get(o));//传统写法对象.成员变量,反射:成员变量对象.get(对象) 招财猫喵喵叫
//java.Lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
Constructor constructor=cls.getConstructor();//()中可以指定构造器参数类型,返同无参构造器
System.out.println(constructor);//Cat()
//搞出这个类的 public Cat(String name) 有一个参数的构造器
Constructor constructor2=cls.getConstructor(String.class);//这里老师传入的String.class就是String类的Class对象
System.out.println(constructor2);//Cat(string name)
}
}
o的运行时类型class com.ReflexReview.hspedu.Cat
=================
招财猫喵喵叫
public int com.ReflexReview.hspedu.Cat.age
10
public com.ReflexReview.hspedu.Cat()
public com.ReflexReview.hspedu.Cat(java.lang.String)
反射机制原理图
1.对于第一个箭头ClassLoder 就体现了反射
如果new cat()会导致类的加载 加载cat.class字节码文件到内存的堆区域 class类对象 这里有成员变量 构造器 成员方法 注解 泛型
怎么就会生成一个class对象放在堆区里面呢?
这里有一个特别重要的东西 叫做类的加载器
class类对象在堆还有个数据结构 变成可以操作的数据了
底层会把成员变量映射成一个对象Field[]数组对象 构造器Constructor[] cons因为构造器可能有多个 成员方法Method[] ms
类的加载完就生成对象了 相当于往运行堆区复制东西
2.类的加载完成后会生成一个对象 这个对象在运行阶段堆区而不是类对象/堆区中 同时该对象知道他是属于哪个Class对象的
他们之间是有映射关系的
3.得到Class对象后
1.创建对象,调用对象方法2.操作它的属性等等
1.2体现JVM底层实现
3.是应用程序员的应用
5.反射相关类
一.反射机制可以帮组我们完成的事情
二.反射相关的主要类
对于1的理解 1个class类对象就代表一个class字节码文件的感觉
对于理解2 Method表示类的方法 他的一个Method对象表示某个类的方法
理解3 Field代表某个类的成员变量 它的一个对象代表某个类的字段成员变量了44444444444444444444444
6. 反射优点和缺点
一.案例
package com.ReflexReview.hspedu;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试反射调用的性能,和优化方案
*/
public class Reflection02 {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
// Field
m1();
m2();
m3();
}
//传统方法调用hi
public static void m1(){
Cat cat=new Cat();
long start=System.currentTimeMillis();
for(int i=0;i<90000;i++){
cat.hi();
}
long end=System.currentTimeMillis();
System.out.println("传统方式来调用hi耗时间"+(end-start));
}
//反射机制调用方法hi
public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls=Class.forName("com.ReflexReview.hspedu.Cat");
Object o=cls.newInstance();
Method hi=cls.getMethod("hi");
long start=System.currentTimeMillis();
for(int i=0;i<90000;i++){
hi.invoke(o);
}
long end=System.currentTimeMillis();
System.out.println("m2()耗时"+(end-start));
}
//反射调优+关闭访问检查
public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls=Class.forName("com.ReflexReview.hspedu.Cat");
Object o=cls.newInstance();
Method hi=cls.getMethod("hi");
hi.setAccessible(true);//在反射调用方法时,取消访问检查
long start=System.currentTimeMillis();
for(int i=0;i<90000;i++){
hi.invoke(o);
}
long end=System.currentTimeMillis();
System.out.println("m3()耗时"+(end-start));
}
}
二. 反射调用优化-关闭访问检查
传统方式来调用hi耗时间4
m2()耗时13
m3()耗时9
7.Class类分析
新开