什么是反射
reflection(反射)
Class类是一个管理反射的类
一个类只有一个Class对象
一个类被加载后都会被封装在一个Class对象中
获取字节码的三个方法
/*第一种方式通过地址获取反射*/
Class c1 = Class.forName("Student");
/*通过类名获得*/
Class<Student> c2 = Student.class;
/*通过对象名获取*/
Student person= new Student();
Class c3= person.getClass();
/*一个对象只能有一个Class*/
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
什么时候类会初始化
类的加载:将class文件字节码内容加载到内存中,并将这些静态数据转化成方法区的运行时数据结构,然后生成一个代表这个类的java,long,Class对象。
主动引用
当new子类对象的时候父类会被初始化,子类也会初始化
反射引用子类,父类和子类都要初始化
被动引用(不会产生初始化)
子类去调用父类的静态方法和变量子类不会被初始化
数组也不会产生初始化
调用常量不会初始化子类和父类
反射的操作方法
newInstance()用无参的构造器来new对象
Class demo1 = Class.forName("Demo1")
Demo1 c1 =(Demo1) demo1.newInstance();
getDeclaredConstructor()通过有参的方法来new对象
Class demo1 = Class.forName("Demo1")
Constructor Constructor = demo1.getDeclaredConstructor(int.class, String.class, Demo2.class);
Demo1 c2 = (Demo1)Constructor.newInstance(12,"云边",new Demo2("小卖部"));
getDeclaredMethod获取方法
Class demo1 = Class.forName("Demo1");
Demo1 c1 =(Demo1) demo1.newInstance();
Method setName = demo1.getDeclaredMethod("setName", String.class);
invoke(那个对象,赋值)打开方法权限
setName.invoke(c1,null);
getDeclaredField修改属性
Field name2 = demo1.getDeclaredField("name");
setAccessible(true);关闭安全检查
Field name2 = demo1.getDeclaredField("name");
name2.setAccessible(true);
name2.set(c2,"梦");
set赋值
name2.set(c2,"梦");
通过反射去建对象和调方法
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 通过反射越过泛型检查
*
* 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
*/
public class Demo {
public static void main(String[] args) throws Exception{
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
// strList.add(100);
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(strList, 100);
//遍历集合
for(Object obj : strList){
System.out.println(obj);
}
}
}
通过反射无参构造和有产构造
Class c1 = Class.forName("Demo1");/*获取字节码c1*/
Constructor Constructor = c1.getDeclaredConstructor(int.class,String.class,Demo2.class);/*根据c1去调用构造器*/
Demo1 c2=(Demo1) Constructor.newInstance(15, "王梦", new Demo2("云边有个小卖部"));/*new出对象叫c2*/
System.out.println(c2);
Method getDemo2 = c1.getDeclaredMethod("getDemo2");/*通过c1去调方法*/
Method setName = c1.getDeclaredMethod("setName", String.class);/*通过字节码c1去获取setname的方法*/
/*invoke激活的意思*/
setName.invoke(c2,"wang");/*激活set方法通过对象c2给里面的setname赋值*/
System.out.println(c2.getName()+"获去年纪");
System.out.println(getDemo2.getName());
System.out.println( c2.getDemo2().getName());
System.out.println("===============================================");
/*通过反射去操作属性*/
Demo1 demo1 =(Demo1) c1.newInstance();/*通过c1去获取无参的构造方法*/
System.out.println(demo1);
Field name = c1.getDeclaredField("name");/*通过方法获取声明字段*/
name.setAccessible(true);/*关闭安全检查*/
name.set(demo1,"孟");/*通过set跟demo1对象的name赋值*/
System.out.println(demo1.getName());
}
自我总结
我觉得反射就是通过反射获取唯一字节码对象,通过字节码对象去获取方法,泛型,属性,父类,变量,放入通过字节码对象new的对象中,