静态绑定和动态绑定
绑定指的是被调用的方法的与方法所在实际的类关联起来。
- 动态绑定
在运行时获取所引用对象的实际类型。 最常见的就是多态:父类申明引用子类实例来执行方法;
对于静态方法、所有成员变量,能被子类再次声明,这个叫影藏!
在子类被强制转换成父类后:
- 隐藏:访问的是父类中!
- 多态:访问的还是子类方法!
- 静态绑定
发生在前期编译过程中。只包含:private、 final、 构造函数、 static修饰的方法。
在编译期间,类文件常量池【Constant pool】中的【符号引用】在运行阶段的运行时常量池里,会解析为【直接引用】 。
因为这几个类型的方法无法被重写,运行期保持不变, 其他方法需要在运行时才能真实确认实际方法主体类。
final
简单点:
- 修饰类:类不能被继承。
- 修饰方法:方法不可以被子类覆盖,但是可以重载。
- 修饰变量:对于基本类型变量,不可修改; 对于对象类型变量,指的是引用句柄不能修改(不能让其指向另一个对象),内部属性还是可以修改的。只能赋值1次!
- 修饰的成员变量可以在构造器、非静态初始化块、声明时赋值
- 修饰的类变量在静态初始化块、申明时赋值
-
修饰局部变量必须显示初始化!
- 重写:@Override 方法名、入参、返回值都一样。 遵循原则: 父类能出现的地方,子类一定可以出现。 权限不能小于父类,抛出的检测异常不能大于父类
- 重载:方法名一样,方法入参一定不样。
复杂点:
每一个方法的调用开始到执行结束的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的。因此频繁的函数调用会造成性能大量消耗。
在JVM运行期间的编译优化JIT过程里,会考虑内联final方法来提升执行效能。方法内联就是把被调用的函数代码"复制"到调用方函数中!以空间换时间,占用更多的内存,所以JVM更偏好更小的方法。
JVM会自动的识别热点方法,并对它们使用方法内联优化。但是一个方法就算被JVM标注成为热点方法,JVM仍然不一定会对它做方法内联优化。比较常见的原因就是这个方法体太大了,分为两种情况。
- 如果方法是经常执行的,默认情况下,方法大小小于325字节的都会进行内联(可以通过 -XX:MaxFreqInlineSize=N 来设置这个大小)
- 如果方法不是经常执行的,默认情况下,方法大小小于35字节才会进行内联(可以通过-XX:MaxInlineSize=N 来设置这个大小)
想要对热点的方法使用上内联优化,最好尽量使用final、private、static修饰方法,避免方法因为继承,导致需要额外的类型检查,这将导致JIT对一个方法内联却达不到理想的提升效果。