前言
|ू・ω・` )
哟,大家好啊,这一章节是对反射的一些补充和加深。
如果有兴趣可以去看看反射【一】
对了,本章节我采用了一些博客主的图片啊,之类的,
还有一个博主的我感觉挺不错的,可以看看
虽然是全文字
链接:https://blog.csdn.net/u010325193/article/details/80865672
反射的概念
JAVA反射机制是在运行状态中:
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
啦啦,因为你在实列化的时候是在创建一个class文件,那么是咋样创建的呢?
为什么要反射呢?
大家可以参考一下,不懂也没事,下次我会做个章节的。
注意:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
反射之获取Class对象
1、获取Class对象的三种方式
- Object ——> getClass();
- 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
- 通过Class类的静态方法:forName(String className)(常用)
第一种:
//Object ——> getClass();
Student stu = new Student();
Class clz = stu.getClass();
第二种
//任何数据类型(包括基本数据类型)都有一个“静态”的class属性
Class clz = Student.class
第三种:
//通过Class类的静态方法:forName(String className)(常用)
Class clz = Class.forName("com.reflect.demo.student");
ok,先了解了解,后再继续我们的反射之路
反射之动态main方法
反射也是可以调用main方法的哦,在上面一章里,反射是可以调用方法的,所以,那么不可以调用main方法吗?
首先,我们创建一个Student类
public class Student {
public static void main(String[] args) {
System.out.println("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方法
//第一个参数,对象类型,因为方法是static静态的,
//这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
} catch (Exception e) {
e.printStackTrace();
}
}
}
图片详解
然后运行结果:“main方法执行了”
反射之运行配置文件
对于暂时还不太了解反射的伙计们,其实在一个地方,我们的反射就得到了很大的体现:
那就是util包的DBHelper类,连接eclipse和数据库的类。
咱们只需在配置文件中修改就不需要去改类.
所以我就拿现成的来讲:
public class DBAccess {
private static String driver;
private static String url;
private static String user;
private static String password;
static {// 静态块执行一次,加载 驱动一次
try {
InputStream is = DBAccess.class.getResourceAsStream("config.properties");//获取输入流(在config.properties中)
Properties properties = new Properties();//获取配置文件的对象
properties.load(is);//将流加载到配置文件对象中
driver = properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("pwd");
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
在配置文件中,也就是config.properties这个静态资源文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db_0529?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
user=root
pwd=123
这样就可以了,那有人就说了不就是XML解析中的吗
其实也可以调用方法的
比如:
配置文件:
className = com.fanshe.Student
methodName = show
调用:
InputStream is = DBAccess.class.getResourceAsStream("config.properties");//获取输入流
Properties properties = new Properties();//获取配置文件的对象
properties.load(is);//将流加载到配置文件对象中
className = properties.getProperty("className");
methodName= properties.getProperty("methodName");
//通过反射获取Class对象
Class stuClass = Class.forName(className);//"cn.fanshe.Student"
//2获取show()方法
Method m = stuClass.getMethod(methodName);//show
//3.调用show()方法
m.invoke(stuClass.getConstructor().newInstance());
public class Student {
public void show(){
System.out.println("is show()");
}
}
反射之越过泛型检查
我感觉这个挺好玩的哦,可以在泛型的编码过程,越过去。
泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的
public static void main(String[] args) throws Exception{
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(strList, 100); //可以加入int的类型了
//遍历集合
for(Object obj : strList){
System.out.println(obj);
}
}
大家知道这个能干嘛吗,就算你定死了泛型类型,你还是可以去反调用add方法使得变为Object类型哦!!!
总结
理解并不难,难在怎么去灵活运用
Thanks♪(・ω・)ノ希望大家能用来参考