java的编译期和运行期
参考博文:
https://blog.csdn.net/zl1zl2zl3/article/details/107425987
首先我觉得应该了解一下java中的编译期和运行期的概念。
一张图片:
- 一个.java文件完成运行需要经过哪些步骤?
(1)Java源码–>java字节码
(2)加载java字节码并运行
- 编译期间做些什么?
编译器的作用:源代码(原始语言)–> 目标语言
(1)解析与填充符号表:通过词法语法分析,填充符号表。
(2)注解处理器:当我们处理注解时,如果修改了语法树的话,会重新执行分析以及符号填充过程,把注解也填充进来,直到处理完所有的注解。
(3)语义分析:编译器获得语法树之后,无法确定源程序是符合逻辑的。
(4)解语法糖:虚拟机不支持java中的语法糖,他们在编译阶段就被还原成了简单的基础语法结构。
(5)字节码生成:主要工作就是把语法树和符号表加工成字节码文件。
- 运行期间做些什么?
java运行期间主要是处理编译器产生的字节码,包括加载与执行。
-
java程序是如何运行的?
首先需要把源代码(高级语言)编译成虚拟机可执行的语言(字节码),其次,需要把字节码解释运行后编译成操作系统级别的机器语言,用于执行函数调用。
另外,java语言是平台独立的,但是虚拟机不是。每个操作系统都要下载对应的虚拟机,主要是由于它最终调用的函数库以及线程模型不同。
什么是反射?
反射是一种间接操纵目标对象机制。前提是java程序在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。
反射就是把java类中的各种成分映射成相应的java类,然后进行调用。
反射原理是什么?
在JVM(java虚拟机,通过jvm,获得字节码,java语言在不同平台运行时不需要重新编译。)运行时才会动态的加载类,但是我们有时候在编译期不知道运行的对象是谁,编译成.class文件之后。通过反射,运行中的java程序也可以获取类的信息,并且可以操作类或对象的内部属性,它是在运行时根据需要才加载。
java反射就是当程序运行时,在内存中获得.class对象之后,反向获取该class对象的类的属性和方法等各种信息。
从面向对象的角度来看,我们平时用到的“类”,“构造器”,“属性”,“方法”其实也是一个“类”,它们在jdk中分别对应Class、Constructor、Field、Method类。其中Class相当于“类的类”,可称为“元类”,从这个角度看,我们平时自定义的“类”可以理解为Class的一个对象。
反射有哪些好处?
反射允许静态语言在运行时检查、修改程序的结构和行为。在静态语言中,使用一个变量,必须知道它的类型。换句话说就是,程序在运行时的行为都是固定的。如果想在运行时改变,就需要反射来解决。
“无反射,不框架;无代理,不框架”。反射是框架设计的灵魂。
反射广泛应用于那些需要在运行时检测或修改程序行为的程序中。
当我们想要输入一个对象和类,并想调用它的属性和方法时,一按点号,编译器就会自动列出它的属性和方法。这里用到的就是反射。
反射怎么用?
功能:
-
在运行时判断任意一个对象所属的类。
-
在运行时构造任意一个类的对象。
-
在运行时判断任意一个类所具有的成员变量和方法。
-
在运行时调用任意一个对象的方法。
-
生成动态代理。
获取Class的三种方法:
Student stu1 = new Student();
(1)Object --> getClass
Class stuClass = stu1.getClass();
(2)任何数据类型(包括基本的数据类型)都有一个”静态“的class属性。
Class stuClass2 = Student.class
(3)通过class类的静态方法:forName(String className)
Class stuClass3 = Class.forName("Stu.Student")//此路径是真实地路径
注意: 在运行期间,一个类只有一个Class对象产生。
通过反射获取构造方法并使用:
Class clazz = Class.forName("Stu.Student"); Constructor[] conArray = clazz.getConstructors(); //所有公有地构造方法。
conArray = clazz.getDeclaredConstructors(); //所有的构造方法。
Constructor con = clazz.getConstructor(null); //获取公有并且无参的构造方法。
con = clazz.getDeclaredConstructor(char.class); //获取私有的构造方法,并调用。
获取成员变量并调用:
Field[] fieldArray = stuClass.getFields(); //获取所有公有地字段
fieldArray = stuClass.getDeclaredFields();
//获取所有的字段
Field f = stuClass.getField("name")
//获取公有字段并调用
f = stuClass.getDeclaredField("phoneNum")
//获取私有字段并调用
获取成员方法并调用:
Method[] methodArray = stuClass.getMethods();
//获取所有公有地方法
methodArray = stuClass.getDeclaredMethods();
//获取所有的方法,包括私有的
Method m = stuClass.getMethod("show1",String.class);
//获取公有的show1()方法
m = stuClass.getDeclaredMethod("show4",int.class);
//获取私有的show4()方法
反射main方法:
Class clazz = Class.forName("fanshe.main.Student");
Method methodMain = clazz.getMethod("main",String[].class);
methodMain.invoke(null,(object)new String[]{"a","b","c"})
反射方法的其他使用之—通过反射运行配置文件内容:
public static String getValue(String key) throws IOException{
Properties pro = new Properties();
FileReader in = new FileReader("pro.txt");
pro.load(in);
in.close();
return pro.getProperty(key);
}//此方法接收一个key,在配置文件中获取相应的value
反射方法的其他使用之—通过反射越过泛型检查:
泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的。
静态代理和动态代理的区别
使用代理的目的是:对目标对象(的方法)进行功能增强。
既然是对目标对象的方法进行增强,代理对象的方法中一定会调用目标对象的方法。而且一般会在目标对象的方法调用前后(或者其他时机)做一些其他的处理以达到增强的效果。
什么是静态代理?
代理类和实现类实现同一个接口,代理类里面有一个实现类的引用,客户调用代理类的方法时,代理类就调用实现类的方法。称为静态,是因为代理类和实现类是写死的,就是在编译阶段就确定了。
静态方法可以在代理类调用实现类的方法前后加上一些代码;在构造方法中也可以通过网络加载器加载到别的机器上的类,这样本地调用时,感觉不到远程机器,就像调用本地代码一样。
静态代理的缺点
如果有很多类需要代理,就要写很多的代理类,就比较麻烦。
动态代理的本质是什么?
动态代理的本质就是用户提供类名、方法名、参数、代理类执行方法,返回结果。用类加载器可以将类加载到虚拟机,用Class clazz表示,有这个对象,就可以执行它的方法。(这就是反射)
动态代理的使用?
Proxy实现类是由Proxy的static方法在执行时刻生成的,这个类和被代理类有相同的接口,并且它的构造函数的参数是InvocationHandler。因为这个类是在运行时刻生成的,可以根据传入不同的参数,生成不同的代理类,所以是动态代理。
动态代理类不是由程序员写的,而是根据传入的参数,由Proxy类在运行时生成的,所以可以传入不同的参数,这样就可以在运行时产生不同的代理类,所以是动态的。
Foo f = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[]{Foo.class}, handler);
动态代理的内涵?
java动态代理类位于Java.lang.reflect包下,一般涉及到以下的两个类:
(1)Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method,Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2)Proxy:该类即为动态代理类,主要包含以下内容:Protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。
Static Class getProxyClass(ClassLoader loader,Class[] interfaces):获得一个代理类,其中loader是类装载器,interface是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader,Class[] interface, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
参考博文
https://blog.csdn.net/yangwu007/article/details/109116421
https://blog.csdn.net/ju_362204801/article/details/90578678
https://fxnfk.blog.csdn.net/article/details/78905997
https://blog.csdn.net/he90227/article/details/39155613
https://blog.csdn.net/sinat_38259539/article/details/71799078
https://blog.csdn.net/he90227/article/details/39155613
https://cloud.tencent.com/developer/article/1561114