Java-reflax 反射
概念
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方
法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以>及动态调用对象的方法的功能称为Java语言的反射机制。
逐步分析
1.Class
(1).Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性
(2).对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
(3).对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。 一个 Class 对象包含了特定某个类的有关信息。
(4).Class 对象只能由系统建立对象
(5).一个类在 JVM 中只会有一个Class实例
2.反射获取类对象的三种方式(通过一个Junit测试来说明)
2.1 直接通过类名.Class的方式得到
@Test
public void getClassByClass(){
Class c = Demo.class;
System.out.println("通过类名获取 : "+c);
}2.2 通过对象的getClass()方法获取,这个使用的少
(一般是传的是Object,不知道是什么类型的时候才用)
@Test
public void getClassByObject(){
Demo demo = new Demo();//此处会调用无参构造方法
Class<? extends Demo> class1 = demo.getClass();
System.out.println("通过对象获取 : "+class1);
}2.3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常
@Test
public void getClassByAllClass() throws ClassNotFoundException{
Class<?> forName = Class.forName("reflax.Demo");
System.out.println("通过全类型获取 : "+forName);
}注意:
1 直接通过类名.Class的方式得到
Class c = Demo.class;3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常
Class<?> forName = Class.forName("reflax.Demo");3.利用newInstance创建对象:调用的类必须有无参的构造器
public void testNewInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class<?> forName = Class.forName("reflax.Demo");
Object newInstance = forName.newInstance();
System.out.println(newInstance);
}若删除了Demo的无参构造,会出错。
4.ClassLoader类加载器
4.1.获取一个系统的类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("系统类加载器"+systemClassLoader);4.2.获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader))
ClassLoader parent = ClassLoader.getSystemClassLoader().getParent();
System.out.println("扩展类加载器"+parent);4.3、获取扩展类加载器的父类加载器,输出为Null,无法被Java程序直接引用
ClassLoader parent2 = ClassLoader.getSystemClassLoader().getParent().getParent();
System.out.println("启动类加载器"+parent2);4.4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器
ClassLoader classLoader = Class.forName("reflax.Demo").getClassLoader();
System.out.println("当前类由哪个类加载器进行加载-->"+classLoader); 4.5、测试JDK提供的Object类由哪个类加载器负责加载的,输出为Null,无法被Java程序直接引用
ClassLoader classLoader2 = Class.forName("java.lang.Object").getClassLoader();
System.out.println("JDK提供的Object类由哪个类加载器加载-->" + classLoader2); 
5.反射机制通过加载器获取流对象:getResourceAsStream方法
//特别说明: getResourceAsStream(“path”),path的路径和new Demo()的位置有关
//Demo 路径 reflax/Demo.java
//test.properties 路径 reflax/test.properties
InputStream resourceAsStream = new Demo().getClass().getClassLoader().getResourceAsStream("reflax/test.properties");
System.out.println(resourceAsStream);
Properties properties = new Properties();
properties.load(resourceAsStream);
System.out.println("文件内容"+resourceAsStream);
System.out.println(properties.get("name"));
System.out.println(properties.get("age"));6.反射机制获取类中的方法:Method: 对应类中的方法
(1)反射机制获取类中的方法:获取本类方法
6.1 获取方法:默认只能获取public修饰的方法
Class classzz = Class.forName("reflax.MethodDemo");
Method[] methods = classzz.getMethods();6.2 获取方法:所有修饰权限的方法都可以获得
Class classzz = Class.forName("reflax.MethodDemo");
Method[] declaredMethods = classzz.getDeclaredMethods();6.3获取方法:获取指定的方法(所有修饰权限)
Class classzz = Class.forName("reflax.MethodDemo");6.3.1 获取指定方法名的 无参方法
Method declaredMethod = classzz.getDeclaredMethod("method_public");6.3.2 获取指定方法名的 有参方法
Method declaredMethod2 = classzz.getDeclaredMethod("method_public_2", String.class,int.class,char.class);6.4执行方法:
执行方法:invoke(方法对象,方法实际参数)
Object newInstance = classzz.newInstance();6.4.1 执行 无参方法
declaredMethod.invoke(newInstance);6.4.2 执行 有参方法
declaredMethod2.invoke(newInstance, "TEST",122,'r');代码示例:
package reflax;
public class MethodDemo {
/**
Java权限有四个,分别为public,protected,默认,private,其开放程度依次降低
* public可供所有类访问
* protected继承可见
* private只能类本身内部的方法可以访问
*/
public void method_public(){
System.out.println("method_public");
}
public void method_public_2(String name,int age,char sex){//public 带参数
System.out.println("method_public_2");
String info="Demo{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
System.out.println(info);
}
protected void method_protected(){
System.out.println("method_protected");
}
protected void method_protected_2(String info){//protected 带参数
System.out.println("method_protected_2:"+info);
}
void method_default(){
System.out.println("method_default");
}
void method_default_2(String info){//默认修饰符 带参数
System.out.println("method_default_2:"+info);
}
private void method_private(){
System.out.println("method_private");
}
private void method_private_2(String info){//private 带参数
System.out.println("method_private_2:"+info);
}
}测试:
@Test
public void testMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
Class classzz = Class.forName("reflax.MethodDemo");
//1、得到clazz 对应的类中有哪些方法,不能获取private方法
Method[] methods = classzz.getMethods();
for(Method method:methods){
// System.out.println(method.getName());
}
//2、获取所有的方法(且只获取当前类声明的方法,包括private方法)
Method[] declaredMethods = classzz.getDeclaredMethods();
for(Method method :declaredMethods){
System.out.println(method);
}
//3、获取指定的方法
Class<?>... parameterTypes:一个或多个方法参数的类型,注意要一一对应。
//3.1 获取指定方法名的 无参方法
Method declaredMethod = classzz.getDeclaredMethod("method_public");
System.out.println(declaredMethod);
//3.2 获取指定方法名的 有参方法
Method declaredMethod2 = classzz.getDeclaredMethod("method_public_2", String.class,int.class,char.class);
System.out.println(declaredMethod2);
//4、执行方法! 执行方法:invoke(方法对象,方法实际参数)
Object newInstance = classzz.newInstance();
declaredMethod.invoke(newInstance);
declaredMethod2.invoke(newInstance, "TEST",122,'r');
}(2)反射机制获取接口或者父类的方法:
A : Method: 对应基类或接口中的方法
(只可以获取到接口或父类的public方法)
// 反射机制获取类中的方法:Method: 对应基类或接口中的方法
Class forName = Class.forName("reflax.Demo");
Method[] methods = forName.getMethods();
for(Method method:methods){
System.out.println(method);
}
//获取当前类实现的接口中的方法
Method method = forName.getMethod("play_public_2", String.class);
//执行
Demo newInstance = Demo.class.newInstance();
method.invoke(newInstance, "ddddd");B : 通过当前反射对象,拿到父类反射对象
(可以获取到接口或父类的所有方法)
通过子类的反射对象和拿到的父类反射对象,也仅仅只能执行public方法,不能执行private,protected和default默认修饰的方法
Class classzz = Class.forName("reflax.Demo");
//获取父类的class
Class superclasszz = classzz.getSuperclass();
//获取父类方法的public权限方法
Method[] methods = superclasszz.getMethods();
for(Method method : methods){
System.out.println(method);
}
//仅仅获取父类声明的全部方法
Method[] declaredMethods = superclasszz.getDeclaredMethods();
for(Method method : declaredMethods){
System.out.println(method);
}7.反射机制获取类中的字段属性:Field字段
Class classzz = Class.forName("reflax.Demo");
//获取被public修饰的属性
Field[] fields = classzz.getFields();
for(Field field : fields){
System.out.println(field.getName());
}
// 获取Field的数组,私有字段也能获取
Field[] declaredFields = classzz.getDeclaredFields();
for(Field field : declaredFields){
System.out.println(field.getName()+"类型"+field.getType());
}
//获取指定对象的Field的值
Field declaredField = classzz.getDeclaredField("sex");
Demo demo = (Demo) classzz.newInstance();
char object = (char) declaredField.get(demo);
System.out.println(object);
//设置指定对象的Field的值
declaredField.set(demo, 'T');
System.out.println(demo.getSex());
//若该字段是私有的,需要调用setAccessible(true)方法
Field privateField2 = classzz.getDeclaredField("age");
privateField2.setAccessible(true);
privateField2.set(demo, 14);
System.out.println(demo.getAge());
文章标题:Java-reflax 反射
发布时间:2019-11-29, 14:30:08
最后更新:2019-11-29, 14:30:08