5.0
新特性:
前提:
1.
JVM
没有变
,
编译器改变
2.
逐渐和
C++
融合接近(很多开始被遗弃的
C++
元素又被捡了回来)
3.
程序员开发越发的简单了
5
小点:
1
自动封装和自动解封(简单类型和封装类型之间),但只是在必要的时候进行,比如向上就近原则中
public static void method(Byte b){}:
调用这个方法的时候不会像上就近调用
int
,而是直接调用这个方法。
Integer i = 3 // OK
封箱
int i = new Integer(3) // OK
解箱
i++ ; // OK ,i
是
Integer
在方法中的参数也可以自动的封箱解箱,但是如果存在两个方法:
方法重载依然存在:
public static void method( Integer I ) {
…
}
public static void method( int I ) {
…
}
这个时候调用
method( 10 ) //
会调用第二个方法,因为封箱和解箱都是在迫不得已的情况下才会被调用。
public static void method( Byte b ) {
…
}
public static void method( short s ) {
…
}
这个时候调用
byte b = 1 ; method( byte ) //
会调用第二个方法,因为封箱和解箱都是在迫不得已的情况下才会被调用。
同样存在问题:拿
byte
举例:
byte : 256
种(
1
个字节)
然而
Byte : 257
种(多了一个
null
)
所以如果
Integer I = null ; int i = I ; //
会有空指针异常
封装类有个重要的特性:就是封装
0
自动解箱要注意的:
Byte b = null;
Byte b = 1;
int i = 0;
(默认
i=0
),有二义性,究竟
0
是否是有效数字
0
,还是没有赋值而使用默认给得值;
所以此时用
Integer
就可以避免这样的二义性。
例如:在
hibernate
中使用
Long
而不是
long
去设定
ID
的类型,则
hibernate
会自动检查类型是否是有效数字
2
import
System.out
中的
out
是
System
类得公开静态属性
静态引入:引入一个类里面的静态成员,则访问的时候可以不写类名直接调用静态成员
import static java.lang.System.*;
表示引入
System
中的所有静态属性,则在下面使用的时候
out.println(...);
insert
可以简化更多
因为可以加入包是静态的方法直接使用
例:
import
static
java.lang.System.*;
public class Test {
public static void main(String[] args) {
out.println("sdsd");
}
}
3
新的遍历方法而且非常的方便
for/in loop
使用该
loop
得对象必须实现
Interable
接口
例:
String ss[] = {
“
test
”
,
”
text
”
};
For(String s:ss){
System.out.ptintln(s);
}
4
变常参数
public static void m ( String
…
s)
通过编译器的帮忙可以简化很多,比如反射中就不用再把
String.class
先封装在
Class[]
中了
而可以直接的是用。
但是需要注意在一个方法中只能有一个
String
…
s
,其前面可以跟别的类型参数如
int i
,
String
…
s
还有就是如果有两个以上的参数
String
…
s
必须放在最后参数上。
.
先绝对匹配,如果没有匹配的再去调用
.
变参和数组不能同时存在
,
变参即数组
.
不能同时存在多个
...
,一个方法可以有且只能有一个变参,且该变参只能是参数表中的最后一个
5
格式化输出
:
System.out.printf(
“
%d
”
, 4 )
;
完全符合
C
的习惯风格,是很有用的东西。格式在
API
中写的十分的详细。
java.util.Formatter
类
--
〉格式化输出。
java,util,Scanner
类
--
〉格式化输入。融合了
BufferedReader+StringTokinizer
的功能
四大块
:
1.
★
枚举
(enum)
(一种数据类型)
java.lang.Enum
对象要用大写来写
其实
enum
可以用
class
来实现:
Class Season {
public static final Season SPRINT = new Season() ; //
这就是制定的对象
private Season() { } //
切记把构造方法写成私有
}
可以很好的控制参数的种类和数量,保证必须按照程序员安排的选择。
提高安全性,避免了无谓的异常抛出。
同样可以排序:通过
CompareTo()
方法
直接通过
类名
.
对象
选择所要的对象,而这些对象是程序员写好的,只能是他定义的那几个对象。
类名
[] c =
类名
.values()
;
可以得到所有的对象。
Enum
中有个很诡异的事情,咱们可以理解
enum
ó
final c lass
但是
enum
中却可以有抽象方法,而这些抽象方法只能通过定义好的几个对象来实现,而且只能通过匿名的内部类的方法来实现。
★
枚举是一个数据类型
,
是一个
final
类
,
不能有子类
类型不安全的枚举类型:
公开静态常量
类型安全的枚举模式:
将公开静态常量作为
public
,将构造方法私有,实现枚举类型
java 5.0
引入的新类:
java.lang.Enum
★
实现一个枚举类型,调用该类的
values()
方法,则返回枚举值得数组
final class Season{ //
自己实现的枚举类
public static final Season SPRING = new Season("
春
");
public static final Season SUMMER = new Season("
夏
");
}
★
用枚举类
:
enum Season2{
SPRING(), //
把参数写在
()
里面
SUMMER(); //
枚举值和属性之间用
;
隔开
private String name;
private Season2(String name){
//
此处不能写
public
,必须是私有的,不写就可以,默认就是
private
this.name = name;
}
public String getName(){
return this.name;
}
}
★
.
一个枚举值就是一个枚举对象,构造一个枚举值就是调用相应的构造参数
★★
.final
里面不能有枚举类型,枚举本来是
final
但是隐含的可以用匿名内部类去继承,里面却可以有
abstract.
例
: enum Operation{
ADD{
public abstract double caculator(double d1,double d2){
return d1+d2;
}
},
//
相当于隐含有一个匿名内部类继承了父类
Operation
,
Operation
类已经成为父类,
ADD
其实是匿名内部类的对象
SUB,
MUL,
PROVIDE;
//
抽象方法要求每个枚举值去实现该方法
public abstract double caculator(double d1,double d2){
}
public static void main(String args[]){
for(Operation o:)
}
}
2.
泛型:(编译时信息)
★
很好的解决了集合中对象很难管理其类型的难题。
List<Object> l = new ArrayList<String>() ; //
这是错误的这里不存在多态
List<String> l = new Arraylist<String>() ; // OK
泛型的通配符
<?>
List < ? extends Number >
表示可以是
Number
类和其子类
List < ? super Number >
表示可以使
Number
类和其父类
public static < E > void m( E[] os , List<E> ls )
这里的
<E>
很像
C++
中的模版
★
ArrayList
比较数组是类型不安全的,指得是里面的类型强转时有可能转换错误
public class TestGenerics1{
public static void main(String args[]){
List<String> l = new ArrayList<String>();
l.add("abc");
//l.add(123);
//
此处会报错,泛型要求不能放入非字符串
l.get(0);
//
取得时候也不需要类型转换
for(String s:l){ //
用
for/in loop
打印出
list
里面的东西
System.out.println(s);
}
List<List> l2 = new ArrayList<List>();
L2.add(new ArrayList());
L2.add(new LinkedList());
L2.add(new Vector());
L2.add(new HashSet());
//
以上都是正确的
Set<Number> s = new HashSet<Number>();
s.add(1.2);
Map<String,Integer> m = new HashMap<String,Integer>();
m.put(
“
A
”
,65);
//
不用强制类型转换了,使用了自动解箱
//List<Object> ll = new ArrayList<String>();
|
不能这样写,因为对象变量的泛型和对象的泛型必须是一致的,不存在多态
|
如果这句话对的话,
String
泛型就没用了
} |
} |
-------------|--------------------------------------------------------
/|/
例:
import static java.lang.System.*;
public class TestGenerics2{
public static void main(String args[]){
List<String> l1= new ArrayList<String>();
l1.add("abc");
List<Number> l2 = new ArrayList<Number>();
l2.add(23);
List<Integer> l3 = new ArrayList<Integer>();
l3.add(23);
List<Object> l4 = new ArrayList<Object>();
l4.add("123");
l4.add(456);
print(l1);
//
如果下面
print
方法的参数是某一个固定类型的话,或者是
Object,
这块就不能这样写
,
出错
print(l2);
}
/
static void print(List<?> l){
// <?>
是泛型的通配符,表示什么类型都可以,写
Object
的话就写死了,上面的调用就会报错
for(Object o:l){
out.println(o);
}
}
/
//
如果要
l1,l4
不可以调用,
l2,l3
可以调用则可以
static void print(List<? extends Number> l){}
//<? extends Number>
带限制范围的泛型通配符
,
表示
?
是
Number
得子类
/
//
如果表示都实现了某个接口,依然用
extends
static void print(List<? extends comparable> l){}
/
//
如果要
l2,l4
可以调用,
l1,l3
不可以调用则可以
static void print(List<? super Number> l){}
//<? super Number>
表示
?
是
Number
得父类
}
★
泛型方法,在修饰符和返回值之间写泛型
static void copyArrayToList(Object[] os,List<?> ls){
for(Object o:os){
ls.add(o);
//
报错,因为
os
放入
List
,运行的时候
List
不知道究竟是什么类型
}
}
正确的是:
static
<E>
void copyArrayToList(
E
[] os,List
<E>
ls){
//
两个参数:一个
E
类型的数组,一个存放
E
对象的
List
//
必须要保证数组的类型和泛型的类型时一样的,每个数组是字符串的,每个元素都是字符串,所以每个字符串当然可以放在泛型是字符串的
List
中
,
所以可以使用泛型方法
static
<E,S extends T>
void copyArrayToList(
E
[] os,List
<S>
ls){
//
两个参数:一个
E
类型的数组,一个存放
E
或者
E
子类的对象的
List
for(E o:os){
ls.add(o);
}
}
★
泛型定义:
<E,T>
表示定义了两个泛型,多个泛型定义用,隔开,那么在后面的方法参数表、集合的类型等处应用这两个泛型
.E
是什么类型就看调这个方法的时候怎么传参数的
public static void main(String args[]){
List<String> l1= new ArrayList<String>();
l1.add("abc");
Number[] a1 = new Number[10];
List<Number> l2 = new ArrayList<Number>();
l2.add(23);
Number[] a1 = new Number[10];
List<Integer> l3 = new ArrayList<Integer>();
l3.add(23);
List<Object> l4 = new ArrayList<Object>();
l4.add("123");
l4.add(456);
copyArrayToList(a1,l1);
...
}
///
//
定义泛型的时候也可以限制范围
,
只能向下不能向上,即只能是
extends
,不能用
super
static <E super Numner> void copyArrayToList(ObjectE[] os,List<E> ls){
for(E o:os){
ls.add(o);
}
}
/
//
如果要
E
是
Number
而不是
Integer
,则
static <E extends Numner&comparator> void copyArrayToList(ObjectE[] os,List<E> ls){
for(E o:os){
ls.add(o);
}
}
<E super Numner&comparator>
类名
&
接口,表示
E
继承
Numner
实现
comparator
--------------------------------------------------------------------------
★
自定义一个泛型类:
public class TestGenerics1{
public static void main(String args[]){
MyClass<String> m = new MyClass<String>();
MyClass<Integer> m2 = new MyClass<Integer>();
String s = m.get();
Integer i = m2.get();
//System.out.println(m instanseof MyClass<String>);
//
泛型是编译时概念,到运行的时候什么泛型都没有了,
m instanseof MyClass
是到运行时才能确定的,所以这句话是不对的
}
}
class MyClass <E>{
public void print(E parameter){
}
public E get(){ //
返回类型是泛型
return null;
}
}
★
★注意:
*
不能
new
一个泛型的对象
*
静态方法不能使用类的泛型,
静态变量不能够使用泛型定义
public class MyGenericClass<T> {
public static T value;//
错误的定义
}
此外,泛型的定义不会被继承,举个例子来说,如果
A
是
B
的子类,而
C
是一个声明了泛型定义的类型的话,
C<A>
不是
C<B>
的子类。为了更好的说明,可以看下面的代码,这段代码是
错误的。
List<String> strList =new ArrayList<String>();
List<Object> objList=strList; //
错误的赋值
不过这样一段代码是正确的:
List<Object> strList =new ArrayList<Object>();
strList.add("jsdkfjsdl");
那么,在什么时候我们应该使用统配类型,什么时候我们应该使用泛型函数呢?答案是取决于函数参数之间,函数参数和返回值之间的类型依赖性。
如果一个函数的参数类型与函数返回的参数没有必然关联,同时对于该函数其他的参数的类型也没有依赖关系,那么我们就应该使用统配符,否则就应该使用泛型函数。
为了更清楚地说明这一点,我们可以看一下
java.util
包中
Collections
类型几个方法的定义:
class Collections {
static void swap(List<?> list, int i, int j) {...}
static <T> void copy (List<? super T> dest, List<? extends T> src) {...}
}
其中
swap
函数实际上也可以这样定义:
static <T>void swap(List<T> list, int i, int j) {...}
但是注意到这里泛型类型参数
T
只在参数中用到了一次,也就是说它和函数其他部分没有依赖性,这可以看作是我们应该使用
?
的一个标志。
copy
方法中,拷贝源
src
中的元素必须是
dest
所能够接受的,
src
中的元素必须是
T
的一个子类,但是具体它是哪种子类我们又不必关心,所以方法中使用了泛型作为一个类型参数,
同时也用了统配类型作为第二类型参数