文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。
相关文章:
文章目录:
1.反射的概念
在java中,只要提供类名,就可以通过反射机制来获取类的所有信息。
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接,但是反射使用不当会降低程序的效率。
2.反射的作用
2.1 在运行时判断任意一个对象所属的类;
2.2 在运行时获取类的对象;
2.3 在运行时访问java对象的属性,方法,构造方法等。
3.反射机制的优点与缺点
缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。
优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
4.反射的例子:
4.1 一个被反射的Student的bean:
package testreflect;
import java.util.Date;
/**
*类描述:student的bean
*@author: 张宇
*@date: 日期: 2018年8月30日 时间: 上午11:13:42
*/
public class Student {
private String studentID;
private String studentName;
private Date birthday;
private int score;
public String getStudentID() {
return studentID;
}
public void setStudentID(String studentID) {
this.studentID = studentID;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public void finishTask(String taskName) {
System.out.println(this.studentName + "完成了"+taskName);
}
}
4.2 反射的例子:
package testreflect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
*类描述: 反射得到student的bean中的对象,属性,方法
*@author: 张宇
*@date: 日期: 2018年8月30日 时间: 下午2:09:03
*/
public class ReflectTest {
public static void main(String[] args) {
try {
// 获取类的字节码文件:包名+类名
Class<?> clazz = Class.forName("testreflect.Student");
// 通过类的字节码文件获取所有字段名的数组
Field[] fields = clazz.getDeclaredFields();
// 遍历fileds数组,并打印出来它的字段,修饰符,类型,属性名
for(Field field:fields){
System.out.println(field);
System.out.println("修饰符:"+Modifier.toString(field.getModifiers()));
System.out.println("类型:"+field.getType());
System.out.println("属性名:"+field.getName());
System.out.println("----------------------------------------------");
}
// 获取该类的所有方法,其中getDeclaredMethods是强制获取,不管是共有的还是私有的方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
System.out.println("修饰符:"+ Modifier.toString(method.getModifiers()));
System.out.println("方法名:" + method.getName());
System.out.println("返回类型:" + method.getReturnType());
System.out.println("---------------------------------");
// 获取方法的参数对象
Class<?>[] clazzes = method.getParameterTypes();
for (Class<?> class1 : clazzes) {
System.out.println("参数类型:" + class1);
System.out.println("参数名:"+class1.getName());
}
}
// 通过class对象创建实例
Student student = (Student) clazz.newInstance();
// Field studentName=clazz.getField("studentName");
Field studentName = clazz.getDeclaredField("studentName");
// 如果是获取单个私有方法,要用到setAccessible
studentName.setAccessible(true);
studentName.set(student, "张三");
// 通过class对象获取名为finishtask方法
Method finishTask = clazz.getDeclaredMethod("finishTask", String.class);
finishTask.setAccessible(true);
// 调用finishTask方法
finishTask.invoke(student, "数学");
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.java中有三种类加载器。
5.1 Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
5.2 Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
5.3 AppClassLoader 加载classpath指定的类,最常用的加载器,同时也是java中默认的加载器。
6.类的生命周期
在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM;在程序执行中JVM通过装载,链接,初始化这3个步骤完成。
类的装载是通过类加载器完成的,加载器将.class的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象,用来封装数据; 但是同一个类只会被类装载器装载以前链接就是把二进制数据组装为可以运行的状态。
链接分为校验,准备,解析这3个阶段:
校验 :一般用来确认此二进制文件是否适合当前的JVM(版本);
准备 :为静态成员分配内存空间,并设置默认值;
解析 :指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系);
类型完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收,释放空间。当没有任何引用指向Class对象时就会被卸载,结束类的生命周期。