一、反射:
反射是一种动态机制,它允许我们程序运行起来后再确定实例化对象,调用方法和操作属性,可以提高代码的灵活性。
但是反射会带来较慢的运行速度和更多的系统开销,所以不能过度的依赖反射机制。
二、类对象:
java.lang.Class Class类的每一个实例用于表示JVM加载的一个类,并且每个被JVM加载的类都有且只有一个Class的实例与之对应。
通过类对象可以获取到其表示的类的一切信息:类名、方法、属性、构造器等等。 利用反射操作的第一步就是获取要操作的类的类对象。
1、获取一个类的类对象有以下方式:
① [Class] 类名.class --基本类型只有这种获取类对象的方式
EG:Class cls = String.class; Class cls = int.class;
② [Class] Class.forName(String ClassName) --参数为类的完全限定名,即包名.类名
EG:Class cls = Class.forName("java.lang.String);
③ 使用类加载器ClassLoader
2、其他方法:
1、获取类对象表示的名字(完全限定名):[String] getName()
2、获取类名(不包含包名):[String] getSimpleName()
3、获取本类和父类所有的公开方法:[Method数组]getMethods()
4、获取本类所有方法,包括私有方法:[Method数组]getDeclaredMethods()
三、创建对象的方法?
1、使用new关键字直接创建对象
2、使用Object类提供的clone()方法复制对象
3、使用对象流调用readObject()方法反序列化一个对象
4、使用反射的newInstance()方法实例化对象
四、反射Reflect创建对象的方法:
正常创建类的实例化步骤:
{
BaoYang baoyang = new BaoYang();
System.out.println(baoyang);//FYX_Month02_Week02.day03.BaoYang@1b6d3586
}
使用反射创建类的实例化的步骤:
1、获取实例化的类的对象
Class cls = Class.forName("FYX_Month02_Week02.day03.BaoYang");
2.1无参、:通过类对象进行实例化 [Object] newInstance() 该方法会实例化当前Class所表示的一个类的实例,但是前提是这个类必须有无参构造器。
Object by1 = cls.newInstance();
//BaoYang by = (BaoYang) cls.newInstance();
System.out.println(by1);//FYX_Month02_Week02.day03.BaoYang@4554617c
2.2、有参:通过类对象获取指定参数列表的构造器
Constructor c = cls.getConstructor();//啥也不写时候是无参
c = cls.getConstructor(String.class, int.class);//传参:构造器的参数类型的类对象
Object by2 = c.newInstance("卷卷", 20);
如果构造器定义的的是可变参数,在传参时应该确定到底传递几个,分别进行传递 例如:构造器(int... a),那么getConstructor(int.class,int.class)
3.1、获取所有构造器,存入Constructor[]:
Constructor[] cs = cls.getConstructors();
3.2、遍历数组,得到每一个构造器
for(Constructor con :cs){
System.out.println(con);
//public FYX_Month02_Week02.day03.BaoYang()
//public FYX_Month02_Week02.day03.BaoYang(java.lang.String,int)
}
五、使用Reflect的newInstance()访问方法
1、方法们:
1、[Method] getMethod(String name, Class<?>... parameterTypes):
公开方法:第一个参数为要调用的方法名,第二个参数是可变参数,为该方法参数列表中传入的参数类型对象名。
如果是无参构造,则第二个参数无需传参,只需要传递一个方法名;如果是有参构造,需要传递参数类型的对象名,比如"sayLove",String.class,int.class
2、[Method] getDeclaredMethod(String name, Class<?>... parameterTypes):
私有方法:具体用法与getMethod一致,只是针对的权限不同。
3、[Object] invoke(Object obj, Object... args):
第一个参数是对象名,第二个参数是可变参数,为该方法参数列表中传入的参数内容。
如果是无参构造,则第二个参数无需传参,只需要传递一个对象名; 如果是有参构造,需要先传递对象名,再传递参数的内容,比如:by,"抱羊",20
4、[void]setAccessible(boolean flag):
私有方法:强制访问操作,如果直接invoke会抛出IllegalAccessException:非法访问异常;需要在invoke之前设置私有方法的访问权限,true可访问,false不可。
2、具体使用:
1、无参方法:getMethod(方法名).invoke(对象名)
Method m1 = cls.getMethod("sayLove");
//调用该方法
m1.invoke(by);//抱羊:I love 小羊!
Method m2 = cls.getMethod("sayLike");
m2.invoke(by);//抱羊:I like 小羊 !
2、有参方法:getMethod(方法名,参数类型如String.class).invoke(对象名,参数内容)
Method m1 = cls.getMethod("studyCode",String.class);
m1.invoke(by,"java");//抱羊开始学习:java
Method m2 = cls.getMethod("studyCode",String.class,int.class);
m2.invoke(by,"java",1000);//抱羊开始学习:java,一天要写1000行代码!
3、私有方法:getMethod(方法名),setAccessible(权限true),invoke(对象名)
Method m1 = cls.getDeclaredMethod("sayAge");
m1.setAccessible(true);
m1.invoke(by);//抱羊已经20岁了!
六、使用反射操作属性:
1、方法们 :
1、[Field] getField(String name)
获取非私有属性,括号中放入想要查询的属性的名字
直接使用getFiled方法获取私有属性会抛出NoSuchFieldException找不到该属性异常
2、[Field] getDeclaredField(String name)
获取私有属性,括号中放入想要查询的属性的名字
3、[void] setAccessible(true)
设置访问权限 非私有属性默认为false,不设置true则会抛出IllegalAccessException非法访问异常
4、[void] set(Object obj, Object value)
设置属性值
5、[Object] get(Object obj)
获取属性值
6、[Field数组] getFields():
获取所有非私有属性
7、[Field数组] getDeclaredFields():
获取所有属性
2、Reflect所有方法的总结:
属性用Field,方法用Method,获取所有加s返回数组;
公开直接写getXXX,私有先setAccessible设置权限,再getDeclaredXXX