05 JVM和GC.txt
UP 返回
1.反编译代码
1.1 创建项目javabasic,src下创建包com.dm.bytecode,包下创建类ByteCodeSample
public class ByteCodeSample {
public static void main(String[] args) {
int i=1,j=5;
i++;
++j;
System.out.println(i);
System.out.println(j);
}
}
1.2 打开idea控制台(或者用系统的也行),执行:
cd src 进入目录下
javac com/dm/bytecode/ByteCodeSample.java 编译(此时会在目录下生成ByteCodeSample.class文件)
javap -c com/dm/bytecode/ByteCodeSample.class 反编译(此时会打印出反编译出来的代码)
Compiled from "ByteCodeSample.java" 说明由ByteCodeSample.java编译而来
public class com.dm.bytecode.ByteCodeSample {
public com.dm.bytecode.ByteCodeSample(); 编译生成的缺省无参构造函数
Code: code表示该方法的代码如下
0: aload_0 this句柄,表示对this进行操作
1: invokespecial #1 // Method java/lang/Object."<init>":()V 调用父类的构造方法(注释里说明了其父类为Object)
4: return 退出方法
public static void main(java.lang.String[]); main函数及其参数为String数组
Code:
0: iconst_1 把常量1放到栈顶
1: istore_1 将栈顶的值1放到局部变量1中
2: iconst_5 把常量5放到栈顶
3: istore_2 将栈顶的值5放到局部变量2中
4: iinc 1, 1 将变量1加1
7: iinc 2, 1 将变量2加1
10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; getstatic来获取PrintStream的静态域对象,将其压入栈顶
13: iload_1 iload_1 将本地变量1的值推入栈顶
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 调用PrintStream.println方法打印
17: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
20: iload_2 对变量2同样进行上述操作
21: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
24: return
}
1.3 java跨平台的实现:
.java文件通过javac编译,生成.class字节码文件;字节码文件会被各个平台的JVM解析,转换成特定平台的执行指令。演示如下:
ssh root@192.168.0.108 win平台上可以通过ssh命令登录其他服务器,这里表示以root登录192.168.0.108,输入密码以后即可操作对应电脑
scp ByteCodeSample.class root@192.168.0.108:~ 进入之前编译的bytecode文件夹下,使用scp可以将指定路径下的文件ByteCodeSample.class传入以root用户登录进192.168.0.108的用户目录下(~即表示用户目录,稍后输入密码即可执行操作)
scp需要两边电脑同时支持,如果服务器的linux是最简安装则不支持该命令,需要使用yum install openssh-clients安装即可
mkdir -p com/dm/bytecode 进入目标服务器,创建文件夹com/dm/bytecode(因为之前就是在该路径下编译产生的class,所以这里的文件也要放在同样的文件夹下才能被执行,否则会报找不到主类的错)
cp ByteCodeSample.class com/dm/bytecode/ 将ByteCodeSample.class移进com/dm/bytecode/文件夹下(当前目录是用户目录~)
java com.dm.bytecode.ByteCodeSample 执行,可以发现打印出了2和6,跨平台成功
2 虚拟机
2.1 java虚拟机的结构,分为4大部分:
Class Loader
Runtime Data Area(JVM内存空间结构模型。Stack,Heap,Method Area,PC Register,Native Method Stack)
Execution Engine
Native Interface(本地接口。融合不同的编程语言为java所用)
Class Loader依据特定格式,将class文件加载到内存(只要符合格式即加载,能不能运行由Execution Engine管);Execution Engine负责对class文件里的字节码进行解析并交给操作系统执行。
2.2 ClassLoader
ClassLoader负责通过将Class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接初始化等操作
3 反射
创建类:
package com.dm.reflect;
public class Robot {
private String name;
public void sayHi(String helloSentence) {
System.out.println(helloSentence + " " + name);
}
private String throwHello(String tag) {
return "Hello " + tag;
}
}
在main中运用反射:
public class ReflectSample {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class rc = Class.forName("com.dm.reflect.Robot");
Robot r = (Robot) rc.newInstance();
System.out.println("Class name is " + rc.getName());
Method getHello = rc.getDeclaredMethod("throwHello", String.class);//能获取类中除了继承和实现的接口的其他所有方法,包括私有
getHello.setAccessible(true);//私有方法需要设置
Object str = getHello.invoke(r, "Bob");
System.out.println("getHello result is " + str);
Method sayHi = rc.getMethod("sayHi", String.class);//只能获取公共的方法,但是可以获取继承以及实现的方法
sayHi.invoke(r, "Welcome");
Field name = rc.getDeclaredField("name");
name.setAccessible(true);
name.set(r, "Alice");
sayHi.invoke(r, "Welcome");
}
}
DOWN 返回