0
点赞
收藏
分享

微信扫一扫

反射知识梳理


文章目录

  • ​​笔记​​
  • ​​代码:​​
  • ​​反射​​
  • ​​1.根据包名如何获取包下的类的信息并能调用类的信息?​​
  • ​​2.反射有什么好处,并举例说明​​
  • ​​3.获取字节码对象的三种方式​​
  • ​​4.反射获取实例对象的两种方式​​
  • ​​5.获取Class中的字段​​
  • ​​6.获取class中的方法​​
  • ​​7.反射调用类,增强扩展性的例子​​

笔记

  • 码云上的笔记
    ​​https://gitee.com/hufanglei/study/raw/master/%E5%8F%8D%E5%B0%84%E7%AC%94%E8%AE%B0/%E5%8F%8D%E5%B0%84.pdf​​
  • 腾讯文档上的笔记
    ​​https://docs.qq.com/pdf/DWklmY0xUUmh2WUxu​​

代码:

​​https://gitee.com/hufanglei/study/tree/master/code/reflect-demo​​

反射

1.根据包名如何获取包下的类的信息并能调用类的信息?

Q: 原理根据文件夹路径获取路径下的文件。

具体操作:

  • 将包名的​​.​​替换成​​/​​,得到文件路径
  • 获取文件路径下的类的名称
  • 根据名称+​​.class​​得到Class对象
  • 根据该类的Class对象获取类的内部信息,然后调用方法,成员变量等。

2.反射有什么好处,并举例说明

Q: new Object获取对象是静态编译,反射是动态编译。反射提高了程序的扩展性。new对象调用的前提(编译需要)是必须内存有这个对象(.class字节码),反射是根据​​.class​​字节码文件生成对象,并调用。才可以调用,反射可以没有这个对象甚至没有class文件,用的时候再根据class文件名去查找class文件强制加载这个对象并调用。比较灵活。

我们封装框架的时候,如tomcat并不知道你写了多少个servlet,但是他可以吧你的servlet在程序启动的时候给调用,为啥呢?因为我们可以根据web.xml或者注解方式把文件的包名,类名等给了tomcat,tomcat启动的时候,扫描这些配置,然后加载到内存中就可以使用了。

我们只要关注注解或web.xml对应的类信息(通常是包名+类名),用反射方式获取的信息就可以了。这就是反射扩展性的一个例子。

3.获取字节码对象的三种方式

public static void main(String[] args) throws ClassNotFoundException {
// test1();
// test2();
test3();
}

/**
* 方式3
* 包名 class
* 只要通过给定的类的 字符串名称就可获取该类,更为扩展
* 可是用class类中的方法完成, 该方法就是forName
*/
private static void test3() throws ClassNotFoundException {
Class<?> classz = Class.forName("com.example.reflect.bean.Person");
System.out.println(classz);
Class<?> classz2 = Class.forName("com.example.reflect.bean.Person");
System.out.println(classz2);
System.out.println(classz == classz2);
}

/**
* 方式2:
* 类名.class
* 任何数据类型都具备一个静态的属性,class类来获取其对应的class对象
* 相对简单,但是还是要明确用到类中的静态成员
* 还是不够扩展
*/
private static void test2() {
Class<?> classz = Person.class;
System.out.println(classz);
Class<?> classz2 = Person.class;
System.out.println(classz2);
System.out.println(classz==classz2);
}

/**
* 方式1:
* getClass()
* Object类中的getClass()方法。
* 这种方式,必须要明确具体的类并创建对象,麻烦
*/
private static void test1() {
Person person = new Person();
Class<?> classz = person.getClass();
System.out.println(classz);
Class<?> classz2 = person.getClass();
System.out.println(classz2);
System.out.println(classz == classz2);
}

4.反射获取实例对象的两种方式

早期: new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存
并创建该字节码文件对象,并接着创建该字节码文件的对应的Person对象。
现在,找寻该名称类文件,并加载进内存,并产生class对象,通过下面产生类的对象

  • 第一种: 通过Class对象的newInstance方法,只能获取无参数的构造函数的实例
  • 第二种:根据Class的属性Construct对象的newIntance(…)方法,获取有参数的构造函数,并实例化

/**
* 第二种方式: 根据Construcat对象的newInstance方法获取对象
* 当获取指定名称对应类中的
*
* 当获取指定名称对应类中的所体现的对象时,而改对象初始化不适用空参构造该怎么办?
* 既然是通过指定的构造函数进行对象的初始化
* 所以应该先获取到该构造函数,通过字节码文件对象即可完成
* 该方法是: getConstructor(paramterTypes)
*/
private static void createObect2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
String name = "com.example.reflect.bean.Person";
Class<?> clazz = Class.forName(name);
Constructor<?> constructor = clazz.getConstructor( String.class, int.class);
Person p = (Person) constructor.newInstance("小强",18);
p.show();
}

//第一种方式
//获取无参的是实例对象
private static void createObect1() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
String name = "com.example.reflect.bean.Person";
Class<?> clazz = Class.forName(name);
Object o = clazz.newInstance();
Person p = (Person) o;
p.show();
}

5.获取Class中的字段

Class类获取字段有4个方法:

演示一个获取可以获取私有字段的单个字段的方法:getDeclaredFiled(String name)

private static void getFieldDemo() throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<?> clazz = Class.forName("com.example.reflect.bean.Person");
Field field = clazz.getDeclaredField("age");
//对私有字段的访问取消权限检查,暴力访问
field.setAccessible(true);
Object object = clazz.newInstance();
//设置值
field.set(object, 19);
Object o = field.get(object);
System.out.println(o);
}

6.获取class中的方法

无参的方法的调用

private static void getMethodDemo() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> clazz = Class.forName("com.example.reflect.bean.Person");
Method[] methods = clazz.getMethods(); //获取的都是公有的方法
for (Method method : methods) {
System.out.println(method.getName());
}
System.out.println("-----------------------");
//只拿本类中的包括私有的
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method.getName());
}
System.out.println("-----------------------");
//获取空参数一般方法
Method method = clazz.getMethod("show", null);
//Object object = clazz.newInstance();
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
Object o = constructor.newInstance("小王", 25);
method.invoke(o, null);
}

有参数的方法的调用

private static void getMethodDemo1() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<?> clazz = Class.forName("com.example.reflect.bean.Person");

//获取空参数一般方法
Method method = clazz.getMethod("paramMethod", String.class, int.class);
Object object = clazz.newInstance();
method.invoke(object, "小强", 23);
}

7.反射调用类,增强扩展性的例子

public interface PCI {
void open();
void close();
}

public class SoundPCI implements PCI {
@Override
public void open() {
System.out.println("SoundP open");
}
@Override
public void close() {
System.out.println("SoundP close");
}
}

public class NetCard implements PCI{
@Override
public void open() {
System.out.println("NetCard open");
}

@Override
public void close() {
System.out.println("NetCard close");
}
}

public class Mainboard {
public void run() {
System.out.println("main board run....");
}
public void userPCI(PCI p) {
if (p != null) {
p.open();
p.close();
}
}
}

public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
Mainboard mainboard = new Mainboard();
mainboard.run();
// mainboard.userPCI(new SoundPCI());
//通过反射调用pci
usePCI(mainboard);
}

private static void usePCI(Mainboard mainboard) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
// File file = new File("pci.properties");
Properties props = new Properties();
InputStream in = ReflectTest.class.getClassLoader().getResourceAsStream("pci.properties");
props.load(in);
for (int i = 0; i < props.size(); i++) {
String pciName = props.getProperty("pci" + (i + 1));
Class clazz = Class.forName(pciName);
PCI p = (PCI) clazz.newInstance();
mainboard.userPCI(p);
}
}
}


举报

相关推荐

0 条评论