1. 经过new调用结构器创立Java目标;
2. 经过Class目标的newInstance()办法调用结构器创立目标;
3. 经过Java的反序列化机制从IO流中康复目标;
4. 经过Java目标供给的clone办法仿制一个目标;
5. 根本类型及String类型,能够直接赋予直接量。
关于Java中的字符串直接量,JVM会运用一个字符串池来保存它们:当第一次运用某个直接量时,JVM会将它放入字符串池中缓存,在一般情况下,字符串池中的字符串不会被Java收回器收回,当程序再次运用该直接量时,无需重新创立一个新的字符串,而是直接让引证变量指向字符串池中现已存在的字符串。
字符串池中的字符串是不会被收回的,这是Java内存泄漏的一个原因。
假设程序需求一个字符序列会改变的字符串,那么应该考虑运用StringBuilder或StringBuffer,当然,最好还是运用StringBuilder,由于关于线程安全的StringBuffer,StringBuilder是线程不安全的,也便是说,StringBuffer中的绝大部分代码都加了synchronized修饰符。
假设你的代码地点的程序或进程是多个线程一起运转的,而这些线程会一起运转这段代码,假设每次运转成果和单线程运转成果相同,并且其他变量的值也和预期的相同,便是线程安全的,或者说,多个线程的切换不会导致该接口的履行成果存在二义性,咱们就说该接口是线程安全的。
Java是强类型言语,所谓强类型言语,一般具有两个根本特征:
1. 所有变更有必要先声明才干运用,声明变量时有必要指定该变量的数据类型;
2. 一量某个变量的数据类型确认下来,那么该变量永远只能承受该类型的数据,不能承受其他类型的数据。
当一个算术表达式中包括多个根本类型时,整个算术表达式的数据类型会自动提高,这是咱们现已知道的规则。在此之外有个特例,请看以下代码:
[java]
short sv = 5;
sv = sv - 2;
咱们一般不能了解的一个问题是:这段代码会报错。但结合数据类型的自动提高,咱们能够这样了解:sv - 2中,2是int型,所以sv - 2的成果是一个int型,所以不能赋值给sv。
再看以下代码:
[java]
short sv = 5;
sv -= 2;
假设你再用自动类型提高来了解的话,你会解释为这一段代码成果也会报错,可惜,Java中还有另一规则:复合赋值运算符包括了一个隐式的类型转化,sv -= 2其实等价于sv = (short)(sv - 2)。
显然这儿又呈现了另外一个问题:将巨大的int转化为short会出什么问题吗?且看如下代码:
[java]
short sv = 5;
sv += 9000;
咱们已知,short类型的数值范围在-32768~32767之间,所以当把9005赋值给sv时,就会呈现高位切断,sv的终究成果为24471。
由此可见,复合赋值运算符简单、便利,并且具有性能上的优势,但复合赋值运算符可能有必定的风险:它潜在的隐式类型转化可能会不知不觉中导致计算成果的高位切断。
且看以下代码:
[java]
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
ListintList = list;
for (int i = 0; i < list.size(); i++) {
System.out.println(intList.get(i));
}
当我看到这段代码的时候,我天经地义的认为这段代码是错误的,由于list里边包括的是String,不能赋值给List,而在Eclipse里边运转这段代码后,你会发现这段代码没有任何错误,能够编译,也能够运转,这便是泛型里边的圈套。在运用泛型时,要注意以下几点:
1. 当程序把一个原始类型的变量赋值给一个带泛型信息的变量时,总是能够经过编译,只是会提出一些正告,如上述代码中,ListintList = list并不会报错;
2. 当程序企图访问带泛型声明的调集的调集元素时,编译器总是把调集元素当成泛型类型处理——它并不关怀调集里调集元素的实践类型,如上述代码中,intList.get(i)的成果是一个Integer类型;
3. 当程序企图访问带泛型声明的调集的调集元素时,JVM会遍历每个调集元素自动履行强制类型转化,假设调集元素的实践类型与调集所带的泛型信息不匹配,运转时将引发ClassCastException反常,假设在上述代码的for循环中加上Integer in = intList.get(i),就会报此反常。
上面讲的是把原始类型赋值给泛型类型,假设反过来呢?且看以下代码:
[java]
Listlist = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
List li = list;
for (int i = 0; i < list.size(); i++) {
System.out.println(li.get(i));
System.out.println(li.get(i).length()); // 1)
}
你会发现1)处的代码编译错误,这是由于——把一个带泛型类型的Java变量赋值给一个不带泛型类型的变量时,Java程序会发生擦除,这种擦除不仅仅会擦除实践类型实参,还会擦除所有泛型信息,如上述代码,li.get(i)是终被当成一个Object目标运用。
Java泛型规划原则:假设一段代码在编译时体系没有发生“[unchecked]未经查看的转化”正告,则程序在运转时不会引发ClassCastException反常。
从JDK1.5开端,Java供给了三种办法来创立、发动多线程:
1. 承继Thread类来创立线程类,重写run()办法作为线程履行体;
2. 完成Runnable接口来创立线程类,重写run()办法作为线程履行体;
3. 完成Callable接口来创立线程类,重写run()办法作为线程履行体;
其中,第一种办法效果最差,它有两点坏处:
1. 线程类承继了Thread类,无法再承继其他父类;
2. 由于每条线程都是一个Thread子类的实例,因而多个线程之间同享数据比较费事。
关于第二种和第三种,它们的本质是相同的,只是Callable接口里边包括的call()办法既能够声明抛出反常,也能够拥有返回值。
无论运用哪种办法,都不要调用run()办法来发动线程:发动线程应该运用start()办法,假设程序从未调用线程目标的start()办法来发动它,那么这个线程目标将一直处于新建状态。