文章目录
javaAPI
命名
J2ME/JavaMe(Java2 Micro Edition,Java2平台的微型版),应用于移动、无线及有限资源的环境;J2SE/JavaSE(Java 2 Standard Edition,Java 2平台的标准版),应用于桌面环境;J2EE/JavaEE(Java 2Enterprise Edition,Java 2平台的企业版),应用于基于Java的应用服务器。
Java1.6发布后进行更名:J2ME-JavaMe,J2SE-JavaSE,2EE-JavaEE
jdk 8u191-b12 : jdk 8,update191 ,branch12。
jdk 10.0.2+13 : jdk 10 ,子版本10.0.2 , branch 13。
jdk jdk1.8.0_171 : jdk8,子版本1.8.0, update 171
JDK
Java Development Kit ,java开发工具包,是面向程序员使用java语言编写java程序所需的开发工具包。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm,hotspot debugger等工具软件,还包含了java程序编写所需的文档和demo例子程序。
JRE
Java Runtime Environment,java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境。
openJDK
为开源的Jdk版本,可以下载openJDK源码自己编译成JDK,可以更好的学习hotspot等底层的代码运行情况(通过debug hotspot,native方法等源码)。
java版本
jdk-8u181-linux-arm32-vfp-hflt.tar.gz
jdk-8u181-linux-x64.rpm
jdk-8u181-windows-x64.exe
java特征
java语言的特征
- 封装(面向对象,数据抽象)
- 继承
- 多态
java程序的特征
- 跨平台
注意:Java语言是跨平台的,但JVM不是跨平台的
关键字
重载,重写(复写,覆盖)
方法签名:方法名 + 参数列表 来确定唯一方法。
重写(override):
- 重写就是子类重写父类的方法
- 方法名,参数列表(类型,顺序)和返回值都必须相同
- 权限修饰符不能小于被重写方法的修饰符(父类protected,子类> protected)
- 方法不能抛出新的异常或者是比被重写方法声明更加宽泛的检查型异常
重载(overload):
- 重载就是同一个类中
- 多个方法名相同,但参数列表不同(包括参数个数和参数一一对应后参数类型),与返回值,权限修饰符,异常无关
class Supper{
// 编译报错,参数列表+get方法名相同,为同一个方法没有重载
// List<Integer>和List<String>同一个类型,泛型擦除
void get(List<Integer> list){
}
int get(List<String> list) {
return 1;
}
}
class Supper{
// 重载
protected void get(List<Integer> list){
}
int get(List<Integer> list, Integer i){
return 1;
}
int get(Integer i, List<Integer> list){
return 2;
}
}
多态
多态也叫动态绑定/后期绑定/运行时绑定,对立的概念静态绑定/前期绑定/编译器绑定。基于RTTI(运行时类型识别)实现。
增强了java语言的可拓展性。基于多态的面向接口编程成为java代码设计的重要原则之一。
类中各种抽象元素的绑定类型
类型 | 绑定类型 | 解释 |
---|---|---|
static方法 | 编译期绑定 | |
域 | 编译期绑定 | 任何域访问操作都将由编译器解析,域访问不是多态的 |
private方法 | 编译期绑定 | private方法也属于final方法 |
final方法 | 编译期绑定 | final告诉编译器“关闭”动态绑定,不需要对方法进行动态绑定 |
除static/final/private的方法 | 运行时绑定 | 每一个对象实例的“mark word”中都会存放对象的实际类型信息,JVM执行子系统(识别invokevisual等字节码命令)能找到正确的方法并调用 |
构造函数 | 编译期绑定 | 构造器不具多态性(它们实际上时static方法,只不过该static声明时隐式的) |
RTTI:
class Shape {
void draw() {
System.out.println(this + ".draw()");}
abstract String toString();
}
class Circle extends Shape {
String toString() {
return "Circle";}
}
class Square extends Shape {
String toString() {
return "Circle";}
}
public static void main(String[] args){
List<Shape> shapelist = Arrays.asList(new Circle(), new Square());
for(Shape shape : shapeList){
shape.draw();
}
}
// output
Circle draw()
Square draw()
public class Supper{
int num = 2;
String get(){
return "supper";
}
// static方法,静态绑定
static String show(){
return "supper show";
}
// final方法,不会被复写,不会进行动态绑定
final String fgo(){
return "supper go";
}
}
public class Sun extends Supper{
int num = 3;
String get(){
return "sun";
}
static String show(){
return "sun show";
}
//编译报错,父类为final方法,此方法拒绝override重载
//String go(){
//return "sub go";
//}
public static void main(String[] args){
Supper supper = new Sun();
System.out.println(supper.num);
System.out.println(supper.get());
System.out.println(supper.show());
System.out.println(supper.fgo());
}
}
## 结果
2
sun
supper show
supper go
进阶:基于字节码和JVM理解多态
虚分派:JVM为了实现多态指定的规则,首先从被调用方法对象的类的实现中查找对应的方法,如果没有找到,则去父类查找,直到找到函数并实现调用。虚分派不管引用类型,只查找引用指向的对象的类型
虚分派在JVM中的实现:vtable(visual table虚表)来实现虚分派的规则。在JMM的方法区中,每一个类都维护一个方法表,该方法表记录每一个方法代码的索引(偏移量)。创建并生成方法表时,JVM会先扫描父类,然后子类,同样的方法(签名相同:名称,参数)会被子类的索引覆盖。
JVM规定在遇到invokevirtual,invokeinterface指令时,就需要遵循虚分派规则,invokestatic指令不遵循虚分派规则,以引用类型代表的类的方法表作为方法代码查找的索引表
上述代码的字节码片段
静态常量池:
#7 = Methodref #20.#58 // com/study/memery/Supper.get:()Ljava/lang/String;
#9 = Methodref #20.#61 // com/study/memery/Supper.show:()Ljava/lang/String;
#10 = Methodref #20.#62 // com/study/memery/Supper.fgo:()Ljava/lang/String;
运行时常量池:
supper.get()
12: invokevirtual #7 // Method get:()Ljava/lang/String;
supper.show()
23: invokestatic #9 // Method show:()Ljava/lang/String;
supper.fgo()
33: invokevirtual #10 // Method fgo:()Ljava/lang/String;
JVM将直接调用,间接调用抽象成4个指令:
指令 | 解释 | 是否跟多态有关 |
---|---|---|
invokevirtual | 用于方法调用,调用public,protected修饰且不被static,final修饰的方法 | 有关 |
invokeinterface | 跟invokevirtual差不多,如果父类引用是接口,就用这个;父类引用是类就用invokevirtual | 有关 |
invokespecial | 用于调用私用方法、构造函数 | 无关 |
invokestatic | 用于静态方法调用 | 无关 |
访问权限控制
public/private/protected/default
修饰符可以修饰类,构造函数,成员变量,方法
访问权限 | 含义 | 本类 | 本包的类 | 非本包子类 | 非本包非子类 |
---|---|---|---|---|---|
public | 公共的 | 是 | 是 | 是 | 是 |
protected | 保护访问权限 | 是 | 是 | 是 | 否 |
default | 包访问权限 | 是 | 是 | 否 | 否 |
private | 私有的 | 是 | 否 | 否 | 否 |
访问权限:public > protected > package > private
defualt : 包访问权限、friendly、package
递归调用
- 方法进栈与出栈的顺序:先进后出
- 方法在出栈的时候,执行的是return语句。因为出栈就意味着方法结束并消费,如果没有return语句,那么方法出栈的时候什么都不执行,就直接销毁。
public class Main {
public static void main(String[] args) {
split(12);
}
public static int split(int number) {
if (number > 1) {
if (number % 2 != 0) {
System.out.print(split((number + 1) / 2));
}
System.out.print(split(number / 2));
}
return number;
}
}
sout