Java反射机制
Java反射机制 Java Reflection
reflection被视为动态语言的关键,反射机制允许程序在运行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。
运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。

-
反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取范型信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理
反射机制👇
public class Person{
private String name;
public int age;
//省略getter、setter方法
public Person(String name, int age){
this.name = name;
this.age = age;
}
private Person(String name){
this.name = name;
}
public Person(){
}
public void show(){
System.out.println("I am a person.")
}
private String showNation(String nation){
System.out.println("My nation is " + nation);
retrun nation;
}
}
//如果不使用反射机制,就只能调用上面public的对象和方法
//使用反射机制
public class ReflectionTest{
public void test2() throws Exception {
Class clazz = Person.class;//反射的源头
//Class的实例就对应着一个运行时类
//通过反射,创建Person类的对象
Constructor cons = clazz.getConstructor(String.class, int.class);
Object obj = cons.newInstance("Tom", 12);//newInstance()创建对应的运行时类的对象
System.out.println(obj.toString());
//or
Person p = (Person)obj;
System.out.println(p.toString());
//通过反射,调用对象指定的属性、方法
Field age = clazz.getDeclaredField("age");
age.set(p, 10);
System.out.println(p.toString());
Method show = clazz.getDeclaredMethod("show");
show.invoke(p);
//通过反射,可以调用Person私有结构
//私有构造器
Constructor cons1 = clazz.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person p1 = (Person)cons1.newInstance("Jerry");
System.out.println(p1);
//私有属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(p1, "Lisa");
System.out.println(p1);
//私有方法
Method showNation = clazz.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String nation = showNation.invoke(p1, "China"); //相当于p1.showNation("China");
System.out.println(nation);
}
}
/*
* 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
*
* 1.获取构造方法:
* 1).批量的方法:
* public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
* 2).获取单个的方法,并调用:
* public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
*
* 调用构造方法:
* Constructor-->newInstance(Object... initargs)
*/
/*
* 获取成员变量并调用:
*
* 1.批量的
* 1).Field[] getFields():获取所有的"公有字段"
* 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
* 2.获取单个的:
* 1).public Field getField(String fieldName):获取某个"公有的"字段;
* 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
*
* 设置字段的值:
* Field --> public void set(Object obj,Object value):
* 参数说明:
* 1.obj:要设置的字段所在的对象;
* 2.value:要为字段设置的值;
*
*/
/*
* 获取成员方法并调用:
*
* 1.批量的:
* public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
* public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
* 2.获取单个的:
* public Method getMethod(String name,Class<?>... parameterTypes):
* 参数:
* name : 方法名;
* Class ... : 形参的Class类型对象
* public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
*
* 调用方法:
* Method --> public Object invoke(Object obj,Object... args):
* 参数说明:
* obj : 要调用方法的对象;
* args:调用方式时所传递的实参;
):
*/
//获取Class的实例的方式
public void test(){
//方式一:调用运行时类的属性.class
Class clazz1 = Person.class;
//方式二:调用运行时类的对象getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
//方式三:调用Class的静态方法forName(String classPath) 这种方法用的多
Class clazz3 = Class.forName("com.atguigu.jaca.Person");//路径
//clazz1 clazz2 clazz3 clazz4指向的是同一个对象
//方式四:使用类的加载器ClassLoader 了解即可
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
}
/*
在运行期间,一个类只有一个Class对象产生
*/
-
通过new的方式或反射的方式都可以调用公共的结构,建议用直接new的方式
什么时候用反射的方式:编译的时候确定不下来new哪个对象
反射:动态性
-
反射机制与面向对象中的封装性是不是矛盾的?
封装性是建议你怎么调用的问题
反射是能不能调用的问题
-
在javabean中要求提供一个public的空参构造器,
便于通过反射,创建运行时类的对象
便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器
反射main方法
package fanshe.main;
public class Student{
public static void main(String[] args){
System.out.println("main方法执行了...");
}
}
package fanshe.main;
import java.lang.reflect.Method;
/*
获取Student类的main方法,不是当前的main方法,不要搞混
*/
public class Main{
public static void main(String[] args){
try{
//1.获取Student对象的字节码
Class clazz = Class.forName("fanshe.main.Student");
//2.获取main方法
Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称。第二个参数:方法形参的类型
//3.调用main方法
//methodMain.invoke(null, new String[]{"a","b","c"});
//第一个参数:对象类型,因为方法是static的,所以可以为null。第二个参数new String[]{"a","b","c"}拆成三个对象,所以需要将它强转
methodMain.invoke(null, (Object)new String[]{"a","b","c"});//method 1
//methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//method 2
}catch(Exception e){
e.printStackTrace();
}
}
}

浙公网安备 33010602011771号