java hashcode

java hashcode java hash code hash code是一种编码方式,在Java中,每个对象都会有一个hashcode,Java可以通过这个hashcode来识别一个对象。至于hashcode的具体编码方式,比较复杂 (事实上这个编码是可以由程序员通过继承和接口的实现重写的) ,可以参考数据结构书籍。而hashtable等结构,就是通过这个哈希实现快速查找键对象。这是他们的内部联系,但一般编程时无需了解这些,只要知道hashtable实现了一种无顺序的元素排列就可以了。 两个对象值相同(x.equals(y) == true),则一定有相同的hash code。 因为: Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入 (又叫做预映射, pre-image) ,通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。 以下是java语言的定义: 对象相等则hashCode一定相等; hashCode相等对象未必相等。 这也涉及到如何写自定义的hashCode方法的问题: 必须符合以上条件。注意条件2中的未必。具体可参见java doc; Effective Java中有更详细论述。 补充一点个人简介 hash 就是 类似于数学集合, 每一个键,k可以对应一个或多个值,对象就类似于值,所以"相同的对象"具有相同的键值,也就是hashCode;

2012-09-21 · 1 min · 31 words · -

java Constructor

java Constructor **一、构造器是干什么用的? (what) ** 构造器是用来生成一个类的实例是用来初始化这个实例用的 **二、构造器如何工作? (how) ** Java在构造实例时的顺序是这样的: 分配对象空间,并将对象中成员初始化为0或者空,java不允许用户操纵一个不定值的对象。 执行属性值的显式初始化 执行构造器 4 、将变量关联到堆中的对象上 而执行构造器的步骤有可以分为以下几步: Bind构造器的参数 如果显式的调用了this,那就递归调用this构造器然后跳到步骤5 递归调用显式或者隐式的父类构造器,除了Object以外,因为它没有父类 执行显式的实例变量初始化 (也就是上边的流程中的第二步,调用返回以后执行, 这个步骤相当于在父构造器执行后隐含执行的,看样子像一个特殊处理) 三、构造器不可被orerride (why) 其实你只需要记住一句话: 构造器不是方法,那么用来修饰方法特性的所有修饰符都不能用来修饰构造器 (并不等与构造器 具备这些特性,虽然不能用static修饰构造器,但它却有静态特性) 构造器只能用 public private protected这 三个权限修饰符,且不能有返回语句。 参考: http://doc.linuxpk.com/43476.html

2012-09-21 · 1 min · 35 words · -

java native

java native Java不是完美的,Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层 (如系统硬件等),为此Java使用native方法来扩展Java程序的功能。 可以将native方法比作Java程序同C程序的接口,其实现步骤: 1、在Java中声明native()方法,然后编译; 2、用javah产生一个.h文件; 3、写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件 (注意其中又包含了JDK带的jni.h文件) ; 4、将第三步的.cpp文件编译成动态链接库文件; 5、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。 JAVA本地方法适用的情况 1.为了使用底层的主机平台的某个特性,而这个特性不能通过JAVA API访问 2.为了访问一个老的系统或者使用一个已有的库,而这个系统或这个库不是用JAVA编写的 3.为了加快程序的性能,而将一段时间敏感的代码作为本地方法实现。 首先写好JAVA文件 /* Created on 2005-12-19 Author shaoqi */ package com.hode.hodeframework.modelupdate; public class CheckFile { public native void displayHelloWorld(); static { System.loadLibrary(“test”); } public static void main(String[] args) { new CheckFile().displayHelloWorld(); } } 然后根据写好的文件编译成CLASS文件 然后在classes或bin之类的class根目录下执行javah -jni com.hode.hodeframework.modelupdate.CheckFile, 就会在根目录下得到一个com_hode_hodeframework_modelupdate_CheckFile.h的文件 然后根据头文件的内容编写com_hode_hodeframework_modelupdate_CheckFile.c文件 #include “CheckFile.h” #include #include JNIEXPORT void JNICALL Java_com_hode_hodeframework_modelupdate_CheckFile_displayHelloWorld(JNIEnv *env, jobject obj) { printf(“Hello world!n”); return; } 之后编译生成DLL文件如"test.dll",名称与System.loadLibrary(“test”)中的名称一致 vc的编译方法: cl -I%java_home%include -I%java_home%includewin32 -LD com_hode_hodeframework_modelupdate_CheckFile.c -Fetest.dll ...

2012-09-21 · 1 min · 80 words · -

Java assertion

Java assertion ashttp://www.ibm.com/developerworks/cn/java/l-javaassertion/index.html sertion的语法和语义 J2SE 1.4在语言上提供了一个新特性,就是assertion(断言)功能,它是该版本在Java语言方面最大的革新。在软件开发中,assertion是一种经典的调试、测试方式,本文将深入解析assertion功能的使用以及其设计理念,并给出相关的例子 。 assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制,如C,C++和Eiffel等,但是支持的形式不尽相同,有的是通过语言本身、有的是通过库函数等。另外,从理论上来说,通过assertion方式可以证明程序的正确性,但是这是一项相当复杂的工作,目前还没有太多的实践意义。 在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion检查通常是关闭的。下面简单介绍一下Java中assertion的实现。 1.1) 语法表示 在语法上,为了支持assertion,Java增加了一个关键字assert。它包括两种表达式,分别如下: assert expression1; assert expression1: expression2; 在两种表达式中,expression1表示一个boolean表达式,expression2表示一个基本类型或者是一个对象(Object) ,基本类型包括boolean,char,double,float,int和long。由于所有类都为Object的子类,因此这个参数可以用于所有对象。 1.2) 语义含义 在运行时,如果关闭了assertion功能,这些语句将不起任何作用。如果打开了assertion功能,那么expression1的值将被计算,如果它的值为false,该语句强抛出一个AssertionError对象。如果assertion语句包括expression2参数,程序将计算出expression2的结果,然后将这个结果作为AssertionError的构造函数的参数,来创建AssertionError对象,并抛出该对象;如果expression1值为true,expression2将不被计算。 一种特殊情况是,如果在计算表达式时,表达式本身抛出Exception,那么assert将停止运行,而抛出这个Exception。 1.3) 一些assertion例子 下面是一些Assert的例子。 assert0 < value; assert0 < value:“value="+value; assertref != null:“ref doesn’t equal null”; assertisBalanced(); 1.4) 编译 由于assert是一个新关键字,使用老版本的JDK是无法编译带有assert的源程序。因此,我们必须使用JDK1.4(或者更新)的Java编译器,在使用Javac命令时,我们必须加上-source 1.4作为参数。-source 1.4表示使用JDK 1.4版本的方式来编译源代码,否则编译就不能通过,因为缺省的Javac编译器使用JDK1.3的语法规则。 一个简单的例子如下: javac -source 1.4 test.java 1.5) 运行 由于带有assert语句的程序运行时,使用了新的ClassLoader和Class类,因此,这种程序必须在JDK1.4(或者更高版本)的JRE下运行,而不能在老版本的JRE下运行。 由于我们可以选择开启assertion功能,或者不开启,另外我们还可以开启一部分类或包的assertion功能,所以运行选项变得有些复杂。通过这些选项,我们可以过滤所有我们不关心的类,只选择我们关心的类或包来观察。下面介绍两类参数: 参数 -esa和 -dsa: 它们含义为开启(关闭)系统类的assertion功能。由于新版本的Java的系统类中,也使了assertion语句,因此如果用户需要观察它们的运行情况,就需要打开系统类的assertion功能 ,我们可使用-esa参数打开,使用 -dsa参数关闭。 -esa和-dsa的全名为-enablesystemassertions和-disenablesystemassertions,全名和缩写名有同样的功能。 参数 -ea和 -ea: 它们含义为开启(关闭)用户类的assertion功能: 通过这个参数,用户可以打开某些类或包的assertion功能,同样用户也可以关闭某些类和包的assertion功能。打开assertion功能参数为-ea;如果不带任何参数,表示打开所有用户类;如果带有包名称或者类名称,表示打开这些类或包;如果包名称后面跟有三个点,代表这个包及其子包;如果只有三个点,代表无名包。关闭assertion功能参数为-da,使用方法与-ea类似。 -ea和-da的全名为-enableassertions和-disenableassertions,全名和缩写名有同样的功能。 下面表格表示了参数及其含义,并有例子说明如何使用。 参数 例子 说明 -ea java -ea 打开所有用户类的assertion -da java -da 关闭所有用户类的assertion -ea:<classname> java -ea:MyClass1 打开MyClass1的assertion -da:<classname> java -da: MyClass1 关闭MyClass1的assertion -ea:<packagename> java -ea:pkg1 打开pkg1包的assertion -da:<packagename> java -da:pkg1 关闭pkg1包的assertion -ea:... java -ea:... 打开缺省包(无名包)的assertion -da:... java -da:... 关闭缺省包(无名包)的assertion -ea:<packagename>... java -ea:pkg1... 打开pkg1包和其子包的assertion -da:<packagename>... java -da:pkg1... 关闭pkg1包和其子包的assertion -esa java -esa 打开系统类的assertion -dsa java -dsa 关闭系统类的assertion 综合使用 java -dsa:MyClass1:pkg1 关闭MyClass1和pkg1包的assertion 其中...代表,此包和其子包的含义。例如我们有两个包为pkg1和pkg1.subpkg。那么pkg1...就代表pkg1和pkg1.subpkg两个包。 另外,Java为了让程序也能够动态开启和关闭某些类和包的assertion功能,Java修该了Class和ClassLoader的实现,增加了几个用于操作assert的API。下面简单说明一下几个API的作用。 ClassLoader类中的几个相关的API: setDefaultAssertionStatus:用于开启/关闭assertion功能 setPackageAssertionStatus:用于开启/关闭某些包的assertion功能 setClassAssertionStatus: 用于开启/关闭某些类的assertion功能 clearAssertionStatus: 用于关闭assertion功能 [回页首][1] assertion的设计问题 首先,我们认为assertion是必要的。因为,如果没有统一的assertion机制,Java程序通常使用if-then-else或者switch-case语句进行assertion检查,而且检查的数据类型也不完全相同。assertion机制让Java程序员用统一的方式处理assertion问题,而不是按自己的方式处理。另外,如果用户使用自己的方式进行检查,那么这些代码在发布以后仍然将起作用,这可能会影响程序的性能。而从语言言层次支持assertion功能,这将把assertion对性能带来的负面影响降到最小。 Java是通过增强一个关键字assert实现支持assertion,而不是使用一个库函数支持,这说明Java认为assertion对于语言本身来说是非常重要的。实际上,在Java的早期的规范中,Java是能够支持assert的,但是由于一些实现的限制,这些特性从规范中除去了。因此,assert的再次引入应该是恢复了Java对assert的支持。C语言就是通过Assert.h函数库实现断言的支持。 Java的assertion的开启也和C语言不太一样,我们都知道在C语言中,assertion的开启是在编译时候决定的。当我们使用debug方式编译程序时候,assertion被开启,而使用release方式编译时候,assertion自动被关闭。而Java的assertion却是在运行的时候进行决定的。其实,这两种方式是各有优缺点。如果采用编译时决定方式,开发人员将处理两种类型的目标码,debug版本和release版本,这加大了文档管理的难度,但是提高了代码的运行效率。Java采用运行时决定的方式,这样所有的assertion信息将置于目标代码中,同一目标代码可以选择不同方式运行,增强目标代码的灵活性,但是它将牺牲因为assertion而引起一部分性能损失。Java专家小组认为,所牺牲的性能相当小,因此java采用了运行时决定方式。 另外,我们注意到AssertionError作为Error的一个子类,而不是RuntimeException。关于这一点,专家组也进行了长期的讨论。Error代表一些异常的错误,通常是不可以恢复的,而RuntimeException强调该错误在运行时才发生的特点。AssertionError通常为非常关键的错误,这些错误往往是不容易恢复的,而且assertion机制也不鼓励程序员对这种错误进行恢复。因此,为了强调assertion的含义,Java专家小组选择了让AssertError为Error的子类。 [回页首][1] assertion与继承 在本节,我们将考虑assertion与继承的关系,研究assert是如何定位的。如果开启一个子类的assertion,那么它的父类的assertion是否执行? 下面的例子将显示如果一个assert语句在父类,而当它的子类调用它时,该assert为false。我们看看在不同的情况下,该assertion是否被处理。 class Base { public void baseMethod() { assert false : “Assertion failed:This is base “;// 总是assertion失败 System.out.println(“Base Method”); } } class Derived extends Base { public void derivedMethod() { assert false: “Assertion failed:This is derive”;// 总是assertion失败 System.out.println( “Derived Method” ); } public static void main( String[] args ) { try { Derived derived = new Derived(); derived.baseMethod( ); derived.derivedMethod(); } catch( AssertionError ae ) { System.out.println(ae); } } } ...

2012-09-21 · 2 min · 368 words · -

在WSL2中安装ArchLinux

在WSL2中安装ArchLinux https://zhuanlan.zhihu.com/p/266585727 https://github.com/DDoSolitary/LxRunOffline .\LxRunOffline i -n archlinux -f C:\workspace\apps\archlinux-bootstrap-2022.02.01-x86_64.tar.gz -d C:\workspace\apps\wsl-archlinux -r root.x86_64 wsl --set-version archlinux 2 wsl -d archlinux lxrunoffline su -n archlinux -v 1000

2012-09-21 · 1 min · 26 words · -

Static Nested Class, Inner Class, Anonymous Inner Class

Static Nested Class, Inner Class, Anonymous Inner Class Inner Class (内部类) 定义在类中的类 Nested Class (嵌套类) 是静态 (static) 内部类。 要创建嵌套类的对象,并不需要其外围类的对象。 不能从嵌套类的对象中访问非静态的外围类对象。 Anonymous Inner Class (匿名内部类) 匿名的内部类是没有名字的内部类。 匿名的内部类不能extends (继承) 其它类,但一个内部类可以作为一个接口,由另一个内部类实现。 嵌套类可以作为接口的内部类。正常情况下,你不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分,因为它是static 的。只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。 内部类被继承,由于内部类有一个指向外围类对象的秘密引用,所以在继承内部类的时候,该秘密引用必须被初始化。解决方法是enclosingClassReference.super();语法,看一下代码: class Outer { class Inner { } } class AnoClass extends Outer.Inner { AnoClass (Outer wi) { wi.super(); } } 匿名类 (Anonymous Class) 当一个内部类的类声名只是在创建此类对象时用了一次,而且要产生的新类需继承于一个已有的父类或实现一个接口,才能考虑用匿名类,由于匿名类本身无名,因此它也就不存在构造方法,它需要显示地调用一个无参的父类的构造方法,并且重写父类的方法。 f.addMouseMotionListener(new MouseMotionAdapter(){ //匿名类开始 public void mouseDragged(MouseEvent e){ String s="Mouse dragging: x="+e.getX()+"Y="+e.getY(); tf.setText(s); } } ); //匿名类结束 存在它的原因是: ...

2012-09-21 · 1 min · 89 words · -

forward redirect

forward redirect forward vs redirect forward 是服务器内部重定向,程序收到请求后重新定向到另一个程序,而客户机并不知晓; forward会将 request state、bean、等信息带到下一个jsp页面; 使用getAttribute () 来取得前一个jsp所放的信息 redirect 是服务器收到请求后发送一个状态头给客户,客户将再次请求,就有两次网络通行的来往。 redirect 是送到客户端后再次request,因此上一个jsp的信息不被保留 效率: Forward高, Redirect低, 因为Redirect的流程是这样的, request 1 sent to server, server return back to client, request 2 then sent to server. But Forward 仅在server side处理, 对client side 是透明的. 由于Redirect 有两次传输, 所以效率低. 范围: 由于对request.setAttribute() 来说, 它携带的对象生存范围只在request内, 所以Redirect方式会导致request携带的对象丢失. http://www.iteye.com/topic/3497 http://article2008.iteye.com/blog/173832

2012-09-21 · 1 min · 54 words · -

Java, 堆(Heap), 栈/线程栈(Stack), 方法区(method), 常量池

Java, 堆(Heap), 栈/线程栈(Stack), 方法区(method), 常量池 Java, 堆(Heap), 栈/线程栈(Stack), 方法区(method Area), 常量池(Constant Pool) heap, 堆 堆是线程共享的,所有的对象的实例和数组都存放在堆中,任何线程都可以访问。Java的垃圾自动回收机制就是运用这个区域的。 Stack(栈), thread stacks(线程栈), call stack, Execution stack 栈是线程私有的,每个线程都是自己的栈,每个线程中的每个方法在执行的同时会创建一个栈帧用于保存 PC(程序计数器) 局部变量表、操作数栈、动态链接、方法返回地址等信息。每一个方法从调用到执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。其中局部变量表,存放基本类型 (boolean、byte、char、short、int、float) 、对象的引用等等,对象的引用不是对象实例本身,而是指向对象实例的一个指针。 ———————————————— 版权声明: 本文为CSDN博主「万猫学社」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接: https://blog.csdn.net/heihaozi/article/details/102752636 内存指令区,存储数据: 基本数据类型, 指令代码,常量,对象的引用地址(2) Hotspot VM: 栈内存从概念上分 “线程的栈内存” 和 “JVM的栈内存” 两种。 线程的栈内存: 每新建一个线程时,会分配给这个线程一个栈内存初始值,最大的大小可通过 -Xss 来设置。线程占有的栈内存大小,通过不断执行方法,生成局部变量等操作,栈桢不断增加,该线程的栈内存也不断被使用。最终达到 -Xss 的值时,会抛出 StackOverFlowError。其实这里就是线程的栈内存溢出,背后的概念与 OOME 是一样的,只是jvm设计者取的名字不一样而已。3.JVM的栈内存: 当一个jvm进程启动时,会不断消耗 native memory。我们可以通过参数 -Xmx 等来设置堆内存、方法区内存的最大值,当达到阀值时,jvm就会报OOME。但是栈内存大小,则是物理机器的 native memory,其上限就是native memory的上限。不断建线程消耗native memory待尽时,就会报OOME。 作者: chiukong 链接: https://www.zhihu.com/question/28637033/answer/41677862 来源: 知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 保存对象实例,实际上是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法 (方法是指令,保存在stack中) 。对象实例在heap中分配好以后,需要在stack中保存一个4字节的heap内存地址,用来定位该对象实例在heap中的位置,便于找到该对象实例。 基本数据类型包括byte、int、char、long、float、double、boolean和short。 函数方法属于指令 引用网上广泛流传的"Java堆和栈的区别"里面对堆和栈的介绍; ...

2012-09-21 · 3 min · 538 words · -

HashMap,Hashtable

HashMap,Hashtable HashMap, Hashtable HashTable的应用非常广泛,HashMap是新框架中用来代替HashTable的类,也就是说建议使用HashMap,不要使用HashTable。可能你觉得HashTable很好用,为什么不用呢?这里简单分析他们的区别。 HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像 Vector 和ArrayList一样。 HashTable不允许null值(key和value都不可以), HashMap允许 null 值(key和value都可以)。 hashMap去掉了HashTable 的contains(Object value)方法,但是加上了containsValue ()和containsKey ()方法。 HashTable使用 Enumeration,HashMap使用 Iterator。以上只是表面的不同,它们的实现也有很大的不同。 HashTable中 hash数组默认大小是11,增加的方式是 old*2+1。HashMap 中 hash数组的默认大小是16,而且一定是2的指数。 哈希值的使用不同,HashTable 直接使用对象的hashCode,代码是这样的: int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; //而HashMap重新计算hash值,而且用与代替求模: int hash = hash(k); int i = indexFor(hash, table.length); static int hash(Object x) { int h = x.hashCode(); h += ~(h << 9); h ^= (h >>> 14); h += (h << 4); h ^= (h >>> 10); return h; } static int indexFor(int h, int length) { return h & (length-1); } ``` 以上只是一些比较突出的区别,当然他们的实现上还是有很多不同的,比如 HashMap对null的操作 HashMap可以看作三个视图: key的Set,value的Collection,Entry的Set。 这里HashSet就是其实就是HashMap的一个视图。HashSet内部就是使用Hashmap实现的,和Hashmap不同的是它不需要Key和Value两个值。 往hashset中插入对象其实只不过是内部做了 public boolean add(Object o) { return map.put(o, PRESENT)==null; } HashMap为散列映射,它是基于hash table的一个实现,它可在常量时间内安插元素,或找出一组key-value pair.HashSet为散列集,它把查找时间看的很重要,其中所有元素必须要有hashCode() http://oznyang.iteye.com/blog/30690 http://zhaosoft.iteye.com/blog/243587 http://coolshell.cn/articles/9606.html http://coolshell.cn/articles/9606.html/embed#?secret=NbrQHz1OQo

2012-09-21 · 1 min · 115 words · -

java 位运算,移位运算符,bitwise operators

‘java 位运算,移位运算符,bitwise operators’ Java提供的位运算符有: 左移( « )、右移( » ) 、无符号右移( »> ) 、位与( & ) 、位或( | )、位非( ~ )、位异或( ^ ),除了位非( ~ )是一元操作符外,其它的都是二元操作符。 左移( « ) Test1、将5左移2位: package com.xcy; public class Test { public static void main(String[] args) { System.out.println(5<<2);//运行结果是20 } } 运行结果是20,但是程序是怎样执行的呢? 首先会将5转为2进制表示形式(java中,整数默认就是int类型,也就是32位): 0000 0000 0000 0000 0000 0000 0000 0101 然后左移2位后,低位补0: 0000 0000 0000 0000 0000 0000 0001 0100 换算成10进制为20 右移( » ) ,右移同理,只是方向不一样罢了(感觉和没说一样) System.out.println(5»2);//运行结果是1 ...

2012-09-21 · 2 min · 405 words · -

java线程安全

java线程安全 什么叫线程安全?这个首先要明确。线程安全就是说多线程访问同一代码,不会产生不确定的结果。 java的内存模型,java的线程同步机制。特别是内存模型,java的线程同步机制很大程度上都是基于内 存模型而设定的。 浅谈java内存模型 不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题: 可见性和有序性。我们都知道计算机有高速缓存的存在,处理器并不是每次处理数据都是取内存的。JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm内存模型的基础上,如果解决多线程的可见性和有序性。 那么,何谓可见性? 多个线程之间是不能互相传递数据通信的,它们之间的沟通只能通过共享变量来进行。Java内存模型 (JMM) 规定了jvm有主内存,主内存是多个线程共享的。当new一个对象的时候,也是被分配在主内存中,每个线程都有自己的工作内存,工作内存存储了主存的某些对象的副本,当然线程的工作内存大小是有限制的。当线程操作某个对象时,执行顺序如下: (1) 从主存复制变量到当前工作内存 (read and load) (2) 执行代码,改变共享变量值 (use and assign) (3) 用工作内存数据刷新主存相关内容 (store and write) JVM规范定义了线程对主存的操作指 令: read,load,use,assign,store,write。当一个共享变量在多个线程的工作内存中都有副本时,如果一个线程修改了这个共享变量,那么其他线程应该能够看到这个被修改后的值,这就是多线程的可见性问题。 那么,什么是有序性呢?线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变量,则会从主内存中拷贝一个副本到工作内存中,这个过程为read-load,完成后线程会引用该副本。当同一线程再度引用该字段时,有可能重新从主存中获取变量副本(read-load-use),也有可能直接引用原来的副本 (use),也就是说 read,load,use顺序可以由JVM实现系统决定。 线程不能直接为主存中的字段赋值,它会将值指定给工作内存中的变量副本(assign),完成后这个变量副本会同步到主存储区(store- write),至于何时同步过去,根据JVM实现系统决定.有该字段,则会从主内存中将该字段赋值到工作内存中,这个过程为read-load,完成后线程会引用该变量副本,当同一线程多次重复对字段赋值时,比如: for(int i=0;i<10;i++) a++; 线程有可能只对工作内存中的副本进行赋值,只到最后一次赋值后才同步到主存储区,所以assign,store,write顺序可以由JVM实现系统决定。假设有一个共享变量x,线程a执行x=x+1。从上面的描述中可以知道x=x+1并不是一个原子操作,它的执行过程如下: 1 从主存中读取变量x副本到工作内存 2 给x加1 3 将x加1后的值写回主存 如果另外一个线程b执行x=x-1,执行过程如下: 1 从主存中读取变量x副本到工作内存 2 给x减1 3 将x减1后的值写回主存 那么显然,最终的x的值是不可靠的。假设x现在为10,线程a加1,线程b减1,从表面上看,似乎最终x还是为10,但是多线程情况下会有这种情况发生: 1: 线程a从主存读取x副本到工作内存,工作内存中x值为10 2: 线程b从主存读取x副本到工作内存,工作内存中x值为10 3: 线程a将工作内存中x加1,工作内存中x值为11 4: 线程a将x提交主存中,主存中x为11 5: 线程b将工作内存中x值减1,工作内存中x值为9 6: 线程b将x提交到中主存中,主存中x为9 同样,x有可能为11,如果x是一个银行账户,线程a存款,线程b扣款,显然这样是有严重问题的,要解决这个问题,必须保证线程a和线程b是有序执行的, 并且每个线程执行的加1或减1是一个原子操作。看看下面代码: public class Account { private int balance; ...

2012-09-21 · 3 min · 587 words · -

同步/异步

同步/异步 所谓同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是出于阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。 异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。 并不是说谁好谁不好,只是同步的机制不适合在正式应用的项目当中 (但自己测试还是可以的) 同步,就是实时处理,比如服务器一接收客户端请求,马上响应,这样客户端可以在最短的时间内得到结果,但是如果多个客户端,或者一个客户端发出的请求很频繁,服务器无法同步处理,就会造成涌塞。 异步,就是分时处理,服务器接收到客户端请求后并不是立即处理,而是等待服务器比较空闲的时候加以处理,可以避免涌塞。 同步和异步之分: 同步就是调用一个函数,直接函数执行完了才返回到调用函数 异步就是被调用函数初始化完后马上返回。 多线程应用服务器工作 同步在一定程度上可以看做是单线程,这个线程请求一个方法后就待这个方法给他回复,否则他不往下执行(死心眼)。异步在一定程度上可以看做是多线程的(废话,一个线程怎么叫异步),请求一个方法后,就不管了,继续执行其他的方法。比如一个文章系统里面,文章内容通常是字数非常多的,如果数据量大,打开会非常的慢,这个时候可以采取两种方法: 1、死心眼: 一直等待要显示的数据全部取出来 标题、作者、来源、创建时间、关键字、点击次数、文章正文 ok,全部取出 显示 碰上心急的用户,他会骂死你的。 2、异步: 首先显示能够快速取出的部分: 标题、作者、来源、创建时间、关键字、点击数 显示 然后另外的一个线程等待取出文章的正文显示! 异步就是: 做一件事情的同事,不影响做其他的事情。 -------------- 同步就是(我死心眼)我等你(给我回答),异步就是(我很忙)我不等你(给我回答) 严格的说,异步还是有两种 一种是等,但是等的过程和同步不一样,等的时候可以做别的工作,但是程序的主线还是等待 WaitforSingleObject(hEvent,INFINTE,TRUE); 另外一种是CALLBACK方式,这种异步是完全不等待,程序主线发出请求之后就干别的事情去了,完全不理会请求执行的如何。 所有异步必然设计两个以上的线程 (不然不存在异步的问题) ,第一种方式下,请求的后期工作是在发出请求的线程上执行,第二种方式下,后期工作可以在任何线程 (通常是执行请求的线程上) 完成。

2012-09-20 · 1 min · 36 words · -

运行时异常/一般异常

运行时异常/一般异常 http://blog.csdn.net/yakihappy/article/details/3979883 Throwable是所有Java程序中错误处理的父类,有两种资类: Error和Exception。 Error: 表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。 Exception: 表示可恢复的例外,这是可捕捉到的。 Java提供了两类主要的异常:runtime exception和checked exception。 checked 异常也就是我们经常遇到的IO异常,以及SQL异常都是这种异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。 但是另外一种异常: runtime exception,也称运行时异常,我们可以不处理。当出现这样的异常时,总是由虚拟机接管。比如: 我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。 出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有一般异常的特点,是可以被Catch块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。 如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常,或者是通过对异常的处理显式的控制程序退出。 异常处理的目标之一就是为了把程序从异常中恢复出来。

2012-09-20 · 1 min · 20 words · -

JAVA String, StringBuffer, StringBuilder

JAVA String, StringBuffer, StringBuilder JAVA平台提供了两个类: String 和 StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而StringBuffer类提供的字符串允许进行修改。当你知道字符数据要改变的时候你就可以使用 StringBuffer。典型地,你可以使用 StringBuffers 来动态构造字符数据。 在java中与字符串操作相关的类 Character 是进行单个字符操作的, String 字符串常量 对一串字符进行操作。不可变类。 StringBuffer 也是对一串字符进行操作,但是可变类。字符串变量 (线程安全) StringBuilder 字符串变量 (非线程安全) String String是对象不是原始类型, 为不可变对象,一旦被创建,就不能修改它的值,对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去. String 是final类,即不能被继承. 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。 而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的: String S1 = “This is only a” + " simple" + " test"; StringBuffer Sb = new StringBuilder(“This is only a”).append(" simple").append(" test"); 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个 String S1 = “This is only a” + " simple" + “test”; 其实就是: String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如: String S2 = “This is only a”; String S3 = " simple"; String S4 = " test"; String S1 = S2 +S3 + S4; 这时候 JVM 会规规矩矩的按照原来的方式去做 ...

2012-09-20 · 2 min · 402 words · -

引用类型 基本类型

引用类型 基本类型 在Java性能优化系列中,内存管理是一个要优先考虑的关键因素。而说到内存分配,就必然会涉及到基本类型和引用类型。所以我们今天就先来介绍一下这两种类型在性能方面各自有什么奥妙。 名词定义 先明确一下什么是基本类型,什么是引用类型。简单地说,所谓基本类型就是Java语言中如下的8种内置类型: boolean、char、byte、short、int、long、float、double。而引用类型就是那些可以通过new来创建对象的类型 (基本上都是派生自Object) 。 ★两种类型的存储方式 这两种类型的差异,首先体现在存储方式上。在Java中,引用类型是存储在堆 (Heap) 上的;而基本类型是存储在栈 (Stack) 上。可能有同学会小声问: 堆和栈有啥区别捏?要说堆和栈的差别,那可就大了去了。如果你对这两个概念还是不太明白或者经常混淆,建议先找本操作系统的书拜读一下。 ★堆和栈的性能差异 堆和栈在性能方面是有很大差别滴。堆相对进程来说是全局的,能够被所有线程访问;而栈是线程局部的,只能本线程访问。打个比方,栈就好比个人小金库,堆就好比国库。你从个人小金库拿钱去花,不需要办什么手续,拿了就花,但是钱数有限;而国库里面的钱虽然很多,但是每次申请花钱要打报告、盖图章、办N多手续,耗时又费力。 同样道理,由于堆是所有线程共有的,从堆里面申请内存要进行相关的加锁操作,因此申请堆内存的复杂度和时间开销比栈要大很多;从栈里面申请内存,虽然又简单又快,但是栈的大小有限,分配不了太多内存。 ★为什么这样设计? 可能有同学又问了,干嘛把两种类型分开存储,干嘛不放到一起捏?这个问题问得好!下面我们就来揣测一下,当初Java为啥设计成这样。 当年Java它爹 (James Gosling) 设计语言的时候,对于这个问题有点进退两难。如果把各种东西都放置到栈中,显然不现实,一来栈是线程私有的 (不便于共享) ,二来栈的大小是有限的,三来栈的结构也间接限制了它的用途。那为啥不把各种东西都放置到堆里面捏?都放堆里面,倒是能绕过上述问题,但是刚才也提到了,申请堆内存要办很多手续,太繁琐。如果仅仅在函数中写一个简单的"int n = 0",也要到堆里面去分配内存,那性能就大大滴差了 (要知道Java是1995年生出来的,那年头我家的PC配4兆内存就属豪华配置了) 。 左思右想之后,Java它爹只好做了一个折中: 把类型分为基本类型和引用类型;引用类型 (Object派生) 的对象存放到堆里面;把基本类型 (非Object派生) 的值存放到栈里面。所以,你从Java语法上也可以看出两者的差别: 引用类型可以用new创建对象 (对于某些单键,表面上没用new,但是在getInstance()内部也还是用的new) ;而基本类型则不需要用new来创建。 这样设计的弊端 顺便跑题一下,斗胆评价Java它爹这种设计的弊端 (希望Java Fans不要跟我急) 。我个人认为: 这个折中的决策,带来了许多深远的影响,随手举出几个例子: 由于基本类型不是派生自Object,因此不能算是纯种的对象。这导致了Java的"纯面向对象"招牌打了折扣。 由于基本类型不是派生自Object,出于某些场合 (比如容器类) 的考虑,不得不为每个基本类型加上对应的包装类 (比如Integer、Byte等) ,使得语言变得有点冗余。 结论 从上述的介绍,我们应该明白,使用new创建对象的开销是不小的。在程序中能避免就应该尽量避免。另外,使用new创建对象,不光是创建时开销大,将来垃圾回收时,销毁对象也是有开销的。 http://program-think.blogspot.com/2009/03/java-performance-tuning-1-two-types.html http://www.ibm.com/developerworks/cn/java/praxis/pr8.html 下表列出了原始类型以及它们的对象封装类。 原始类型和封装类 原始类型 封装类 boolean Boolean char Character byte Byte short Short int Integer long Long float Float double Double 引用类型和原始类型的行为完全不同,并且它们具有不同的语义。例如,假定一个方法中有两个局部变量,一个变量为 int 原始类型,另一个变量是对一个 Integer 对象的对象引用: ...

2012-09-20 · 2 min · 247 words · -

java basic

java basic JDK 和 JRE 的区别 JRE:Java Runtime Environment 的简称,java 运行时环境,为 java 的运行提供了所需环境。 Java 虚拟机 jfr JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。 包含了JRE 编译器: javac 其他的工具: JavaDoc,Java调试器(jdb), jcmd, jstat, jmap JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。 http://www.wiloon.com/jdk-jre == vs equals == 对于基本类型和引用类型 == 的作用效果是不同的 基本类型:比较的是值是否相同; 引用类型:比较的是引用是否相同; String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.out.println(x.equals(y)); // true System.out.println(x.equals(z)); // true 代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。 ...

2012-09-20 · 4 min · 720 words · -

网关

网关 网关(Gateway)又称网间连接器、协议转换器。网关在传输层上以实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。 网关是一种充当转换重任的计算机系统或设备。在使用不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。同时,网关也可以提供过滤和安全功能。大多数网关运行在OSI 7层协议的顶层-应用层。基本概念 大家都知道,从一个房间走到另一个房间,必然要经过一扇门。同样,从一个网络向另一个网络发送信 网关息,也必须经过一道"关口",这道关口就是网关。顾名思义,网关 (Gateway) 就是一个网络连接到另一个网络的"关口"。也就是网络关卡。 在OSI中,网关有两种: 一种是面向连接的网关,一种是无连接的网关。当两个子网之间有一定距离时,往往将一个网关分成两半,中间用一条链路连接起来,我们称之为半网关。 按照不同的分类标准,网关也有很多种。TCP/IP协议里的网关是最常用的,在这里我们所讲的"网关"均指TCP/IP协议下的网关。 那么网关到底是什么呢?网关实质上是一个网络通向其他网络的IP地址。比如有网络A和网络B,网络A的IP地址范围为"192.168.1.1192. 168.1.254",子网掩码为255.255.255.0;网络B的IP地址范围为"192.168.2.1192.168.2.254",子网掩码为255.255.255.0。在没有路由器的情况下,两个网络之间是不能进行TCP/IP通信的,即使是两个网络连接在同一台交换机 (或集线器) 上,TCP/IP协议也会根据子网掩码 (255.255.255.0) 判定两个网络中的主机处在不同的网络里。而要实现这两个网络之间的通信,则必须通过网关。如果网络A中的主机发现数据包的目的主机不在本地网络中,就把数据包转发给它自己的网关,再由网关转发给网络B的网关,网络B的网关再转发给网络B的某个主机 (如附图所示) 。网络A向网络B转发数据包的过程。 所以说,只有设置好网关的IP地址,TCP/IP协议才能实现不同网络之间的相互通信。那么这个IP地址是哪台机器的IP地址呢?网关的IP地址是具有路由功能的设备的IP地址,具有路由功能的设备有路由器、启用了路由协议的服务器 (实质上相当于一台路由器) 、代理服务器 (也相当于一台路由器) 。 在和 Novell NetWare 网络交互操作的上下文中,网关在 Windows 网络中使用的服务器信息块 (SMB) 协议以及NetWare网络使用的 NetWare 核心协议 (NCP) 之间起着桥梁的作用。网关也被称为 IP 路由器。 举例说明 假设你的名字叫小不点(很小),你住在一个大院子里,你的邻居有很多小伙伴,父母是你的网关。当你想跟院子里的某个小伙伴玩,只要你在院子里大喊一声他的名字,他听到了就会回应你,并且跑出来跟你玩。 但是你家长不允许你走出大门,你想与外界发生的一切联系,都必须由父母 (网关) 用电话帮助你联系。假如你想找你的同学小明聊天,小明家住在很远的另外一个院子里,他家里也有父母 (小明的网关) 。但是你不知道小明家的电话号码,不过你的班主任老师有一份你们班全体同学的名单和电话号码对照表,你的老师就是你的DNS服务器。于是你在家里和父母有了下面的对话: 小不点: 妈妈(或爸爸),我想找班主任查一下小明的电话号码行吗? 网关例子家长: 好,你等着。 (接着你家长给你的班主任挂了一个电话,问清楚了小明的电话) 问到了,他家的号码是211.99.99.99 小不点: 太好了!妈(或爸),我想找小明,你再帮我联系一下小明吧。 家长: 没问题。 (接着家长向电话局发出了请求接通小明家电话的请求,最后一关当然是被转接到了小明家家长那里,然后他家长把电话给转到小明) . 就这样你和小明取得了联系。如果搞清了什么是网关,默认网关也就好理解了。就好像一个房间可以有多扇门一样,一台主机可以有多个网关。默认网关的意思是一台主机如果找不到可用的网关,就把数据包发给默认指定的网关,由这个网关来处理数据包。现在主机使用的网关,一般指的是默认网关。默认网关一般填写192.168.x.1

2012-09-20 · 1 min · 58 words · -

使用 arpalert 来做被动式arp防火墙

使用 arpalert 来做被动式arp防火墙 http://forum.ubuntu.org.cn/viewtopic.php?f=116&t=110347&sid=ae4c75fe6a8b5aa1672e8a05bc6f7d85 我说的被动式是指在探测到欺骗时做出防护动作 在局域网环境中 arp 欺骗是个很头疼的问题, 尤其是网关不是自己控制的时候. 虽然自己可以绑定网关, 但是网关就没办法了. 结果导致网关的东西传不回来, 无法上网. 原理: arpalert 监听网卡收到的 arp 包, 并根据规则(黑白名单等)调用一个防护脚本. 安装: 安装以下包: libnet-arp-perl arpalert(建议用最新的 2.0.11 版, 2.0.10 前的版本处理名单时有问题) 另外将以下文本存为 /usr/local/sbin/arpdef.pl 加上可执行权限(755) [perl] #!/usr/bin/perl -w use strict; if ( $< ) { print “$0n”; system(“sudo”,($0,@ARGV)); exit; } my $mac = $ARGV[0]; my $ip = $ARGV[1]; my ($gateip,$gatemac) = (“192.168.6.1”,“00:04:80:FA:3C:00”); exit 0 if ((“U$mac” eq “U$gatemac”) && ($ip eq $gateip)); #logging .. my $date=`date +"%F %T"`; ...

2012-09-19 · 5 min · 1059 words · -

子网, 子网掩码

子网, 子网掩码 子网掩码 subnet mask 子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。 https://www.zhihu.com/question/21064101 IP和子网掩码 IP 是由四段数字组成 3 类常用的 IP A 类IP段 0.0.0.0 到 127.255.255.255 B 类IP段 128.0.0.0 到 191.255.255.255 C 类IP段 192.0.0.0 到 223.255.255.255 A 类的默认子网掩码 255.0.0.0 一个子网最多可以容纳 1677 万个 IP B 类的默认子网掩码 255.255.0.0 一个子网最多可以容纳 6 万个 IP C 类的默认子网掩码 255.255.255.0 一个子网最多可以容纳 254 个 IP 要想在同一网段,只要网络标识相同就可以了,那要怎么看网络标识呢?首先要做的是把每段的IP转换为二进制。 (有人说,我不会转换耶,没关系,我们用 windows 自带计算器就行。打开计算器,点查看>科学型,输入十进制的数字,再点一下"二进制"这个单选点,就可以切换至二进制了。) 把子网掩码切换至二进制,我们会发现,所有的子网掩码是由一串连续的1和一串连续的0组成的 (一共4段,每段8位,一共32位数) 。 255.0.0.0 11111111.00000000.00000000.00000000 255.255.0.0 11111111.11111111.00000000.00000000 255.255.255.0 11111111.11111111.11111111.00000000 这是A/B/C三类默认子网掩码的二进制形式,其实,还有好多种子网掩码,只要是一串连续的1和一串连续的0就可以了 (每段都是8位) 。如11111111.11111111.11111000.00000000,这也是一段合法的子网掩码。子网掩码决定的是一个子网的计算机数目,计算机公式是2的m次方,其中,我们可以把m看到是后面的多少颗0。如255.255.255.0 转换成二进制,那就是11111111.11111111.11111111.00000000,后面有8个0,那m就是8,255.255.255.0 这个子网掩码可以容纳2的8次方 (台) 电脑,也就是256台,但是有两个IP是不能用的,那就是最后一段不能为0和255,减去这两台,就是254台。我们再来做一个。 255.255.248.0这个子网掩码可以最多容纳多少台电脑? 计算方法: 把将其转换为二进制的四段数字 (每段要是8位,如果是0,可以写成8个0,也就是00000000) 11111111.1111111.11111000.00000000 然后,数数后面有几颗0,一共是有11颗,那就是2的11次方,等于2048,这个子网掩码最多可以容纳2048台电脑。 一个子网最多可以容纳多少台电脑你会算了吧,下面我们来个逆向算法的题。 一个公司有530台电脑,组成一个对等局域网,子网掩码设多少最合适? 首先,无疑,530台电脑用B类IP最合适 (A类不用说了,太多,C类又不够,肯定是B类) ,但是B类默认的子网掩码是255.255.0.0,可以容纳6万台电脑,显然不太合适,那子网掩码设多少合适呢?我们先来列个公式。 2的m次方=560 首先,我们确定2一定是大于8次方的,因为我们知道2的8次方是256,也就是C类IP的最大容纳电脑的数目,我们从9次方一个一个试2的9次方是512,不到560,2的10次方是1024,看来2的10次方最合适了。子网掩码一共由32位组成,已确定后面10位是0了,那前面的22位就是1,最合适的子网掩码就是: 11111111.11111111.11111100.00000000,转换成10进制,那就是255.255.252.0。 ...

2012-09-19 · 1 min · 133 words · -

JVM 操作数栈 Operand Stack

JVM 操作数栈 Operand Stack http://denverj.iteye.com/blog/1218359 Like the local variables, the operand stack is organized as an array of words. But unlike the local variables, which are accessed via array indices, the operand stack is accessed by pushing and popping values. If an instruction pushes a value onto the operand stack, a later instruction can pop and use that value. 和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。但是和前者不同的是,它不是通过索引来访问,而是通过标准的栈操作—压栈和出栈—来访问的。比如,如果某个指令把一个值压入到操作数栈中,稍后另一个指令就可以弹出这个值来使用。 The virtual machine stores the same data types in the operand stack that it stores in the local variables: int,long, float, double, reference, and returnType. It converts values of type byte, short, and char to int before pushing them onto the operand stack. ...

2012-09-19 · 3 min · 428 words · -