一

{"type":"编程笔记"}


  • Home

  • Archives
  • Search

java class file

Posted on 2016-12-25   |   In java

The Java Class File

The previous chapter, the first of Part II, "Java Internals," gave an overview of the Java Virtual Machine. The next four chapters will focus on different aspects of the Java Virtual Machine. This chapter takes a look at the Java class file. It describes the contents of the class file, including the structure and format of the constant pool. This chapter serves as a complete reference of the Java class file format.

Accompanying this chapter on the CD-ROM is an applet that interactively illustrates the material presented in the chapter. The applet, named Getting Loaded, simulates the Java Virtual Machine loading a Java class file. At the end of this chapter, you will find a description of this applet and an instructions on how to use it.

What is a Java Class File?

The Java class file is a precisely defined binary file format for Java programs. Each Java class file represents a complete description of one Java class or interface. There is no way to put more than one class or interface into a single class file. The precise definition of the class file format ensures that any Java class file can be loaded and correctly interpreted by any Java Virtual Machine, no matter what system produced the class file or what system hosts the virtual machine.

Although the class file is related to the Java language architecturally, it is not inextricably linked to the Java language. As shown in Figure 6-1, you could write programs in other languages and compile them to class files, or you could compile your Java programs to a different binary file format. Nevertheless, most Java programmers will likely use the class file as the primary vehicle for delivering their programs to Java Virtual Machines.

As mentioned in earlier chapters, the Java class file is a binary stream of 8-bit bytes. Data items are stored sequentially in the class file with no padding between adjacent items. The lack of padding helps keep class files compact. Items that occupy more than one byte are split up into several consecutive bytes that appear in big-endian (higher bytes first) order.

Just as your Java classes can contain varying numbers of fields, methods, method parameters, local variables, and so on, the Java class file can contain many items that vary in size or number from one class file to another. In the class file, the size or length of a variable-length item precedes the actual data for the item. This allows class file streams to be parsed from beginning to end, reading in the size of an item first followed by the item data.

What's in a Class File?

The Java class file contains everything a Java Virtual Machine needs to know about one Java class or interface. The remainder of this chapter describes the class file format using tables. Each table has a name and shows an ordered list of items that can appear in a class file. Items appear in the table in the order in which they appear in the class file. Each item has a type, a name, and a count. The type is either a table name or one of the "primitive types" shown in Table 6-1. All values stored in items of type u2, u4, and u8 appear in the class file in big-endian order.

Table 6-1. Class file "primitive types"

Type Bytes
u1 a single unsigned byte
u2 two unsigned bytes
u4 four unsigned bytes
u8 eight unsigned bytes

The major components of the class file, in their order of appearance in the class file, are shown in Table 6-2. Each of these components is described in more detail below.

Table 6-2. Format of a ClassFile Table

Type Name Count
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods mehtods_count
u2 attributes_count 1
attribute_info attributes attributes_count
Read more »

java command line options

Posted on 2016-12-16   |   In java
 java -showversion -helpjava version "1.8.0_66"Java(TM) SE Runtime Environment (build 1.8.0_66-b17)Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)Usage: java [-options] class [args...]           (to execute a class)   or  java [-options] -jar jarfile [args...]           (to execute a jar file)where options include:    -d32          use a 32-bit data model if available    -d64          use a 64-bit data model if available    -server       to select the "server" VM                  The default VM is server,                  because you are running on a server-class machine.    -cp <class search path of directories and zip/jar files>    -classpath <class search path of directories and zip/jar files>                  A : separated list of directories, JAR archives,                  and ZIP archives to search for class files.    -D<name>=<value>                  set a system property    -verbose:[class|gc|jni]                  enable verbose output    -version      print product version and exit    -version:<value>                  Warning: this feature is deprecated and will be removed                  in a future release.                  require the specified version to run    -showversion  print product version and continue    -jre-restrict-search | -no-jre-restrict-search                  Warning: this feature is deprecated and will be removed                  in a future release.                  include/exclude user private JREs in the version search    -? -help      print this help message    -X            print help on non-standard options    -ea[:<packagename>...|:<classname>]    -enableassertions[:<packagename>...|:<classname>]                  enable assertions with specified granularity    -da[:<packagename>...|:<classname>]    -disableassertions[:<packagename>...|:<classname>]                  disable assertions with specified granularity    -esa | -enablesystemassertions                  enable system assertions    -dsa | -disablesystemassertions                  disable system assertions    -agentlib:<libname>[=<options>]                  load native agent library <libname>, e.g. -agentlib:hprof                  see also, -agentlib:jdwp=help and -agentlib:hprof=help    -agentpath:<pathname>[=<options>]                  load native agent library by full pathname    -javaagent:<jarpath>[=<options>]                  load Java programming language agent, see java.lang.instrument    -splash:<imagepath>                  show splash screen with specified imageSee http://www.oracle.com/technetwork/java/javase/documentation/index.html for more details.

常用命令行部分选项说明

  1. -cp、-classpath:目录和压缩的或.jar文件通过:(在 Windows 上通过;)来分隔。设置应用程序类和资源的搜索路径。如果不使用-classpath和-cp,也不设置CLASSPATH环境变量,那么缺省情况下,用户类路径是当前目录.。
  2. -help、-?:打印使用消息。
  3. -fullversion:印出 JVM 的构建和版本信息。
  4. -showversion:打印产品版本并继续。
  5. -verbose:<option>[,<option>...]:启用详细输出。使用逗号分隔多个选项。可用选项为:
    1. class:为装入的每个类的stderr写入一个条目。
    2. gc:提供详细的垃圾回收信息。
    3. jni:向stderr写入信息,描述应用程序和 JVM 所调用的JNI服务。
  6. -version:印出 JVM 的完全构建和版本信息。
Read more »

git merge losts commits

Posted on 2016-12-03   |   In linux

下面的脚本重现了一个git分支合并的误操作,导致分支合并后,虽然在提交历史上可以看到每个commit,但是feature分支上提交的修改丢失了。

[ -a git-merge-head.git ] && rm -rf git-merge-head.git[ -a git-merge-head-logs ] && rm -rf git-merge-head-logsgit --bare init git-merge-head.gitgit clone git-merge-head.git git-merge-head-logscd git-merge-head-logs/echo "1" > v01-master.txtgit add -A && git commit -m "v01-master"git checkout -b featureecho "2" >> v01-master.txtgit add -A && git commit -m "v02-feature"git checkout masterecho "3" > v03-master.txtgit add -A && git commit -m "v03-master"#1git merge feature -m ""#2git reset .#3git checkout .git commit -m "commit version lost modification of v02-feature"echo "4" > v04-master.txtgit add -A && git commit -m "v04-master"echo "5" > v05-master.txtgit add -A && git commit -m "v05-master"cat v01-master.txt

问题说明

可以看到上述命令最后cat v01-master.txt命令,其输出的文件内容如下,可以看到feature分支中的修改丢失掉了。

1

使用git log -- v01-master.txt命令查看文件提交历史,只有master分支的提交历史,feature分支的提交丢失了。

db8ba5a v01-master

错误分析

第一个出错的操作#1,在合并分支时,因为没有提交版本的说明,导致合并没完成,没有产生合并操作的commit,但这个时间合并的内容已经被加入了git的index暂存区,如果此时手工commit这2个分支的合并操作,完全是没问题的。此时的git status输出如下:

On branch master

All conflicts fixed but you are still merging.

(use "git commit" to conclude merge)

Changes to be committed:

modified:   v01-master.txt

接下来第二个出错的操作#2,git reset .操作默认是mixed模式,会回滚index暂存区和本地仓库到指定的版本,所有的修改内容仍然是存在于当前git的工作空间的,分支中的内容可以git add之后再git commit,仍然不会丢失,此时的git status输出如下:

On branch master

All conflicts fixed but you are still merging.

(use "git commit" to conclude merge)

Changes not staged for commit:

(use "git add ..." to update what will be committed)

(use "git checkout -- ..." to discard changes in working directory)

modified:   v01-master.txt

no changes added to commit (use "git add" and/or "git commit -a")

最后第三步操作#3是版本修改丢失的关键原因,它通过git checkout .操作从index暂存区恢复代码到工作空间,将本地工作空间中的修改直接覆盖掉了,导致了此次合并中feature分支的修改丢失了。

其实上面#2和#3这2步操作接近于做了一次git reset --hard操作,只是因为之前的git merge操作没有完成,所以在.git目录里仍然存在MERGE_HEAD、MERGE_MODE和MERGE_MSG文件,可以继续提交此次合并操作,但实际上所有的代码已经被还原了。

Read more »

java method handle

Posted on 2016-11-20   |   In java

JDK 7以前字节码指令集中,四条方法调用指令invokevirtual、invokespecial、invokestatic、invokeinterface的第一个参数都是被调用的方法的符号引用CONSTANT_Methodref_info或者CONSTANT_InterfaceMethodref_info常量,方法的符号引用在编译时产生,而动态类型语言只有在运行期才能确定接收者类型,为了在Java虚拟机层面上提供动态类型的直接支持,在JDK 7中新增了invokedynamic指令。

JDK 7实现了JSR 292《Supporting Dynamically Typed Languages on the Java Platform》,JSR 292主要服务的对象是JVM上动态语言的实现。

新加入的java.lang.invoke包是就是JSR 292的一个重要组成部分,这个包的主要目的是在之前单纯依靠符号引用来确定调用的目标方法这条路之外,提供一种新的动态确定目标方法的机制,称为MethodHandle。

MethodHandle可以指向任意方法,提供为方法创建“别名”的能力,可以用统一的方式去调用MethodHandle。此外,MethodHandle还支持组合,可以以适配器的方式将多个MethodHandle串在一起,实现参数过滤、参数转换、返回值转换等许多功能。

目前通过benchmark测试的结果来看,调用MethodHandle的速度是最慢的,距调用接口方法的速度还是有较明显的差距,下面会测试代码详细说明。

MethodHandle对许多JVM的内部实现来说并不是一个全新的概念。要实现JVM,在内部总会保留一些指向方法的指针,JDK 7只是把它(和其它许多JVM里原本就支持的概念)具体化为Java类型暴露给Java代码用而已,这就是所谓的reification。

MethodHandle的主要要解决的问题就是要高效的调用编译时已知签名但具体目标未知的方法,其主要还是为JVM上的动态语言的实现服务,并不是面向普通的Java程序员的,换个说法就是对普通Java程序员来说并不是很常用的。

MethodHandle示例

public class SimpleDynamicInvoker {    public static class InvokeDynamicA {        public void array(String[] args) {            int length = args.length;            System.out.println(this.getClass().getSimpleName() + " : arguments length is : " + length);        }    }    public static class InvokeDynamicB {        public void array(String[] args) {            int length = args.length;            System.out.println(this.getClass().getSimpleName() + " : arguments length is : " + length);        }        public static int list(List<String> args) {            int length = args.size();            System.out.println("list size is : " + length);            return length;        }    }    public static void main(String[] args) throws Throwable {        InvokeDynamicB invokeDynamicB = new InvokeDynamicB();        MethodHandles.Lookup lookup = MethodHandles.lookup(); // 1        // instance method invoke        MethodType methodType = MethodType.methodType(void.class, String[].class); // 2        MethodHandle methodHandle = lookup.findVirtual(InvokeDynamicB.class, "array", methodType).bindTo(invokeDynamicB); // 3        methodHandle.invoke(new String[]{"abc", "def", "ghi"}); // 4        // bind the same methodType and methodName to another instance        methodHandle = lookup.findVirtual(InvokeDynamicA.class, "array", methodType).bindTo(new InvokeDynamicA());        methodHandle.invokeExact(new String[]{"abc", "def", "ghi"});        // static method invoke        methodType = MethodType.methodType(int.class, java.util.List.class);        methodHandle = lookup.findStatic(InvokeDynamicB.class, "list", methodType);        List<String> list = Lists.newArrayList("abc", "def", "ghi");        // 必须指明返回类型为int,满足methodType的要求,否则抛异常:expected (List)int but found (List)Object        // Object length = methodHandle.invokeExact(list);        int length = (int) methodHandle.invokeExact(list);        System.out.println(length);    }}

这个例子用到的是MethodHandles、MethodHandles.Lookup、MethodType、MethodHandle几个类。代码执行流程:

  1. 调用MethodHandles.lookup()方法,遍历调用栈检查访问权限,然后得到一个MethodHandles.Lookup实例;该对象用于确认创建MethodHandle的实例的类对目标方法的访问权限是否满足要求,并提供搜索目标方法的逻辑。
  2. 指定目标方法的方法类型,得到一个MethodType实例。
  3. 通过MethodHandles.lookup()静态方法得到一个类型为MethodHandles.Lookup的工厂,然后靠它搜索指定的类型、指定的名字、指定的方法类型的方法,得到一个MethodHandle实例。
  4. 调用MethodHandle上的invoke()方法,或者是invokeExact()这样与虚拟机指令直接关联的相关方法。

其中,第1步中调用的MethodType.methodType()方法接收的参数是一组类型,第一个参数是返回类型,后面依次是各个参数类型。

第2步调用中MethodType.methodType(void.class, String[].class)得到的就是一个返回类型为void,参数列表为String[]类型的方法类型。而这个方法类型在class字节码文件中的描述符就是:

descriptor: ([Ljava/lang/String;)V

MethodType的实例只代表所有返回值类型与参数类型匹配的一类方法的方法类型,自身没有名字;在检查某个方法是否与某个MethodType匹配时只考虑结构,可以算是一种特殊的structural-typing。

第2步看起来跟普通的反射很像,但通过反射得到的代表方法的对象是java.lang.reflect.Method的实例,它含有许多跟“执行”没有直接关系的信息,比较笨重;通过Method对象调用方法只是正常方法调用的模拟,所有参数会被包装为一个数组,开销较大。而MethodHandle则是个非常轻量的对象,主要目的就是用来引用方法并调用;通过它去调用方法不会导致参数被包装,原始类型的参数也不会被自动装箱。

MethodHandles.Lookup对象上有三个find方法,包括findStatic()、findVirtual()、findSpecial(),分别对应invokestatic、invokevirtual & invokeinterface、invokespecial这4个虚拟机指令。

注意第3步中findVirtual()方法所返回的MethodHandle的方法类型会通过bindTo(Object)显式绑定到一个具体的实例对象上;调用虚方法的MethodHandle要显式传入方法接收者receiver。

而下面的findStatic()方法则不需要再调用bindTo(Object)方法进行对象绑定。

MethodHandle的方法类型不是Java语言的静态类型系统的一部分。虽然它的实例在运行时带有方法类型信息(MethodType),但在编译时Java编译器却不知道这一点。所以在编译时,调用invoke时传入任意个数、任意类型的参数都可以通过编译;但在运行时要成功调用,由Java编译器推断出来的返回值类型与参数列表必须与运行时MethodHandle实际的方法类型一致,否则会抛出WrongMethodTypeException,可以参考上述例子最后的注释说明。

从上面的例子看来,使用MethodHandle并没有多少困难,不过看完它的用法之后,自然会与java的反射Reflection产生对比。

仅站在Java语言的角度看,MethodHandle的使用方法和效果上与Reflection都有众多相似之处。不过,它们也有以下这些区别:

  1. Reflection和MethodHandle机制本质上都是在模拟方法调用,但是Reflection是在模拟Java代码层次的方法调用,而MethodHandle是在模拟字节码层次的方法调用。在MethodHandles.Lookup上的三个方法findStatic()、findVirtual()、findSpecial()正是为了对应于invokestatic、invokevirtual & invokeinterface和invokespecial这几条字节码指令的执行权限校验行为,而这些底层细节在使用Reflection API时是不需要关心的。
  2. Reflection中的java.lang.reflect.Method对象远比MethodHandle机制中的java.lang.invoke.MethodHandle对象所包含的信息来得多。前者是方法在Java一端的全面映像,包含了方法的签名、描述符以及方法属性表中各种属性的Java端表示方式,还包含有执行权限等的运行期信息。而后者仅仅包含着与执行该方法相关的信息。用开发人员通俗的话来讲,Reflection是重量级,而MethodHandle是轻量级。
  3. MethodHandle与Reflection除了上面列举的区别外,最关键的一点在于:Reflection API的设计目标是只为Java语言服务的,而MethodHandle则设计为可服务于所有Java虚拟机之上的语言,其中也包括了Java语言而已。

某种程度上可以说invokedynamic指令与MethodHandle机制的作用是一样的,都是为了解决原有四条invoke*指令方法分派规则固化在虚拟机之中的问题,把如何查找目标方法的决定权从虚拟机转嫁到具体用户代码之中,让用户(包含其他语言的设计者)有更高的自由度。

Read more »

using 7zip and unarchiver on mac os

Posted on 2016-11-19   |   In macos

7zip installation

 brew install p7zip

7z command usage examples

7z压缩文件

 mkdir 7z-压缩文件夹 cd 7z-压缩文件夹 echo "test" > 7z-中文文件名.txt cd - 7z a test.zip 7z-压缩文件夹

7z解压缩

解压缩到unzip目录中,目录不存在会自动创建,注意-o后面的参数前面不要加空格。

 7z x test.zip -ounzip
Read more »
1…141516…99
yuweijun

yuweijun

492 posts
12 categories
RSS
GitHub Twitter
© 2021 yuweijun
Powered by Hexo
Theme - NexT.Mist.KISS