它是jQuery 1.3中新增的方法,有些时候真的是非常的好用,比如做Ajax聊天的时候。下面是JQuery参考手册中的一个示例:
<p>Click me!</p>
$("p").live("click", function(){
$(this).after("<p>Another paragraph!</p>");
});
Memory of my life and idea.
<p>Click me!</p>
$("p").live("click", function(){
$(this).after("<p>Another paragraph!</p>");
});
var test = function() {
alert(this);
this.f = function() {
alert(this);
};
};
test();
var t =new test();
t.f();
Object Window
Object Object
Object Object
| 同一个类 | 同一个包 | 不同包的子类 | 不同包的非子类 |
Private | √ |
|
|
|
Default | √ | √ |
|
|
Protected | √ | √ | √ |
|
Public | √ | √ | √ | √ |
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
/** The lock protecting all mutators */
transient final ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private volatile transient Object[] array; //volatile 关键字使其每次被赋值之后都会被其他线程看到,而不会使用线程拷贝的副本。加上赋值操作本身是原子性的所以不会冲突
/**
* Gets the array. Non-private so as to also be accessible
* from CopyOnWriteArraySet class.
*/
final Object[] getArray() {
return array;
}
/**
* Sets the array.
*/
final void setArray(Object[] a) {
array = a;
}
public E get(int index) {
return (E)(getArray()[index]); //不需要同步
}
public E set(int index, E element) {final ReentrantLock lock = this.lock;
lock.lock(); //锁定,如果已被锁定则等待
try {
Object[] elements = getArray();
Object oldValue = elements[index];
if (oldValue != element) { //写入的值与原值不一样int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len); //拷贝
newElements[index] = element;
setArray(newElements);//赋值} else {// Not quite a no-op; ensures volatile write semantics
setArray(elements);}}
return (E)oldValue;
} finally {
lock.unlock();//解锁
}
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
public class SingletonAa {因为初始化依赖于static变量,而这些初始化函数在变量被初始化之前被调用了...所以会跑出NullPointException。
private static SingletonAa singletonAa = new SingletonAa();
public static String name = "sam";
public static String password;
static {
password = "tiger";
}
private SingletonAa(){
if(name.equals("sam")) System.out.println("name is ok");
if(password.equals("tiger")) System.out.println(" password is ok");
}
public static SingletonAa getInstance() {
return singletonAa;
}
}
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singletion();
}
return instance;
}
}
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
Singleton temp = new Singletion(); //防止无序写入导致的多线程问题
instance = temp;
}
}
}
return instance;
}
}
public class Singleton {起初我看到这个代码的时候还认为它不是线程安全的,因为考虑到并发情况下,instance可能被初始化多次,所以得到的并不是单例而是多个。
static class SingletonsHolder {
static Singletons instance = new Singletons();
}
public static Singletons getInstances() {
return SingletonsHolder.instance;
}
}
public class Singletons {上述代码完成的过程是:
public static boolean b = true;
private Singletons() {
System.out.println("In " + b);
if (b) {
System.out.println("Sleeping " + b);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Singletons " + b);
}
static class SingletonsHolder {
static Singletons instance = new Singletons();
}
public static Singletons getInstances() {
System.out.println("getInstances");
return SingletonsHolder.instance;
}
public static void main(String[] args) throws InterruptedException {
System.out.println("Start");
new Thread() {
public void run() {
System.out.println(Singletons.getInstances());
}
}.start();
Thread.sleep(1000);
Singletons.b = false;
new Thread() {
public void run() {
System.out.println("Two Start");
System.out.println(Singletons.getInstances());
System.out.println("Two End");
}
}.start();
System.out.println("End ");
}
}
Start
getInstance
In true
Sleeping true
等待了1秒
End
Two Start
getInstance
等待了4秒
Singletons false可见最终得到的单例是同一个。分析我们知道测试的执行过程为:
org.my.test.singleons.Singletons@1a758cb
org.my.test.singleons.Singletons@1a758cb
Two End
Long start = System.currentTimeMillis();
String s = "1";
for (int i=1;i<1000000000;i++) {
if (s.equals("1"))
s = "2"; //11710,11672,11678
s = (s.equals("1"))? "2":s; //11147,11137,11269
s = (s.equals("1"))? "2":"1";//9539,9528,9647
}
Long end = System.currentTimeMillis();
System.out.println(end - start);
转自:http://hxraid.javaeye.com/blog/522167
作者:Java标准类库有几千个类,唯独String不太一样。为什么这么说?就因为每次上网冲杯Java时,都能看到关于String无休无止的争论。还是觉得有必要让这个讨厌又很可爱的String美眉,赤裸裸的站在我们这些Java色狼面前了。嘿嘿....
众所周知,String是由字符组成的串,在程序中使用频率很高。Java中的String是一个类,而并非基本数据类型。 不过她却不是普通的类哦!!!
【镜头1】 String对象的创建
1、关于类对象的创建,很普通的一种方式就是利用构造器,String类也不例外:
String s=new String("Hello world");
问题:参数"Hello world"是什么东西,也是字符串对象吗?莫非用字符串对象创建一个字符串对象???
2、当然,String类对象还有一种大家都很喜欢的创建方式:
String s="Hello world";
问题:有点怪呀,怎么与基本数据类型的赋值操作(int i=1)很像呀???
在开始解释这些问题之前,我们先引入一些必要的知识:
(1) Java class文件结构
我们都知道,Java程序要运行,首先需要编译器将源代码文件编译成字节码文件(也就是.class文件)。然后在由JVM解释执行。
class文件是8位字节的二进制流 。这些二进制流的涵义由一些紧凑的有意义的项 组成。比如class字节流中最开始的4个字节组成的项叫做魔数 (magic),其意义在于分辨class文件(值为0xCAFEBABE)与非class文件。class字节流大致结构如下图左侧。
其中,在class文件中有一个非常重要的项——常量池 。这个常量池专门放置源代码中的常量信息(并且不同的常量存放在不同标志的常量表中)。如上图右侧是HelloWorld代码中的常量表 (HelloWorld代码如下),其中有四个不同类型的常量表(四个不同的常量池入口)。关于常量池的具体细节,请参照《深入Java虚拟机》第二版第 6章。
public class HelloWorld{ void hello(){ System.out.println("Hello world"); } }
显然,HelloWorld代码中的"Hello world"被编译之后,可以清楚的看到存放在了class二进制流的常量池项中(上图右侧红框区域)。并且我们还发现常量池中专门有为String类型设置的常量表 。也就是说,在编译阶段,就已经将代码中的这种("****")形式作为了字符串常量存放在常量池中了 ,这一点和下面代码中出现的整形常量(142),浮点型常量(12.1)等的处理是没有区别的。
String s="Hello world";
int intData=142;
double dblData=12.1;
(2) Java虚拟机运行class文件
当Java虚拟机需要运行一个class文件时,它首先会用类装载器装载进class文件。当然也就需要在内存中存放许多东西。比如class的二进制字 节码。还有需要存储class文件中得到的其他信息,比如程序创建的对象,传递给方法的参数,返回值,局部变量等等。怎么多麻烦的数据当然需要管 理,JVM会把这些东西都组织到几个“运行时数据区 ”中。这些数据区中就有我们动不动就谈到的"堆"呀,"栈"呀什么的?想要详细了解这部分东西可以看《深入Java虚拟机》第二版第5章。
在这里我只谈谈“方法区 ”这个运行时数据区。在Java虚拟机中,关于被装载类型的信息会在一个逻辑上被称为"方法区"的内存中,当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入该文件。紧接着虚拟机提取其中的类型信息,并将这些信息存储到方法区中。
方法区中的这些类型信息是很有用的,比如:这个类型的全限定名(net.single.HelloWorld);这个类型的直接超类的全限定名;这个类型 是类类型还是接口类型;这个类型的访问修饰符(public,final,static)等。还有两个大家都很熟悉的引用:指向类ClassLoader 的引用和指向Class类的引用。这是Java反射机制能够运行的关键所在。这里我们要提到的是一个非常重要的信息——该类型的常量池 。
上面提到的,class文件结构中的常量池二进制流就被JVM存储在方法区中进行管理。当程序运行时需要使用到常量值的时候,直接在方法区常量池所在的内存中寻找就可以了。
(3) 操作码助忆符指令集
将String s=new String("Hello world");编译成class文件后的指令(由eclipse打开class文件查看的):
0 new java.lang.String [15] 3 dup 4 ldc <String "Hello word"> [17] 6 invokespecial java.lang.String(java.lang.String) [19] 9 astore_1 [s] 10 retur
下面通俗的解释一下这些指令,详细见《深入Java虚拟机》第二版附表:按操作码助忆符排列的指令集。
★ new指令: 在内存的堆区域中为新字符串对象分配足够大的空间,并将对象的实例变量设为默认值。
★ ldc指令:在内存的方法区常量池中找到String类型字面值常量表 的入口,然后定位到的"Hello word"所在内存中的位置。
★ invokespecial指令:调用指定的类构造器(这里调用的是String(String)这一个构造器。将ldc指令所找到的"Hello word"的内容传入到new指令所开辟在堆中的字符串对象中。
★ astore_1:将new指令所开辟堆的内存位置存入局部变量s中 。
将String s="Hello world";编译成class文件后的指令:
0 ldc <String "Hello world"> [15] 2 astore_1 [str] 3 return
★ ldc指令:在内存的方法区常量池中找到String类型字面值常量表 的入口,然后定位到的"Hello word"所在内存中的位置(如果常量池中没有"Hello word",则会在其中添加一个"Hello word")。
★ astore_1:将ldc指令定位到的常量池中的位置存入局部变量s中 。
镜头总结: String类型脱光了其实也很普通。真正让她神秘的原因就在于String类型字面值常量表 的存在。
相关问题解决
(问题1) 代码1 代码2
String sa=new String("Hello world"); String sc="Hello world";
String sb=new String("Hello world"); String sd="Hello world";
System.out.println(sa==sb); // false System.out.println(sc==sd); // true
变量sa,sb中存储的内容是JVM在堆中开辟的两个String对象的内存地址。==比较就是sa,sb变量存储的内容,也就是两个不同的内存地址,当然是false;
变量sc,sd中存储的内容也是地址,但却都是方法区常量池中"Hello word"所在的地址,自然一样。
(问题2) 代码1 代码2
String sa = "ab"; String sc="ab"+"cd";
String sb = "cd"; String sd="abcd";
String sab=sa+sb; System.out.println(sc==sd); //true
String s="abcd";
System.out.println(sab==s); // false
代码1中sa+sb被编译以后使用的是StringBuilder.append(String)方法。JVM会在堆中创建一个 StringBuilder类,将sa所指向常量池中的内容"ab"传入,然后调用append(sb所指向的常量池内容)完成字符串合并功能,最后将堆 中StringBuilder对象的地址赋给变量sab。而s存储的是常量池中"abcd"的地址。sab与s地址当然不一样了。
代码2中"ab"+"cd"会直接在编译阶段就合并成常量"abcd",所以相同的字符串在常量池中的地址也相同了。
【镜头二】 String三姐妹(String,StringBuffer,StringBuilder),谁更性感?
String不用多说,扒的差不多了。但他还有两个妹妹StringBuffer,StringBuilder长的也不错哦!我们首先对这三姐妹下个定义:
String(大姐,出生于JDK1.0时代) 不可变字符序列
StringBuffer(二姐,出生于JDK1.0时代) 线程安全的可变字符序列
StringBuilder(小妹,出生于JDK1.5时代) 非线程安全的可变字符序列
讨论1、StringBuffer与String的可变性问题。
我们先看看这两个类的简要源代码:
//String public final class String { private final char value[]; public String(String original) { // 把原字符串original切分成字符数组并赋给value[]; } } //StringBuffer public final class StringBuffer extends AbstractStringBuilder { char value[]; //继承了父类AbstractStringBuilder中的value[] public StringBuffer(String str) { super(str.length() + 16); //继承父类的构造器,并创建一个大小为str.length()+16的value[]数组 append(str); //将str切分成字符序列并加入到value[]中 } }
很显然,String和StringBuffer中的value[]都用于存储字符序列。但是,
(1) String中的是常量(final)数组,只能被赋值一次。
比如:new String("abc")使得value[]={'a','b','c'},之后这个String对象中的value[]再也不能改变了。这也正是大家常说的,String是不可变的原因 。
注意:这个对初学者来说有个误区,有人说String str1=new String("abc"); str1=new String("cba");不是改变了字符串str1吗?那么你有必要先搞懂对象引用和对象本身的区别。
(2) StringBuffer中的value[]就是一个很普通的数组,而且可以通过append()方法将新字符串加入value[]末尾。这样也就改变了value[]的内容和大小了。
比如:new StringBuffer("abc")使得value[]={'a','b','c','',''...}(注意构造的长度是str.length()+16)。如果再将这个对象append("abc"),那么这个对象中的value[]={'a','b','c','a','b','c',''....}。这也就是为什么大家说 StringBuffer是可变字符串 的涵义了。
从这一点也可以看出,StringBuffer中的value[]完全可以作为字符串的缓冲区功能。
String s1=new String("aaa");
StringBuffer sb1=new StringBuffer(); //一个字符串缓冲区
sb1.append(s1);//将字符串s1加进缓冲区
注意,讨论String和StringBuffer可不可变。本质指对象内部的value[]字符数组可不可变,而不是对象引用可不可变。
讨论2、StringBuffer与StringBuilder的线程安全性问题
StringBuffer和StringBuilder可以算是双胞胎了,这两者的方法没有很大区别。但在线程安全性方面,StringBuffer允许多线程进行字符操作。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。
有多线程编程经验的程序员应该知道synchronized。这个关键字是为线程同步机制 设定的。我简要阐述一下synchronized的含义:
每一个类对象都对应一把锁,当某个线程A调用类对象O中的synchronized方法M时,必须获得对象O的锁才能够执行M方法,否则线程A阻塞。一旦 线程A开始执行M方法,将独占对象O的锁。使得其它需要调用O对象的M方法的线程阻塞。只有线程A执行完毕,释放锁后。那些阻塞线程才有机会重新调用M方 法。这就是解决线程同步问题的锁机制。
了解了synchronized的含义以后,大家可能都会有这个感觉。多线程编程中StringBuffered比StringBuilder要安全多了 ,事实确实如此。如果有多个线程需要对同一个字符串缓冲区进行操作的时候,StringBuffer应该是不二选择。
注意:是不是String也不安全呢?事实上不存在这个问题,String是字符串常量,不可变。线程对于String对象只能读取,无法修改。试问:还有什么不安全的呢?
讨论3、String和StringBuffer的效率问题(这可是个热门话题呀!)
首先说明一点:StringBuffer和StringBuilder可谓双胞胎,StringBuilder是1.5新引入的,其前身就是StringBuffer。在Core Java editior 7 中文版P611页中有这么一句话: StringBuffer比StringBuilder的效率稍低 。
我们用下面的代码运行1W次字符串的连接操作,测试String,StringBuffer所运行的时间。
//测试代码 public class RunTime{ public static void main(String[] args){ //位置1 long beginTime=System.currentTimeMillis(); for(int i=0;i<10000;i++){ //位置2 } long endTime=System.currentTimeMillis(); System.out.println(endTime-beginTime); } }
(1) String常量与String变量的"+"操作比较
首先声明两个概念:String str="Heart"中"Heart"是String常量(存放在常量池中);而str则是String变量,是String对象的引用。
▲测试①代码: (测试代码位置1) String str="";
(测试代码位置2) str="Heart"+"Raid";
[耗时: 0ms]
▲测试②代码 (测试代码位置1) String s1="Heart";
String s2="Raid";
String str="";
(测试代码位置2) str=s1+s2;
[耗时: 15—16ms]
结论:String常量的“+连接” 稍优于 String变量的“+连接”。
原因:测试①的"Heart"+"Raid"在编译阶段就已经连接起来,并形成了一个新的字符串常量"HeartRaid"。运行阶段只需要 将"HeartRaid"存入常量池。循环1W次也只不过将常量池中"HeartRaid"的地址取出1W次赋值给String对象的引用而已。
测试②在编译阶段,编译器并不知道s1和s2代表什么,它会将这句话编译成几个指令,大体上是这样的。
首先:StringBuilder temp=new StringBuilder(s1),
然后:temp.append(s2)
最后:str=temp.toString();
我们发现,虽然在中间的时候也用到了append()方法,但是在开始和结束的时候分别创建了StringBuilder和String对象。可想而知:调用1W次,是不是就创建了1W次这两中对象呢?不划算。
不言而喻:String变量的"+"连接操作比String常量操作使用的更加广泛。
(2)String对象的"累+"连接操作与StringBuffer对象的append()累和连接操作比较。
▲测试①代码: (代码位置1) String s1="Heart";
String s="";
(代码位置2) s=s+s1;
[耗时: 4200—4500ms]
▲测试②代码 (代码位置1) String s1="Heart";
StringBuffer sb=new StringBuffer();
(代码位置2) sb.append(s1);
[耗时: 0ms(当循环100000次的时候,耗时大概16—31ms)]
结论:StringBuffer的append()累和连接 远好于 String对象的"累+"连接
原因:测试①中s=s+s1我们知道编译器也会使用StringBuilder的append方法,但是首先编译器会将new StringBuilder存放s,然后在通过 StringBuilder.append(s1),最后在new一个新的String对象存放 StringBuilder的连接后的内容 。试想这个过程一次就需要创建一个新的String并赋值给引用s,10000次就需要创建了1W次新String对象。正式因为String中的value[]数组不可变,只能不停的创建新的String来存放变化中的字符串。效率可想而知了。
测试②中sb.append(s1);只需要将自己的value[]数组不停的扩大来存放s1即可。无需在堆中创建一大堆的对象。效率高就不足为奇了。
不言而喻:大规模累加字符串的时候,StringBuffer就比她姐姐不知道强多少倍了。
镜头总结: (1) 在编译阶段就能够确定的字符串常量,完全没有必要创建String或StringBuffer对象。直接使用字符串常量的"+"连接操作效率最高。
(2)否则,StringBuffer对象的append效率要高于String对象的"+"连接操作。
(3) intern()方法很有用。
当调用String 对象的intern方法时,如果池已经包含一个等于此对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
也就是如果我们需要使用new关键字来创建很多内容重复的字符串的话,使用String.intern()方法可以提高效率。
1. 数据截断:
由于long类型变量的运算(赋值、比较、移位等)产生。long定义在x86上为32bits,而在ia64上为64bits.容易在与int型变量运算时出现异常。
处理方法:尽量避免不同类型变量间的运算,避免将长度较长的变量赋值到较短的变量中,统一变量长度可以解决这个问题。简单的对于32位转移到64位可以将所有long定义转换为int定义。
2. 指针存储:
在x86平台下,习惯使用int来存储指针,并将指针直接参与到int型的运算中,而64位平台下指针大小为64bits,无法存储到int中。对指针的运算也可能会因为数据长度的不一致导致异常。
处理方法:修改用于存储传递指针的变量为intptr_t 类型定义,以保证平台兼容性
3. 不规范的结构:
未命名或为指定数量的成员可能会出现异常
处理方法:命名未命名的成员,声明类型符号,将long型定义转为int型。
4. 代码中的直接数
直接使用16进制数字进行赋值时(一般会隐含假设该变量为32位变量的前提) 可能出现异常。使用数字定义数据大小,进行移位运算时会出现异常。
处理方法:检查代码中的直接数字是否有表示32位有关的各种形式,如4,32, 0x7fffffff等,替换为宏定义。
编写代码时注意可移植化:
1. 在32位与64位下使用同样的头文件
2. 使用严禁的格式定义,如:用off_t定义偏移量,用fpos_t定义文件位置, intptr_t定义指针
3. 使用<intypes.h>中定义的整数类型,不使用int,long,long long的传统定义方式。使用带有整形标示符参数的printf函数,不使用%d,%ld的格式化方式。
4. 使用固定宽度或宏定义的整数类型,数字,掩码
5. 对整形变量作边界检查。
6. 32位与64位进程共享内存操作时,使用64位作为操作字长。
转自:http://www.cnblogs.com/aming/archive/2008/10/27/1320277.html
1、typeof 运算符把类型信息以字符串形式返回。typeof 返回六种可能的值:“数字类型”、“字符串类型”、“布尔型”、“对象类型”、“函数类型”和“未定义类型”。
但对所有的对象和数组类型返回的都是"object",所以它只在区别对象和原始类型的时候才有用。要区一种对象类型和另一种对象类型,必须使用其他的方法。如:instanceof运算符和constructor属性。
2、instanceof运算符。如果 object 是 class 或构造函数的实例,则 instanceof 运算符返回 true。如果 object 不是指定类或函数的实例,或者 object 为 null,则返回 false。
那么,B类由当前Classloader,也就是AClassloader装载。同样的,修改上述的foo方法,其实现改为:
Class clazz = Class.forName("foo.B");
最终获取到的clazz,也是由AClassLoader所装载。
根 (Bootstrap) 装载器:该装载器没有父装载器,它是 JVM 实现的一部分,从 sun.boot.class.path 装载运行时库的核心代码。
扩展 (Extension) 装载器:继承的父装载器为根装载器,不像根装载器可能与运行时的操作系统有关,这个类装载器是用纯 Java 代码实现的,它从 java.ext.dirs ( 扩展目录 ) 中装载代码。
系统 (System or Application) 装载器:装载器为扩展装载器,我们都知道在安装 JDK 的时候要设置环境变量 (CLASSPATH ) ,这个类装载器就是从 java.class.path(CLASSPATH 环境变量 ) 中装载代码的,它也是用纯 Java 代码实现的,同时还是用户自定义类装载器的缺省父装载器。
<div id=”header”>顶部区域</div>
<div id=”mainer”>
<h1>使用负边距创建自适应宽度的流体布局</h1>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
</div>
<div id=”sideBar”>
<h2>最新文章</h2>
<ul>
<li>最新文章一</li>
<li>最新文章二</li>
<li>最新文章三</li>
</ul>
</div>
<div id=”footer”>底部区域</div>
body,p,h1,h2,ul {
margin:0;padding:0;
}
#header {
background-color: #A8A754;
}
#footer {
background-color: #A8A754;
clear: both;
}
#mainer {
width: 100%;
margin-right: -250px;
float: left;
}
#sideBar {
float: right;
width: 250px;
}
<div id=”mainer”>
<div id=”main”>
<h1>使用负边距创建自适应宽度的流体布局</h1>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
</div>
</div>
#sideBar {
color: #FFF;
background-color: #36361A;
}
#main {
margin-right: 250px;
background-color: #616030;
}
#mainer {
background: url(bj1.jpg) repeat-y right bottom;
}
<div id=”header”>顶部区域</div>
<div id=”wrapper” class=”mid”>
<div id=”mainer”>
<div id=”main”>
<h1>使用负边距创建自适应宽度的流体布局</h1>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
</div>
</div>
<div id=”sideBar”>
<h2>最新文章</h2>
<ul>
<li>最新文章一</li>
<li>最新文章二</li>
<li>最新文章三</li>
</ul>
</div>
<div class=”clear”></div>
</div>
<div id=”footer”>底部区域</div>
#wrapper {width: 92%;}
.clearing {clear: both;}
.mid {margin:0 auto;}
<div id=”header” class=”mid”>顶部区域</div>
<div id=”wrapper” class=”mid”>
<div id=”mainer”>
<div id=”main”>
<div id=”leftBar”>
<h2>栏目标题</h2>
<ul>
<li>文章标题</li>
<li>文章标题</li>
<li>文章标题</li>
</ul>
</div>
<div id=”inmain”>
<h1>使用负边距创建自适应宽度的流体布局</h1>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
<p>随着越来越大的浏览器的出现及普及,网站界面如何能满足不同分辨率浏览器使用者的浏览需求,逐渐成为前端开发工程师必须面对的问题。采 用百分比进行架构是个不错的主意。以往我们进行这类架构都是使用table表格。但,其实使用很小的技术就可以创建出符合WEB标准化的自适应布局。 </p>
</div>
</div>
</div>
<div id=”sideBar”>
<h2>最新文章</h2>
<ul>
<li>最新文章一</li>
<li>最新文章二</li>
<li>最新文章三</li>
</ul>
</div>
<div class=”clear”> </div>
</div>
<div id=”footer” class=”mid”>底部区域</div>
#main {
margin-right: 250px;
background: url(bj2.jpg) #616030 repeat-y left bottom;
}
#leftBar {
float: left;
width: 150px;
}
#inmain {
margin-left: 150px;
}
1、完全隐藏
在<boby>里加入scroll="no",可隐藏滚动条;
<boby scroll="no">
2、在不需要时隐藏
指当浏览器窗口宽度或高度大于页面的宽或高时,不显示滚动条;反之,则显示;
<boby scroll="auto">
3、样式表方法
在<boby>里加入style="overflow-x:hidden",可隐藏水平滚动条;加入style="overflow-y:hidden",可隐藏垂直滚动条。
这种方法在页面头部为:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">这种兼容模式下是不行的,其它的没试过,最后终于找到了正确的方法:
被包含页面里加入
<style>
html { overflow-x:hidden; }
</style>
有一段解释是这样说的:body{ overflow-x:hidden; }在标准 DTD 下是不可以的。
4、另一种方法
<style type="text/css">
body {
overflow-x:hidden; /*隐藏水平滚动条*/
overflow-y:hidden; /*隐藏水平滚动条*/
}
</style>
此方法在页面头部为:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">这种兼容模式下也是不行的。
问题二:如何使firefox始终显示滚动条?<style type="text/css">
html {
overflow-x:hidden; /*隐藏水平滚动条*/
overflow-y:hidden; /*隐藏水平滚动条*/
}
</style>
html {
overflow:-moz-scrollbars-vertical;
}
body, html {
min-height:101%;
}
int indexFor(int h, int length)
{
return h & length;
}
转自:http://www.javaeye.com/topic/401478
理解 Java 的 GC 与 幽灵引用
Java 中一共有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵),
这 4 种类型的引用与 GC 有着密切的关系, 让我们逐一来看它们的定义和使用场景 :
1. Strong Reference
StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收
@Test public void strongReference() { Object referent = new Object(); /** * 通过赋值创建 StrongReference */ Object strongReference = referent; assertSame(referent, strongReference); referent = null; System.gc(); /** * StrongReference 在 GC 后不会被回收 */ assertNotNull(strongReference); }
2. WeakReference & WeakHashMap
WeakReference, 顾名思义, 是一个弱引用, 当所引用的对象在 JVM 内不再有强引用时, GC 后 weak reference 将会被自动回收
@Test public void weakReference() { Object referent = new Object(); WeakReference<Object> weakRerference = new WeakReference<Object>(referent); assertSame(referent, weakRerference.get()); referent = null; System.gc(); /** * 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收 */ assertNull(weakRerference.get()); }
WeakHashMap 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry
@Test public void weakHashMap() throws InterruptedException { Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>(); Object key = new Object(); Object value = new Object(); weakHashMap.put(key, value); assertTrue(weakHashMap.containsValue(value)); key = null; System.gc(); /** * 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理 */ Thread.sleep(1000); /** * 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry */ assertFalse(weakHashMap.containsValue(value)); }
3. SoftReference
SoftReference 于 WeakReference 的特性基本一致, 最大的区别在于 SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用
@Test public void softReference() { Object referent = new Object(); SoftReference<Object> softRerference = new SoftReference<Object>(referent); assertNotNull(softRerference.get()); referent = null; System.gc(); /** * soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用 */ assertNotNull(softRerference.get()); }
4. PhantomReference
作为本文主角, Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同, 因为它的 get() 方法永远返回 null, 这也正是它名字的由来
@Test public void phantomReferenceAlwaysNull() { Object referent = new Object(); PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>()); /** * phantom reference 的 get 方法永远返回 null */ assertNull(phantomReference.get()); }
诸位可能要问, 一个永远返回 null 的 reference 要来何用, 请注意构造 PhantomReference 时的第二个参数 ReferenceQueue(事实上 WeakReference & SoftReference 也可以有这个参数),
PhantomReference 唯一的用处就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中.
5. RererenceQueue
当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.
@Test public void referenceQueue() throws InterruptedException { Object referent = new Object(); ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue); assertFalse(weakReference.isEnqueued()); Reference<? extends Object> polled = referenceQueue.poll(); assertNull(polled); referent = null; System.gc(); assertTrue(weakReference.isEnqueued()); Reference<? extends Object> removed = referenceQueue.remove(); assertNotNull(removed); }
6. PhantomReference vs WeakReference
PhantomReference 有两个好处, 其一, 它可以让我们准确地知道对象何时被从内存中删除, 这个特性可以被用于一些特殊的需求中(例如 Distributed GC, XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作).
其二, 它可以避免 finalization 带来的一些根本性问题, 上文提到 PhantomReference 的唯一作用就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中, 但是 WeakReference 也有对应的功能, 两者的区别到底在哪呢 ?
这就要说到 Object 的 finalize 方法, 此方法将在 gc 执行前被调用, 如果某个对象重载了 finalize 方法并故意在方法内创建本身的强引用, 这将导致这一轮的 GC 无法回收这个对象并有可能
引 起任意次 GC, 最后的结果就是明明 JVM 内有很多 Garbage 却 OutOfMemory, 使用 PhantomReference 就可以避免这个问题, 因为 PhantomReference 是在 finalize 方法执行后回收的,也就意味着此时已经不可能拿到原来的引用, 也就不会出现上述问题, 当然这是一个很极端的例子, 一般不会出现.
7. 对比
taken from http://mindprod.com/jgloss/phantom.html
Soft vs Weak vs Phantom References | ||||
---|---|---|---|---|
Type | Purpose | Use | When GCed | Implementing Class |
Strong Reference | An ordinary reference. Keeps objects alive as long as they are referenced. | normal reference. | Any object not pointed to can be reclaimed. | default |
Soft Reference | Keeps objects alive provided there’s enough memory. | to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key. | After a first gc pass, the JVM decides it still needs to reclaim more space. | java.lang.ref.SoftReference |
Weak Reference | Keeps objects alive only while they’re in use (reachable) by clients. | Containers that automatically delete objects no longer in use. | After gc determines the object is only weakly reachable | java.lang.ref.WeakReference java.util.WeakHashMap |
Phantom Reference | Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use offinalize()) | Special clean up processing | After finalization. | java.lang.ref.PhantomReference |