------- android培训、java培训、期待与您交流! ----------
JDK5.0新特性介绍
1 静态导入
2 自动装箱/拆箱
3 增强for循环
4 可变参数
5 枚举
6 反射
7 注解
8 泛型
1.静态导入
JDK 1.5 增加的静态导入语法用于导入类的某个静态属性或方法。
使用静态导入可以简化程序对类静态属性和方法的调用。
它完全是为了便利而增加的新特性
语法:
import static 包名.类名.静态属性|静态方法|*
例如:
import static java.lang.System.out //静态导入类成员
import static java.lang.Math.* //使用通配符
注意:
import static java.util.Arrays.sort;
import static java.util.Collections.sort;
这是允许的,运行时会根据参数来自动找到对应的方法。
注:如果导入的两个静态方法的参数也是一样的话,由于不能确定是哪个方法,
所有使用时需要小心。
2.自动装箱和拆箱
Java中的基本类型不是对象,因此包装类用来当做对象版本的基本类型。
自动装箱:指开发人员可以把一个基本数据类型直接赋值给对应的包装类。Autoboxing
自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型。Autounboxing
思考:
Integer i = null;
int j = i;
语法有无错误,能否运行?
i被赋值为null是合法的,然后i被拆箱给j,然而null对基本类型来说是不合法的,运行会抛出NullPointerException
3.增强for循环
增强for循环又称为“foreach”或“enhanced for”循环。
抛弃迭代:在JDK5以前的版本中,遍历数组或集合中的元素,需先获得数组的长度或集合的迭代器,比较麻烦!
因此JDK5中定义了一种新的语法——增强for循环,以简化此类操作。增强for循环只能用在数组、或实现Iterable接口的子类上。
语法格式:
for(变量类型 变量 :需迭代的数组或集合){
}
增强for循环的特点:只适合取数据。要想在遍历时改元素的值,请使用传统for循环。
4.可变参数
可变参数(variable argument)允许你指定可以采用多个同类型参数的方法,而不需要事先确定参数的数目。
语法:
public void foo(int … args){
}
注意事项:
调用可变参数的方法时, 编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以在方法体中以数组的形式访问可变参数
在一个方法参数中只能使用一个省略号;且省略号必须出现在方法中参数列表的最后一个位置。
5.枚举类
为什么需要枚举?
一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,比如成绩Grade只能为ABCDE。
此类问题在JDK5以前采用自定义带有枚举功能的类解决,Java5以后可以直接使用枚举予以解决。
JDK5新增的 enum 关键字用于定义一个枚举类。
一个枚举也可以有构造函数、字段和方法。
枚举类具有如下特性:
枚举类也是一种特殊形式的Java类。
枚举类中声明的每一个枚举值代表枚举类的一个实例对象。
与java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但枚举类的构造函数必须为私有的。
枚举类也可以实现接口、或继承抽象类。
JDK5中扩展了swith语句,它除了可以接收int, byte, char, short外,还可以接收一个枚举类型。
若枚举类只有一个枚举值,则可以当作单态设计模式使用。
Java中声明的枚举类,均是java.lang.Enum类的孩子,它继承了Enum类的所有方法。常用方法:
name()
ordinal()
valueof(String name)此方法虽然在JDK文档中查找不到
values() 此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便。
示例:
enum Grade{
A("100~90"){
public String toLocaleString(){
return "优秀";
}
},B("89~80"){
public String toLocaleString(){
return "良好";
}
},C("79~70"){
public String toLocaleString(){
return "一般";
}
},D("69~60"){
public String toLocaleString(){
return "刚及格";
}
},E("59~0"){
public String toLocaleString(){
return "不及格";
}
};//代表着自身的一个个的实例对象
//字段
private String value;// A 100~90 B 89~80 C 79~70 D 69~60 E 59~0
//构造函数,必须私有
private Grade(){}
private Grade(String value){
this.value = value;
}
public String getValue() {
return value;
}
//获取中文名
public abstract String toLocaleString();
}
6.反射
(1)什么是反射?
反射就是把Java类中的各种成分映射成一个个的java对象。
例如,一个类有:成员变量,方法,构造方法,包等等信息,
利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。
(2)Class类
要利用反射,必须先得到代表字节码的Class。
Class类用于表示.class文件(字节码)。
如何获取字节码文件对象:
A:通过Object类的getClass()方法。
B:数据类型的class静态属性。
C:通过Class类的静态方法forName()
public static Class> forName(String className)
请问用哪一种?为什么?
第三种。因为第三种形式的做法,类的路径是可以通过配置文件执行的。
7.内省(Introspector) — JavaBean
(1)为什么要学内省?
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,
所以SUN公司开发了一套API,专门用于操作java对象的属性。
(2)通过内省技术访问(java.beans包提供了内省的API)JavaBean的两种方式。
a.通过PropertyDescriptor类操作Bean的属性
通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),
b.通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。
(3)Beanutils是Apache开发的一套快速操作JavaBean getter/setter方法的API,目前比较流行。
准备包:
commons-beanutils.jar,commons-logging.jar
语法:
设置:
BeanUtils.setProperty(Object bean,String propertyName,String propertyValue);
获取:
BeanUtils.getProperty(Object bean,String PropetyName);
8.泛型
(1)JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,
转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
(2)注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,
即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛型信息,
以此使程序运行效率不受到影响,这个过程称之为“擦除”。
(3)泛形的基本术语,以ArrayList
ArrayList
ArrayList
整个称为ArrayList
整个ArrayList
9.注解(Annotation)
(1)注解起到标识做用。比如Junit的@Test注解。Junit会在运行时检查方法上是否存在此注解,如果存在,就通过反射来运行你的方法
从 JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是 Annotation(注解)。
三个基本的 Annotation:
@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
@SuppressWarnings: 抑制编译器警告.
Annotation 其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,
传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。
在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
(2)自定义 Annotation
定义新的 Annotation 类型使用 @interface 关键字
声明注解的属性
注解属性的作用:原来写在配置文件中的信息,可以通过注解的属性进行描述。
Annotation 的属性声明方式:String name();
属性类型:基本类型、String、Class、枚举、注解及以上类型的一维数组类型
属性默认值声明方式:String name() default “xxx”;
特殊属性value:如果注解中有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx")
特殊属性value[];
(3)JDK的元Annotation
元Annotation指修饰Annotation的Annotation。JDK中定义了如下元Annotation:
@Retention:只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留的域,
@Rentention 包含一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域。
@Target:指定注解用于修饰类的哪个成员. @Target 包含了一个名为 value,类型为ElementType的成员变量。
@Documented:用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
@Inherited:被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
10.代理的概念和作用
(1) 要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,
例如,异常处理、日志、计算方法的运行时间、事物管理等等,你准备如何做?
编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,
并在调用方法时加上系统功能的代码。
如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置使用目标类还是代理类,
这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,
以后运行一段时间后,又想去掉系统功能也很容易。
(2)动态代理技术
要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!
JVM可以在运行期间动态生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
代理类的哥哥方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
a.调用目标方法之前
b.调用目标方法之后
c.调用目标方法前后
d.在处理目标方法异常的catch块中
11.类加载器
(1)类加载器负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象
(2)当 JVM 启动时,会形成由三个类加载器组成的初始类加载器层次结构:
bootstrap classloader:引导(也称为原始)类加载器,它负责加载Java的核心类。
extension classloader:扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中的JAR包。
system classloader:系统(也称为应用)类加载器,它负责在JVM被启动时, 加载来自在命令java中
的-classpath或者java.class.path系统属性或者 CLASSPATH操作系统属性所指定的JAR类包和类路径。
(3)全盘负责委托机制
classloader 加载类用的是全盘负责委托机制。
全盘负责:即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的其它Class通常也由这个classloader负责载入。
委托机制:先让parent(父)类加载器 寻找,只有在parent找不到的时候才从自己的类路径中去寻找。
类加载还采用了cache机制:如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,
并存入cache,这就是为什么修改了Class但是必须重新启动JVM才能生效,并且类只加载一次的原因。