反射机制主要使用的包是:java.lang.reflect(下面的Method,Field,Constructor)、java.lang.Class
1.获取class的三种方式
(1).Class.forName(“类路径”)
(2).实例对象.getClass()//方法继承自Object
(3).类名.getClass
2. 通过反射实例化对象
调用Class的实例化对象.newInstance()
底层调用的是类的无参构造方法,如果没有无参构造方法,会出现异常
3. 调用类的静态代码块的一种方式
Class c = Class.forName("ClassPath")//参数为类的路径
这条命令会导致类加载,从而使类的静态代码块执行
4. 获取类路径下文件夹的绝对路径(通用)
(1)实现方式:
Thread.currentThread().getContextLoader().getResource("类的名字").getPath()
解释:当前线程的类加载器默认从类的根路径下加载资源,所以如果属性配置文件与类路径一致,就能通过getSource()方法获取,注意:从当前类根路径出发(src),例如:com/test/Test01
(2)使用流的方式实例化对象:
Properties p = new Properties();
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("1.properities");
p.load(in);
String str = p.getProperty("ClassPath");
System.out.println(str);
Class c = Class.forName(str);
System.out.println(c.newInstance());
- 资源绑定器的使用
**局限性:只能绑定扩展名字为.properties的文件、同样只能查找类根路径下的文件。
使用:
//注意:不需要带上文件的扩展名
ResouceBundle bundle = ResouceBundle.getBoundle("资源文件名字")
//获取属性
String value = bundle.getString("key的值")
- 类加载器的双亲委派机制
jdk中自带三个加载器:
启动类加载器:加载rt.jar(新版jdk貌似已经不是这个了)
扩展类加载器:加载ext/*.jar(新版jdk貌似已经不是这个了)
应用类加载器:加载classpath中的类
为了保证类加载的安全,使用了双亲委派机制,优先从启动类加载器中加载,这个过程成为“父”。“父”无法加载到,再从扩展类加载器中加载,这个过程成为“母”。如果都加载不到直到加载到为止 - 反射获取属性
(1).找到类:三种方式上面第一点
常用的: static Class forName()
静态方法,根据类名寻找类,返回Class类对象
(2).找到Field:Field[] getDeclaredFields()
Class类下的实例方法,找到对应类的所有属性
(3).获取属性的修饰符
int getModifier()
Field类下实例方法,获取类的所有修饰符,返回值为int型,每一个int数字代表着不同的修饰符号
(3.1).获取int类型修饰符转换为对应修饰符
static String Modifier.toString(int)
Modifier类下静态方法,可以将3中获取的int返回值对应转换成具体的修饰符
(4).获取属性的类型
Class getType()
Field类下面的实例方法,返回值为Field实例对象对应的Class对象
一般配合getSimpleName获取到具体的类型
(5).获取属性的名字
String getName
Field类下的实例方法
8. 反射修改属性的值(重点)
(1).获取和修改共有字段的值
获取对象的Class
Class c = Class.forName("")//填写类路径
//获取对应Class的一个实例
Object obj = c.newInstance()
//根据属性名称获取属性
Field f =c.getDeclaredField(“填写属性名字”)
//修改属性值
f.set(obj,)//第一个参数为对象,第二个参数是要赋的值
//获取属性值
f.get(obj)
(2).获取私有字段的值
Class c = Class.forName("")//填写类路径
//获取对应Class的一个实例
Object obj = c.newInstance()
//根据属性名称获取属性
Field f =c.getDeclaredField(“填写属性名字”)
重点也是不同点:打破封装,
f.setAccessible(true)
//修改属性值
f.set(obj,)//第一个参数为对象,第二个参数是要赋的值
//获取属性值
f.get(obj)
9. 可变长度参数
可变长参数必须在参数列表中的最后一个,可变长度参数只有一个,可变长度参数可以当做数组来看待,可允许直接传递一个数组
形式:
public static void test(String... args)
- 反射method
(1).获取对应类的Class
Class c = Class.forName()
(2).调用get.DeclaredMethods()获取所有的Methods数组
Method methods[] = c.getDeclaredMethods()
(3).获取方法的修饰符
for(Method method:methods){
system.out.println(Modifier.toString(method.getMedifiers()));
}
(4).获取方法返回值
method.getReturnType()
实例方法,返回Class对象
(5).获取方法的参数类型
method.getParameterTypes()
实例方法返回Class数组
12. 反射机制调用方法(重点)
(1).获取相应对象的Class
Class c = Class.forName(“类路径”)
(2).实例化对象:
Object obj = c.newIntance()
(3).获取想要调用的方法
Method m = c.getDeclaredMethod("",Class… args)
第一个参数:要调用的方法名字
第二个参数:要调用的方法的参数类型列表
(eg:
method m = c.getDeclaredMethod(“test”,String.Class,String.Class)
)
(4).调用方法
object o = method.invoke(要调用的方法的对象,要传入的参数)
13. 调用构造方法创建对象
(1).获取所有构造方法
Constructor con = c.getDeclaredConstructors()
(2).获取指定的构造方法
Constructor con = c.getDeclaredConstructor(Class… args)
(3).使用constructor实例对象的newIntance()方法
Object o = constructor.newInstance(Class… args)
参数列表为要调用的构造方法的参数类型
14. 调用类实现父类的和接口
(1).获取对应的类
Class c = Class.forName("")
(2).获取该类实现的父类
实例方法,返回值是Class
Class getSuperClass()
(3).获取实现的接口
Class[] getInterfaces(){}
实例方法,返回值是Class数组