反射快速入门
方向探知,在程序运行过程中动态的获取类的相关属性
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制,就叫做JAVA 的反射机制
创建一个普通的类
public class Car {
public String color="red";
public Integer price=10000;
public void run () {
System.out.println("我是汽车 我会跑!");
}
}
简单的应用
/**
* 反射的基本应用
*/
public class TestDemo {
public static void main(String[] args) throws Exception {
// 通过普通的方式获取Car 对象
Car car = new Car();
System.out.println("通过普通的方式获取Car " + car);
// 通过 反射的方式获取
Class<?> name = Class.forName("pojo.Car");
Object o = name.newInstance();
System.out.println("通过 反射的方式获取" + o);
// 通过反射获取属性和方法
Field color = name.getField("color");
System.out.println("color = " + color.get(o));
}
}
反射机制的原理
反射机制允许程序在执行期借助与 Reflection Api 获取任何类的内部信息(比如成员变量,构造方法,成员方法等),并能操作对象的属性及方法,反射在设计模式和框架底层都会使用到。
加载完成类之后 在堆中就产生了一个Class 类型的对象(一个类只有一个Class 对象)这个对象包含了类的完整结构信息 通过这个对象得到累的结构 ,这个对象就像一面镜子 透过镜子看到类的结构 所以形象的称为:反射。
Java 反射机制可以完成:
1,在运行时判断任意一个对象所属的类
2,在运行时构造任意一个类的对象
3,在运行时构造任意一个类所具有的成员变量和方法
4,在运行时调用任意一个对象的成员变量和方法
5,生成动态代理
反射相关的主要类
1,java.lang.Class 代表一个类 Class 对象表示某个类加载后在堆中的对象
2,java.lang.reflect.Method 代表类的方法
3,java.lang.reflect.Field 代表类的成员变量
4,java.lang.reflect.Constructor 代表类的结构方法。
反射的优缺点
优点:可以动态的创建和使用对象(也是框架底层核心)使用灵活,没有反射机制 框架技术就失去底层支撑
缺点:使用反射基本是解释执行,对执行速度有影响
/**
* 反射的基本应用
*/
public class TestDemo {
public static void main(String[] args) throws Exception {
fun();
fun1();
}
// 普通的方式获取
public static void fun() {
long start = System.currentTimeMillis();
Car car = new Car();
for (int i = 0; i < 10000; i++) {
car.run();
}
long end = System.currentTimeMillis();
System.out.println("普通的方式需要的时间" +(end-start) +"ms");
}
public static void fun1() throws Exception {
long start = System.currentTimeMillis();
Class<?> aClass = Class.forName("pojo.Car");
Object instance = aClass.newInstance();
Method method = aClass.getMethod("run");
for (int i = 0; i < 10000; i++) {
method.invoke(instance);
}
long end = System.currentTimeMillis();
System.out.println("反射的方式需要的时间" +(end-start) +"ms");
}
}
结果
反射优化
由于有安全检查 所以反射的时候是比较慢 的 我们可以
public static void fun2() throws Exception {
long start = System.currentTimeMillis();
Class<?> aClass = Class.forName("pojo.Car");
Object instance = aClass.newInstance();
Method method = aClass.getMethod("run");
method.setAccessible(true);
for (int i = 0; i < 10000; i++) {
method.invoke(instance);
}
long end = System.currentTimeMillis();
System.out.println("反射优化的方式需要的时间" +(end-start) +"ms");
}
结果
Class 类介绍
传统的方式去获取对象
我们可以打断点去测试我们的这个传统的方式是如何获取的对象的
newCar() 对象的时候会直接静茹 ClassLoader 的loadClass 方法中
反射的方式获取对象
进入的是Class 中 但是仍然调用的ClassLoader 类加载 的Class 对象
Class 类对象不是new 出来的 而是系统创建的,在某个类的Class 类对象,在内存中只有一份 因为类只加载一次
Class 类中的常用方法
public class Demo {
public static void main(String[] args) throws Exception{
// 获取Car 类对象
Class<?> name = Class.forName("pojo.Car");
// 输出cls
System.out.println("name = " + name);
// 获取到java.lang.Class
System.out.println(name.getClass());
// 获取到包名
System.out.println(name.getPackage().getName());
// 获取到全类名
System.out.println(name.getName());
// 通过类对象创建实例对象
Object o = name.newInstance();
System.out.println(o
);
// 通过反射获取属性
Field color = name.getField("color");
System.out.println(color.get(o));
// 通过反射给属性设置值
color.set(o,"fff");
System.out.println(color.get(o));
// 获取所有属性
Field[] fields = name.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
Class 类对象获取的方式
/**
*
* Class 获取的方式
*
* */
public class Demo1 {
public static void main(String[] args) throws Exception {
// Class.forName
Class<?> name = Class.forName("pojo.Car");
// 直接类名.class
Class<Car> aClass = Car.class;
// 通过new 的方式获取
Class<? extends Car> aClass1 = new Car().getClass();
// 通过类加载器的形式获取
ClassLoader classLoader = Demo1.class.getClassLoader();
Class<?> aClass2 = classLoader.loadClass("pojo.Car");
// 基本数据类型Class 类 int long ...
Class<Integer> aClass3 = int.class;
// 包装类的class
Class<Integer> aClass4 = Integer.TYPE;
System.out.println("aClass3 = " + aClass3);
System.out.println("aClass4 = " + aClass4);
}
}
结果
静态加载和动态加载
反射机制是Java 实现动态语言的关键 也就是通过反射实现类动态加载
1,静态加载 编译时加载相关的类 如果没有则保存 依赖性强
2,动态加载 运行时加载需要的类 如果 运行时不用该类 则不报错 降低了依赖性
类加载时机
1,当创建对象时(new)
2,当子类被加载时
3,调用类中的静态成员时
4,通过反射