反射
反射机制
基本介绍
-
反射机制允许程序在执行期借助子Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法
-
加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射
反射相关类
- java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method:代表该类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法
package reflection;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
public class Reflection1 {
public static void main(String[] args) throws Exception {
//使用properties类读取配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src/reflection/re.properties"));
String classFullPath = properties.get("classFullPath").toString();
String methodName = properties.get("method").toString();
//使用反射
//加载类,返回Class类型的对象
Class cls = Class.forName(classFullPath);
//通过cls获取你加载的类的对象实例
Object object = cls.newInstance();
System.out.println(object.getClass());//运行类型
//获取方法
//java.lang.reflect.Method
Method method = cls.getMethod(methodName);
method.invoke(object);//调用方法
//java.lang.reflect.Field
//无法获取私有的属性
Field field = cls.getField("age");
System.out.println(field.get(object));//显示变量
//java.lang.reflect.Constructor
//Constructor constructor = cls.getConstructor(); //()中可以指定构造器参数类型,现在是无参构造器
Constructor constructor = cls.getConstructor(String.class); //Cat(String name) 现在指定的是带参构造器
System.out.println(constructor);
}
}
反射优化
反射优点和缺点
- 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就会失去底层支撑
- 缺点:使用反射基本是解释执行,对执行速度有影响
关闭访问检查
- Method和Field、Constructor对象都有setAccessible()方法
- setAccessible作用是启动和禁用访问安全检查的开关
- 参数值为true表示 反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查
Class类
基本介绍:
- Class也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 类的Class类对象,在内存中只有一份,且只加载一次
- 每个类的实例都会记录它属于哪个Class实例生成
- 通过Class可以完整地得到一个类的完整结构,通过一系列API
- Class对象是存放在堆的
- 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括 方法代码,变量名,方法名,访问权限等等)
Class类常用方法
方法名 | 说明 |
---|---|
static Class forName(String name) | 返回指定类名name的Class对象 |
Object newInstance() | 调用缺省构造函数,返回该Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体的名称 |
Class[] getInterfaces() | 获取当前Class对象的接口 |
ClassLoader getClassLoader() | 获取该类的类加载器 |
Class getSuperClass() | 返回表示此Class所表示的实体的超类的Class |
Constructor[] getConstructors | 返回一个包含某些Constructor对象的数组 |
Fileld[] getDeclareFields() | 返回Field对象的一个数组 |
Method getMethod(String name,Class ... paramTypes) | 返回一个Method对象,此对象的形参类型为paramType |
package class_;
public class Class {
public static void main(String[] args) throws Exception {
String classAllPath = "class_.Car";
//1 . 获取到Car类 对应的 Class对象
//<?> 表示不确定的Java类型
Class<?> cls = Class.forName(classAllPath);
//2. 输出cls
System.out.println(cls); //显示cls对象
System.out.println(cls.getClass());//输出cls运行类型
//3. 得到包名
System.out.println(cls.getPackage().getName());//包名
//4. 得到全类名
System.out.println(cls.getName());
//5. 通过cls创建对象实例
Car car = (Car) cls.newInstance();
System.out.println(car);//car.toString()
//6. 通过反射获取属性 brand
Field brand = cls.getField("brand");
System.out.println(brand.get(car));
//7. 通过反射给属性赋值
brand.set(car, "奔驰");
System.out.println(brand.get(car));//奔驰
//8.得到所有的属性
System.out.println("=======所有的字段属性====");
Field[] fields = cls.getFields();
for (Field f : fields) {
System.out.println(f.getName());//名称
}
}
}
Class类对象获取
-
前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取
Class cls1 = Class.forName("java.lang.Cat” )
应用场景:多用于配置文件,读取类全路径,加载类
-
前提:若已知具体的类,通过类的class 获取,该方式最为安全可靠,程序性能最高
Class cls2 = Cat.class
应用场景:多用于参数传递,比如通过反射得到对应构造器对象
-
前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class class = 对象.getClass();
应用场景:通过创建好的对象,获取Class对象
-
其他方式(类加载器)
ClassLoader cl = 对象.getClass().getClassLoader();
Class class4 = cl.loadClass(“类的全类名"); -
基本数据(int, char boolean,float,double.byte.long,short)
Class cls = 基本数据类型.class
-
基本数据类型对应的包装类,可以通过.type 得到Class类对象
Class cls = 包装类.TYPE
package class_;
public class Class2 {
public static void main(String[] args) throws Exception {
//1.Class.forName
String classAllPath = "class_.Car";//通过读取配置文件获取
Class<?> cls1 = Class.forName(classAllPath);
System.out.println(cls1);
//2.类名.class
Class<Car> cls2 = Car.class;
System.out.println(cls2);
//3.对象.getClass
Car car = new Car();
Class<?> cls3 = car.getClass();
System.out.println(cls3);
//4.通过类加载[4种]来获取到类的class对象
//先得到类加载器
ClassLoader classLoader = car.getClass().getClassLoader();
//通过类加载器得到class对象
Class<?> cls4 = classLoader.loadClass(classAllPath);
System.out.println(cls4);
//5.基本数据类型
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
Class<Boolean> booleanClass = boolean.class;
System.out.println(integerClass);
//6.基本数据类型对应的包装类,可以通过.TYPE得到Class类对象
Class<Integer> type1 = Integer.TYPE;
Class<Character> type2 = Character.TYPE;
System.out.println(type1);
System.out.println(integerClass.hashCode());
System.out.println(type1.hashCode());
}
}
class Car {
}
有Class对象的类型
-
外部类,成员内部类,静态内部类,局部内部类,匿名内部类
-
interface :接口
-
数组
-
enum:枚举
-
annotation :注解
-
基本数据类型
-
void
类加载
基本介绍
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
类加载时机
- 当创建对象时 (new)//静态加载
- 当子类被加载时,父类也加载 //静态加载
- 调用类中的静态成员时 //静态加载
- 通过反射 //动态加载
过程图
类加载各过程完成任务
加载阶段
JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转换为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
连接阶段
验证
- 目的是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
- 包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
- 可以考虑使用-Xverify:none 参数来关闭大部分的类验证措施,缩短虛拟机类加载的时间
准备
- JVM 会在该阶段对静态变量,分配内存井初始化(对应数据类型的默认初始值如0、OL、null false 等),这些变量所使用的内存都将在方法区中进行分配
解析
- 虛拟机将常量池内的符号引用替换为直接引用的过程
初始化
-
到初始化阶段,才真正开始执行类中定义的 Java 程序代码,此阶段是执行<clinit>() 方法的过程
-
<clinit>() 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,
井进行合井
-
虚拟机会保证一个类的 <Clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<Clinit>()方其他线程都需要阻塞等待,直到活动线程执行<Clinit>()方法完毕
通过反射获取类的结构信息
java.lang.Class类
-
getName:获取全类名
-
getSimpleName:获取简单类名
-
getFields:获取所有public修饰的属性,包含本类以及父类的
-
getDeclaredFields:获取本类中所有属性
-
getMethods:获取所有public修饰的方法,包含本类以及父类的
-
getDeclaredMethods:获取本类中所有方法
-
getConstructors:获取所有public修饰的构造器,包含本类
-
getDeclaredConstructors:获取本类中所有构造器
-
getPackage:以Package形式返回 包信息
-
getSuperClass:以Class形式返回父类信息
-
getlnterfaces:以Class[]形式返回接口信息
-
getAnnotations:以Annotation[] 形式返回注解信息
@Test
public void api01() throws Exception {
//获取class对象
Class<?> personCls = Class.forName("class_.Person");
//获取全类名
System.out.println(personCls.getName());
//获取简单类名
System.out.println(personCls.getSimpleName());
//获取所有public修饰的属性,包括本类的和父类的
System.out.println("==========");
Field[] personClsFields = personCls.getFields();
for (Field personClsField : personClsFields) {
System.out.println(personClsField.getName());
}
//获取本类中的所有属性
System.out.println("==========");
Field[] personClsDeclaredFields = personCls.getDeclaredFields();
for (Field personClsDeclaredField : personClsDeclaredFields) {
System.out.println(personClsDeclaredField.getName());
}
//获取所有public修饰的方法,包含本类以及父类的
System.out.println("==========");
Method[] personClsMethods = personCls.getMethods();
for (Method personClsMethod : personClsMethods) {
System.out.println(personClsMethod.getName());
}
//获取本类中所有方法
System.out.println("==========");
Method[] personClsDeclaredMethods = personCls.getDeclaredMethods();
for (Method personClsDeclaredMethod : personClsDeclaredMethods) {
System.out.println(personClsDeclaredMethod.getName());
}
//获取所有public修饰的构造器,只包含本类
System.out.println("==========");
Constructor<?>[] personClsConstructors = personCls.getConstructors();
for (Constructor<?> personClsConstructor : personClsConstructors) {
System.out.println(personClsConstructor.getName());
}
//获取本类中所有构造器
System.out.println("==========");
Constructor<?>[] personClsDeclaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> personClsDeclaredConstructor : personClsDeclaredConstructors) {
System.out.println(personClsDeclaredConstructor.getName());
}
//以Package形式返回 包信息
System.out.println(personCls.getPackage());
//以Class形式返回父类信息
Class<?> superclass = personCls.getSuperclass();
System.out.println(superclass);//
//getInterfaces:以Class[]形式返回接口信息
System.out.println("==========");
Class<?>[] interfaces = personCls.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface);
}
//以Annotation[] 形式返回注解信息
System.out.println("==========");
Annotation[] annotations = personCls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
java.lang.reflect.Field类
- getModifiers:以int形式返回修饰符
public 是 1,private 是 2 ,protected 是 4,static是8,final是 16 - getType:以Class形式返回类型
- getName:返回属性名
@Test
public void api02() throws Exception{
Class<?> personCls = Class.forName("class_.Person");
Field[] declaredFields = personCls.getDeclaredFields();//获取所有属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName() + " " +
declaredField.getType() + " " +declaredField.getModifiers());
}
}
java.lang.reflect.Method类
-
getModifiers:以int形式返回修饰符
public 是 1,private 是 2 ,protected 是 4,static是8,final是 16 -
getName:返回方法名
-
getParameterTypes:以Class[]返回参数类型数组
@Test
public void api03() throws Exception{
Class<?> personCls = Class.forName("class_.Person");
Method[] declaredMethods = personCls.getDeclaredMethods();//获取所有方法
for (Method declaredMethod : declaredMethods) {
System.out.println("==========");
System.out.println(declaredMethod.getName() + " " +
declaredMethod.getReturnType() + " " + declaredMethod.getModifiers());
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();//获取参数类型
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
}
}
java.lang.reflect.Constructor类
-
getModifiers: 以int形式返回修饰符
-
getName:返回构造器名
-
getParameterTypes:以Class[]返回参数类型数组
@Test
public void api04() throws Exception {
Class<?> personCls = Class.forName("class_.Person");
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("==========");
System.out.println(declaredConstructor.getName() + " "
+ declaredConstructor.getModifiers());
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
}
}
通过反射创建对象
创建方式
方式1:调用类中的pulic修饰的无参构造器
方式2:调用类中的指定构造器
Class相关方法
- newlnstance:调用类中的无参构造器,获取对应类的对象
- getConstructor(Class.…clazz):根据参数列表,获取对应的public构造器对象
- getDecalared Constructor(Class..clazz):根据参数列表,获取对应的所有构造器对象
Constructor类相关方法
- SetAccessible:暴破
- newlnstance(Obiect...obj):调用构造器
package class_;
import java.lang.reflect.Constructor;
public class Test1 {
public static void main(String[] args) throws Exception {
Class<?> userCls = Class.forName("class_.User");
//通过public无参构造器创建实例
Object o = userCls.newInstance();
System.out.println(o);
//通过public的有参构造器
// public User(String name) { 调用该构造器
// this.name = name;
// }
Object o1 = userCls.getConstructor(String.class).newInstance("AAA");
System.out.println(o1);
//通过非public的有参构造器创建实例
//得到构造器
Constructor<?> declaredConstructor = userCls.getDeclaredConstructor(int.class, String.class);
//暴破 使用反射可以访问private构造器/方法/属性
declaredConstructor.setAccessible(true);
Object o2 = declaredConstructor.newInstance(100, "AA");
System.out.println(o2);
}
}
class User { //User类
private int age = 10;
private String name = "A";
public User() {//无参 public
}
public User(String name) {//public的有参构造器
this.name = name;
}
private User(int age, String name) {//private 有参构造器
this.age = age;
this.name = name;
}
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
}
通过反射访问类中的成员
通过反射访问类中的属性
-
根据属性名获取Field对象
Field f= class对象.getDeclaredField(属性名); -
访问:
f.set(o,值);
f.get(o); -
如果是静态属性,则set和get中的参数o,可以写成null
package class_;
import java.lang.reflect.Field;
public class Test2 {
public static void main(String[] args) throws Exception {
Class<?> stuCls = Class.forName("class_.Student");
Object o = stuCls.newInstance();
//使用反射获取age属性对象
Field age = stuCls.getField("age");
age.set(o,100);
System.out.println(age.get(o));
//使用反射操作name属性
Field name = stuCls.getDeclaredField("name");
//暴破
name.setAccessible(true);
name.set(o,"A");
System.out.println(name.get(o));
//由于name是static修饰的变量,所以可以使用null来访问
name.set(null,"AA");
System.out.println(name.get(null));
}
}
class Student {//类
public int age;
private static String name;
public Student() {//构造器
}
public String toString() {
return "Student [age=" + age + ", name=" + name + "]";
}
}
通过反射访问类中的方法
-
根据方法名和参数列表获取Method方法对象
-
获取对象:Object o=class.newlnstance();
-
暴破:o.setAccessible(true);
-
访问:Object returnValue =m.invoke(o,实参列表);
-
注意:如果是静态方法,则invoke的参数o,可以写成null
package class_;
import java.lang.reflect.Method;
public class Test3 {
public static void main(String[] args) throws Exception {
Class<?> bossCls = Class.forName("class_.Boss");
Object o = bossCls.newInstance();
//调用public的hi方法
Method hi = bossCls.getMethod("hi", String.class);
hi.invoke(o,"A");//调用
//调用private static方法
Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);//暴破
System.out.println(say.invoke(o,10, "A", 'a'));//调用
//是static的方法,可以通过null调用
System.out.println(say.invoke(null, 100, "AA", 'a'));
//在反射中,如果方法有返回值,统一返回Object , 但是他运行类型和方法定义的返回类型一致
Object reVal = say.invoke(null, 300, "A", 'a');
System.out.println(reVal.getClass());
Method m1 = bossCls.getDeclaredMethod("m1");
Object relVal1 = m1.invoke(o);
System.out.println(relVal1.getClass());
}
}
class Monster {}
class Boss {//类
public int age;
private static String name;
public Boss() {//构造器
}
public Monster m1() {
return new Monster();
}
private static String say(int n, String s, char c) {//静态方法
return n + " " + s + " " + c;
}
public void hi(String s) {//普通public方法
System.out.println("hi " + s);
}
}
标签:反射,System,Class,public,println,class,out
From: https://www.cnblogs.com/Starry-blog/p/16992648.html