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 性能优化中,内存管理是一个要优先考虑的关键因素。而说到内存分配,就必然会涉及到基本类型和引用类型。 名词定义 所谓基本类型,就是 Java 语言中如下 8 种内置类型:boolean、char、byte、short、int、long、float、double。而引用类型就是那些可以通过 new 来创建对象的类型(基本上都派生自 Object)。 两种类型的存储方式 这两种类型的差异,首先体现在存储方式上。在 Java 中,引用类型的对象存储在堆(Heap)上;而基本类型的值存储在栈(Stack)上。 堆和栈的性能差异 堆和栈在性能方面差别很大。堆相对进程来说是全局的,能够被所有线程访问;而栈是线程局部的,只能本线程访问。 由于堆是所有线程共有的,从堆里申请内存要进行相关的加锁操作,因此申请堆内存的复杂度和时间开销比栈要大很多;从栈里申请内存,虽然又简单又快,但是栈的大小有限,分配不了太多内存。 为什么这样设计 James Gosling 设计 Java 时,把各种东西都放置到栈中显然不现实:一来栈是线程私有的(不便于共享),二来栈的大小是有限的,三来栈的结构也间接限制了它的用途。而都放堆里面,申请堆内存需要加锁,开销太大。如果仅仅在函数中写一个简单的 int n = 0,也要到堆里面去分配内存,性能就会很差。 最终的折中方案:把类型分为基本类型和引用类型;引用类型(Object 派生)的对象存放到堆里面;把基本类型(非 Object 派生)的值存放到栈里面。从 Java 语法上也可以看出两者的差别:引用类型可以用 new 创建对象;而基本类型则不需要用 new 来创建。 这样设计的弊端 这个折中决策带来了一些深远影响: 由于基本类型不是派生自 Object,因此不能算是纯粹的对象,使 Java 的"纯面向对象"招牌打了折扣。 出于某些场合(比如容器类)的考虑,不得不为每个基本类型加上对应的包装类(比如 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 · 260 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 · -

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 · -

int 和 Integer

int 和 Integer Java 提供两种不同的类型: 引用类型和原始类型 (或内置类型) 。Int是java的原始数据类型,Integer是java为int提供的封装类。Java为每个原始类型提供了封装类(Wrapper)。 原始类型 封装类 boolean Boolean char Character byte Byte short Short int Integer long Long float Float double Double 引用类型和原始类型的行为完全不同,并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法,它们包括: 大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始类型实例变量的缺省值与它们的类型有关。 http://www.ibm.com/developerworks/cn/java/praxis/pr8.html

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

java 基本数据类型, primitive type

java 基本数据类型, primitive type Java语言提供了八种基本类型: 六种数字类型 (四个整数型,两个浮点型) ,一种字符类型,一种布尔型。 整数: 包括 int, short, byte, long 浮点型: float, double 字符: char 布尔: boolean java.lang.String 类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,应该用StringBuffer类 (1个字节是8个bit) 整数型: byte (1字节) 、short (2字节) 、int (4字节) 、long (8字节) 浮点型: float (4字节) 、double (8字节) 布尔型: boolean (1字节) 字符型: char (2字节) boolean: boolean数据类型表示一位的信息; 只有两个取值: true和false; 这种类型只作为一种标志来记录true/false情况; 默认值是false; 例子: boolean one = true。 byte 8位有符号整数 byte是一个字节保存的,有8个位. byte取值的范围: -128—127 8位的第一个位是符号位, 0000 0001代表的是数字1 1000 0000代表的就是-1 正数最大为0111 1111,是数字127 负数最大为1111 1111,是数字-128 在java中采用的是补码的形式. ...

2012-09-19 · 2 min · 267 words · -

Java 动态方法调用

Java 动态方法调用 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://wujuxiang.blog.51cto.com/2250829/406802 在Java中,如果方法重写只是一种名字空间的编写,那么它最多是让人感到有趣,但没有实际价值,但情况并非如此。方法重写构造成了Java最大的一个概念基础: 动态方法调度 (dynamic method dispatch) 。动态方法调度是一种机制,借助于这种机制,对一个已经重写的方法的调用将在运行时,而不是在编译时解析。动态方法调度非常重要,因为这关系到Java如何实现运行多态性的问题。我们知道,超类引用变量可以引用子类对象,Java使用这个事实来解决在运行时对重写方法的调用。下面是运行原理: 当一个超类引用调用一个重写方法时,Java根据在调用时被引用对象的类型执行哪个版本的方法。换句话说,是被引用对象的类型 (不是引用变量的类型) 决定将执行哪个版本的重写方法。因此,如果说超类包含一个被子类重写的方法,那么当通过超类引用变量来引用不同类型的对象时,就会执行那个方法的不同版本。演示如下: public class ClassA { void callme(){ System.out.println(“Inside A’s callme method”); } } public class ClassB extends ClassA{ void callme(){ System.out.println(“Inside B’s callme method”); } } public class ClassC extends ClassA{ void callme(){ System.out.println(“Inside C’s callme method”); } } public class Dispatch { public static void main(String[] args) { ClassA classA = new ClassA(); ClassB classB = new ClassB(); ClassC classC = new ClassC(); ...

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

多态性 polymorphism

多态性, polymorphism, /pɑlɪˈmɔrfɪzm/ 一个接口(方法或函数)表现出不同的行为。 多态的实现方式 继承与重写(Override):子类继承父类并重写父类的方法,通过父类引用或指针调用时,会执行子类重写后的方法。 接口(Interface):实现同一个接口的不同类,可以以统一的方式调用接口方法,实际执行的是各个类自己的实现。 什么是多态 多态的概念: 多态(Polymorphism)这个概念最早来自于生物学,表示的是同一物种在同一种群中存在两种或多种明显不同的表型。比如:在南美种群中存在两种颜色的美洲虎:浅黄色的和黑色的。 而在面向对象编程思想中,这个概念表达的是具有共性的类型,在执行相同的行为时,会体现出不同的实现方式。我们可以简称为:相同的行为,不同的实现。 比如:同样看到对面过来一个美女,男人和女人的想法是不一样的。 https://hyktech.gitee.io/javatech/2017/09/01/%E5%A4%9A%E6%80%81/ 多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。 从广义上说,多态性是指一段程序能够处理多种类型对象的能力。在 c++ 语言中,这种多态性可以通过强制多态、重载多态、类型参数化多态、包含多态4种形式来实现。 类型参数化多态和包含多态统称为一般多态性,用来系统地刻画语义上相关的一组类型。重载多态和强制多态统称为特殊多态性,用来刻画语义上无关联的类型间的关系。 包含多态是指通过子类型化,1个程序段既能处理类型t的对象,也能够处理类型t的子类型s的对象,该程序段称为多态程序段。公有继承能够实现子类型。在包含多态中,1个对象可以被看作属于不同的类,其间包含关系的存在意味着公共结构的存在。包含多态在不少语言中存在,如整数类型中的子集构成1个子类型。每一个子类型中的对象可以被用在高一级的类型中,高一级类型中的所有操作可用于下一级的对象。在c++中公有继承关系是一种包含多态,每一个类可以直接公有继承父类或多个父类, 类型参数化多态是指当1个函数(类)统一地对若干类型参数操作时,这些类型表现出某些公共的语义特性,而该函数(类)就是用来描述该特性的。在类型参数化多态中,1个多态函数(类)必须至少带有1个类型参数,该类型参数确定函数(类)在每次执行时操作数的类型。这种函数(类)也称类属函数(类)。类型参数化多态的应用较广泛,被称为最纯的多态。 重载是指用同一个名字命名不同的函数或操作符。函数重载是c++对一般程序设计语言中操作符重载机制的扩充,它可使具有相同或相近含义的函数 用相同的名字,只要其参数的个数、次序或类型不一样即可 java 多态: class A { public String show(D obj) { return "A and D"; } public String show(A obj) { return "A and A"; } } class B extends A { public String show(B obj) { return "B and B"; } public String show(A obj) { return "B and A"; } } class C extends B { } class D extends B { } public class Test { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println(a1.show(b)); System.out.println(a1.show(c)); System.out.println(a1.show(d)); System.out.println(a2.show(b)); // 4. output: B and A System.out.println(a2.show(c)); // 5. output: B and A System.out.println(a2.show(d)); // 6. output: A and D System.out.println(b.show(b)); System.out.println(b.show(c)); System.out.println(b.show(d)); } } 输出 ...

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

封装

封装 封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。

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

内存分页

内存分页 内存分页, paging 为什么要分页 分段的内存碎片太大,是计算中发展过程中尝试过的方案,现在的方案是内存分页,通过某种方式,将虚拟地址映射到物理地址,映射的关系是通过一张表实现的,也就是页表。 分页机制 分页机制的思想是:通过映射,可以使连续的线性地址与物理地址相关联,逻辑上连续的线性地址对应的物理地址可以不连续。 分页的作用 - 将线性地址转换为物理地址 - 用大小相同的页替换大小不同的段 一级页表 我们把一页的大小定义为4K,那么4G就有1M个页,在32位的保护模式下,地址都是32位二进制表示的,用20位二进制定位页表,剩余的12位表示4K里面的偏移。 分页机制打开前要将页表地址加载到控制寄存器CR3中,这个过程是打开页表之前,所以存储的是物理实际地址,每个页表项对应一个物理页,通过页表项就可以访问到实际的物理地址。由于这个过程是固定的,CPU中集成了这个硬件模块,即MMU中的页部件。 二级页表 为什么要二级页表 每个进程1M个页表,每个4字节,进程多了占用的内存还是很多的。 一般进程使用的内存是远低于全部虚拟内存的。二级模式只为进程实际使用的那些虚拟内存区分配页表,既提升了效率,也减少了内存的使用量。 作者:长安 链接:https://www.zhihu.com/question/50796850/answer/654281605 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者:Ideal 链接:https://www.zhihu.com/question/50796850/answer/1449056116 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 我觉得这个问题下目前的回答并没有讲清楚分段和分页的区别,有的答案甚至有错误,我尝试给一个我认为正确的理解。要回答为什么计算机中的内存访问会有分段机制,最好的方式是回到当时首次出现分段机制的历史背景下去考虑这个问题。事实上,对于计算机领域的诸多问题,很多时候工程上的选择都是完全跟当时的历史背景联系紧密的。并且因为硬件软件两个方面在过去几十年中都经历了极速的甚至是面目全非的发展,所以如果你不回溯背景,可能永远没有办法真正理解这些选择,分段最开始是从Intel的8086CPU,受限于价格和技术水平,当时的CPU和寄存器的宽度仍然为16位。那个时候还没有演化成像现在这样如此复杂的内存管理模式,程序在访问内存的时候还是直接给出相应单元的实际物理地址。为了便利地实现多道程序并发运行,也就需要支持对各个程序进行重定位,因为如果不支持重定位,凡是涉及到内存访问的地方都需要将地址硬编码,进而必须把某个程序加载到内存的固定区间。有了分段机制,程序中只需要使用基于段的相对地址,然后更改段基址,就可以方便地对程序进行重定位。当然,在8086CPU中,分段除了服务于重定位的目的,还有其他的作用。具体地说,8086CPU的地址线宽度是20位,可寻址的最大内存空间是1MB,但寄存器这些都是16位, 它是通过段加偏移的方式生成20位的地址,从而实现对1MB内存空间的寻址的。我们经常谈的程序可执行文件的分段,例如代码段数据段这些,在最开始其实就是为了跟上面描述的硬件上的内存分段机制对应,并且逻辑上能够更清晰有序地构造程序的组织结构。所以,总结来说,分段其实是80*86系列CPU的legacy。对于现代操作系统来说,由于已经引入了分页,分段更多的是一种历史包袱,而不是能够提供多大实际作用的内存管理机制。比如,The Linux Programming Interface那本书里就谈到:Linux uses segmentation in a very limited way. In fact, segmentation and paging are somewhat redundant, because both can be used to separate the physical address spaces of processes: segmentation can assign a different linear address space to each process, while paging can map the same linear address space into different physical address spaces. 事实上,通过将 cs (代码段) 和 ds (数据段) 寄存器的值设为0,Linux实际没有使用分段而只使用了分页。因为这样内存管理会更加简单,并且由于像RISC架构的处理器只对分段提供了非常有限的支持,不使用分段会提高Linux操作系统在不同CPU架构上的可移植性。 ...

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

过程抽象 数据抽象

过程抽象 数据抽象 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。 数据抽象就是针对对象的属性,比如建立一个鸟这样的类,鸟会有以下特征,两个翅膀,两支脚,有羽毛等等特性,写成类都是鸟的属性 过程抽象就是针对对象的行为特征,比如鸟会飞,会跳等等,这些方面的就会抽象为方法,即过程,写成类都是鸟的方法 抽 象——就是把现实世界中的某一类东西,提取出来,用程序代码表示,抽象出来一般叫做类或者接口。 数据抽象——就是用代码的形式,表示现实世界中一类事物的特性,比如人的姓名,年龄等,抽象出来一般叫做属性或者成员变量等。 抽象过程——就是用代码的形式,表示现实世界中事物的一系列行为,比如人可以吃饭等,抽象出来一般叫做方法。

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

java List 排序 Collections.sort() 对 List 排序

java List 排序 Collections.sort() 对 List 排序 java.util.Comparator 接口。要实现里面的函数 int compare(Object o1, Object o2) 返回一个基本类型的整型,返回负数表示o1 小于o2,返回0 表示o1和o2相等,返回正数表示o1大于o2。 class User { String name; String age; public User(String name,String age){ this.name=name; this.age=age; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } //具体的比较类,实现Comparator接口 import java.util.Comparator; import java.util.List; import java.util.ArrayList; import java.util.Collections; public class ComparatorUser implements Comparator{ public int compare(Object arg0, Object arg1) { User user0=(User)arg0; User user1=(User)arg1; //首先比较年龄,如果年龄相同,则比较名字 int flag=user0.getAge().compareTo(user1.getAge()); if(flag==0){ return user0.getName().compareTo(user1.getName()); }else{ return flag; } } } //测试类 public class SortTest { public static void main(String[] args){ List userlist=new ArrayList(); userlist.add(new User("dd","4″)); userlist.add(new User("aa","1″)); userlist.add(new User("ee","5″)); userlist.add(new User("bb","2″)); userlist.add(new User("ff","5″)); userlist.add(new User("cc","3″)); userlist.add(new User("gg","6″)); ComparatorUser comparator=new ComparatorUser(); Collections.sort(userlist, comparator); for (int i=0;i<userlist.size();i++){ User user_temp=(User)userlist.get(i); System.out.println(user_temp.getAge()+","+user_temp.getName()); } } } //首先年龄排序,如果年龄相同,则按名字排序 "\`java 结果: 1, aa 2, bb 3, cc 4, dd 5, ee //注意:同样是5岁的人,则比较名字(ee,ff),然后排序 5, ff 6, gg http://www.blogjava.net/zygcs/archive/2008/01/17/176032.html http://muscle-liu.iteye.com/blog/157261

2012-09-16 · 1 min · 162 words · -

Spring中bean的作用域

Spring中bean的作用域 http://blog.csdn.net/ProvidenceZY/article/details/1878582 如何使用spring的作用域: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。 在spring2.0之前bean只有2种作用域即: singleton(单例)、non-singleton (也称prototype) , Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。 1、singleton作用域 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存 (singleton cache) 中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 或者 <bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/> 2、prototype prototype作用域部署的bean,每一次请求 (将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法) 都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。 (让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。) 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/> 或者 <beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/> 3、request request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例: request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置: 如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可: <web-app> … org.springframework.web.context.request.RequestContextListener … ...

2012-09-16 · 1 min · 191 words · -