< 笔记 > Java SE - 09 Java SE 反射
程序员文章站
2022-06-09 20:43:53
...
09 Java SE 反射
By Kevin Song
定义:反射机制是在运行状态中,对于任意一个类(class文件),都能知道这个类的所有方法和属性。对于任意一个对象都能调用它的任意一个方法和属性。
Tomcat例
- Tomcat App提供 Servlet接口
- MyServlet类实现Servlet接口
- 编写MyServlet类配置文件
- Tomcat直接读取配置文件来动态获取MyServlet类中的方法和属性
- Tomcat通过Class类来获取MyServlet类字节码文件中的内容(想要对MyServlet文件进行内容获取,第一步要获取该类的字节码文件对象即可)
- 获取Class类中的对象(字节码文件对象)
- Tomcat通过Class类中的forName()方法获取MyServlet类字节码文件对象
- 获取Class类中的构造方法
- 通过newInstance()获取该类空构造方法对象
- 通过getConstructor获取构造方法对象
- 再通过构造方法对象newInstance();方法来创建非空参对象
- 获取Class类中的字段
- 获取Class类中的方法
- 获取Class类中的对象(字节码文件对象)
- Tomcat通过Class类来获取MyServlet类字节码文件中的内容(想要对MyServlet文件进行内容获取,第一步要获取该类的字节码文件对象即可)
class Person {
name;
age;
}
Person p1 = new Person(Leo, 20);
Person P2 = new Person(Kylo, 28);
//描述字节码文件的类
class Class {
提供可以获取字节码文件的内容(字段,构造方法,一般方法)
}
class Demo {
int a = 6;
Demo() {}
void show() {}
}
class Test {
int b = 9;
Test() {}
void abc() {}
}
获取Class对象
三种方式
- 方式三:Object类中的getClass()方法
- 必须明确具体的类并且创建对象
- 方式二:任何数据类型都具备一个静态的属性.class来获取其对应的class对象
- 要明确类中的静态成员
- 方式三:通过给定的类的字符串名称就可以获取该类
- Class类中的forName()方法
public class ReflectDemo {
public static void main(String[] args) {
//方式一:Object类中的getClass()方法
public static void getClassObject_1() {
Person p = new Person();
Class clazz = p.getClass();
Person p1 = ne Person();
Class clazz1 = p1.getClass();
System.out.println(clazz==clazz1);//true
}
//方式二
public static void getClassObject_2() {
Class clazz = Person.class;
Class clazz1 = Person.class;
System.out.println(clazz==clazz1);//true
}
//方式三
public static void getClassObject_3() throws ClassNotFoundException {
String className ="Person";
Class class = Class.forName(className);
System.out.println(clazz);
}
}
}
public class Person {
private int age;
private String name;
public Person(int age, String name) {
super();
this.age = age;
this.name = name;
System.out.println(personParam run"");
}
public Person() {
super;
System.out.println(person run"");
}
public void show() {
System.out.println(name+"..."+age);
}
private void method() {
System.out.println("method run");
}
public void paraMethod(String str, int num) {
System.out.println("paramMethod run"+str+":"+num);
}
public static void staticMethod() {
System.out.println("staticMethod run");
}
}
获取Class中的构造方法
- 早期创建对象
- new的时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内创建该字节码文件对象,然后创建该字节文件的对应Person对象
- 反射创建对象
- 只要知道类名,通过Class来创建该类字节码文件对象
- 通过newInstance()获取该类空构造方法对象
- 通过getConstructor获取构造方法对象
- 再通过构造方法对象newInstance();方法来创建非空参对象
- 只要知道类名,通过Class来创建该类字节码文件对象
public class ReflectDemo2 {
public static void main(String[] args) {
createNewObject_1();
createNewObject_2();
}
//空参数构造方法
public static void createNewObject_1() {
//以前
Person p = new Person();
//反射
String name = "Person";
Class clazz = Clazz.forName(name);//获取Person类字节码文件对象
Object obj = clazz.newInstance();//产生Person类对象
}
//非空参数构造方法
public static void createNewObject_2() {
String name = "Person";
Class clazz = Clazz.forName(name);//获取Person类字节码文件对象
//获取指定构造函数的对象
Constructor constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("Kylo", 29);
}
}
获取Class中的字段
public class ReflectDemo3 {
public static void main(String[] args) {
createNewObject_1();
createNewObject_2();
}
//空参数构造方法
public static void getFieldDemo() {
Class clazz = Class.forName("Person");
Field field = clazz.getField("age");//获取公有的
field = clazz.getDeclaredField("age");//获取本类,包含私有
//对私有字段的访问取消权限检查,强制访问
field.setAccessible(true);
Object obj = clazz.newInstance();
field.set(obj,20);
Object o = field.get(obj);
System.out.println(o);
}
}
获取Class中的方法
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
getMethodDemo_3();
}
//获取有参方法
public static void getMethodDemo_3() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("paramMethod", String.class,int.class);
Object obj = clazz.newInstance();
method.invoke(obj, "小强",89);
}
//获取无参方法
public static void getMethodDemo_2() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("show", null);//获取空参数一般方法。
//Object obj = clazz.newInstance();
Constructor constructor = clazz.getConstructor(String.class,int.class);
Object obj = constructor.newInstance("小明",37);
method.invoke(obj, null);
}
//获取指定Class中的所有公共方法
public static void getMethodDemo() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method[] methods = clazz.getMethods();//获取的都是公有的方法。
methods = clazz.getDeclaredMethods();//只获取本类中所有方法,包含私有。
for(Method method : methods){
System.out.println(method);
}
}
}
反射练习
public class Mainboard {
public void run() {
System.out.println("main board run....");
}
public void usePCI(PCI p) {//PCI p = new SouncCard();
if (p != null) {
p.open();
p.close();
}
}
}
public class SoundCard implements PCI {
public void open(){
System.out.println("sound open");
}
public void close(){
System.out.println("sound close");
}
}
public class NetCard implements PCI {
@Override
public void open() {
System.out.println("net open");
}
@Override
public void close() {
System.out.println("net close");
}
}
public interface PCI {
public void open();
public void close();
}
/*
* 电脑运行。
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
Mainboard mb = new Mainboard();
mb.run();
//每次添加一个设备都需要修改代码传递一个新创建的对象
//mb.usePCI(new SoundCard());
//能不能不修改代码就可以完成这个动作。
//不用new来完成,而是只获取其class文件。在内部实现创建对象的动作。
File configFile = new File("pci.properties");
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(configFile);
prop.load(fis);
for(int x=0; x<prop.size(); x++){
String pciName = prop.getProperty("pci"+(x+1));
Class clazz = Class.forName(pciName);//用Class去加载这个pci子类。
PCI p = (PCI)clazz.newInstance();
mb.usePCI(p);
}
fis.close();
}
}
pci.properties文件
pci1=cn.itcast.reflect.test.SoundCard
pci2=cn.itcast.reflect.test.NetCard