[1]J2SE5.0新特性之静态导入
J2se5.0之前,如果需要使用其他类的静态方法,如java.lang.Math中的方法,需要写以下的代码:
double value = Math.log(100)*Math.PI;
现在你只需在静态导入,然后就可以直接在代码中使用静态方法和静态字段:
import static java.lang.Math.*;
…
double value = log(100)*PI;
看一个详细的例子。我们先建一个包含一个静态方法和一个静态字段的类:
新建一个类,静态导入上面的字段和方法,并使用它们:
[2]J2SE5.0新特性之Foreach
|
C#中提供了Foreach的用法:
foreach (string item in f)
{
Console.WriteLine(item);
}
Java也增加了这样的功能:
package com.kuaff.jdk5;
import java.util.*;
import java.util.Collection;
public class Foreach
{
private Collection<String> c = null;
private String[] belle = new String[4];
public Foreach()
{
belle[0] = "西施";
belle[1] = "王昭君";
belle[2] = "貂禅";
belle[3] = "杨贵妃";
c = Arrays.asList(belle);
}
public void testCollection()
{
for (String b : c)
{
System.out.println("曾经的风化绝代:" + b);
}
}
public void testArray()
{
for (String b : belle)
{
System.out.println("曾经的青史留名:" + b);
}
}
public static void main(String[] args)
{
Foreach each = new Foreach();
each.testCollection();
each.testArray();
}
}
对于集合类型和数组类型的,我们都可以通过foreach语法来访问它。上面的例子中,以前我们要依次访问数组,挺麻烦:
for (int i = 0; i < belle.length; i++)
{
String b = belle[i];
System.out.println("曾经的风化绝代:" + b);
}
现在只需下面简单的语句即可:
for (String b : belle)
{
System.out.println("曾经的青史留名:" + b);
}
对集合的访问效果更明显。以前我们访问集合的代码:
for (Iterator it = c.iterator(); it.hasNext();)
{
String name = (String) it.next();
System.out.println("曾经的风化绝代:" + name);
}
现在我们只需下面的语句:
for (String b : c)
{
System.out.println("曾经的风化绝代:" + b);
}
Foreach也不是万能的,它也有以下的缺点:
在以前的代码中,我们可以通过Iterator执行remove操作。
for (Iterator it = c.iterator(); it.hasNext();)
{
itremove()
}
但是,在现在的foreach版中,我们无法删除集合包含的对象。你也不能替换对象。
同时,你也不能并行的foreach多个集合。所以,在我们编写代码时,还得看情况而使用它。
[3]J2SE5.0新特性之枚举类型
J2SE5.0新特性之枚举类型
在传统的设计中,为了达到c、c++的枚举的功能,我们一般在类中声明几个常量:
public static final String BELLE_XISHI = “西施”;
public static final String BELLE_WANGZHAOJUN = “王昭君”;
public static final String BELLE_DIAOCHAN = “貂禅”;
public static final String BELLE_YANGGUIFEI = “杨贵妃”;
然而,这样做有些问题:
1. 不是类型安全的:因为被声明为String类型,您可以给它们赋值任意的字符串,而且,有可能两个常量的值相同。
2. 没有命名空间:为了区别与非分类,我们定义的常量以BELLE做前缀。
3. 脆弱:一旦被编译后,如果想插入常量,或者他们的顺序和值被更改,使用它们的程序需要重新编译。
4. 打印值代表的意义不明显。
现在,在新的Java语言中,已经可以使用枚举类型解决上面的问题,我们首先以一个例子来看一下枚举类型是怎么工作的。
这里定义了一个枚举类型Belle(美女)。它四个值:西施、貂禅、王昭君和杨贵妃。注意,这里的值可是中文。
通过Belle.values()方法可以得到Belle枚举类型的所有的值,它返回一个包含Belle值的数组。
这样我们就可以通过belle.getName()或者belle.toString()得到枚举值。
注意:这里用到了printf方法和Foreach类型的循环,在后面的文章中会对这些新特性进行介绍。
事实上,每个枚举值可以设置多个参数,我们将上面的例子扩充一下:
- package com.kuaff.jdk5;
- public class EnumShow2
- {
- enum Belle
- {
- 西施("春秋战国", "范蠡,勾践,夫差"),
- 王昭君("西汉", "刘?,毛延寿,呼韩邪单于"),
- 貂禅("三国", "吕布,董卓"),
- 杨贵妃("唐朝", "李隆基");
- private final String empire;
- private final String mans;
- private Belle(String empire, String mans)
- {
- this.empire = empire;
- this.mans = mans;
- }
- }
- public static void main(String[] args)
- {
- EnumShow2 show = new EnumShow2();
- for (Belle belle : Belle.values())
- {
- System.out.printf("美女的名字:%s, 生活年代:%s, 美女身后的相关男人:%s%n",belle,belle.empire,belle.mans);
- }
- }
- }
在这个例子中,我们为每位美人都加了一个生活年代和相关的男人这两个参数。
这里必须有Belle(String empire, String mans)这样一个构造方法。对每个枚举值,可以象使用对象一样使用它,要得到它的参数,可以通过 枚举对象.参数 方式访问。如果反编译以下它的类,事实上,java编译器也是把它编译成一个类:
static class EnumShow2$Belle extends Enum
{
…
}
以上两个例子可以在Eclipse 3.1M3下编译通过,现在的Eclipse3.1M3已经对JDK5达到了97%的支持。
既然它被编译成了类,我们也会联想到,类可以有方法的,枚举类型是不是页支持方法内呢?是!
我们在扩充一下上面的例子,为每个美人增加一个显示其生平事件的方法:
- package com.kuaff.jdk5;
- public class EnumShow3
- {
- enum Belle
- {
- 西施("春秋战国", "范蠡,勾践,夫差")
- {
- String mainEvent()
- {
- return "为勾践,嫁夫差,与范蠡泛西湖终老";
- }
- },
- 王昭君("西汉", "刘?,毛延寿,呼韩邪单于")
- {
- String mainEvent()
- {
- return "毛延寿,不厚道,刘?不走访基层,不听群众意见,昭君和亲,青冢埋芳泽";
- }
- },
- 貂禅("三国", "吕布,董卓")
- {
- String mainEvent()
- {
- return "红颜真祸水乎?男人好色而已!";
- }
- },
- 杨贵妃("唐朝", "李隆基")
- {
- String mainEvent()
- {
- return "温泉在,佳人无,长生殿内暗伤神,却闻凤凰东度。";
- }
- }
- ;
- private final String empire;
- private final String mans;
- private Belle(String empire, String mans)
- {
- this.empire = empire;
- this.mans = mans;
- }
- abstract String mainEvent();
- }
- public static void main(String[] args)
- {
- EnumShow3 show = new EnumShow3();
- for (Belle belle : Belle.values())
- {
- System.out.printf("美女的名字:%s, 生活年代:%s, 美女身后的相关男人:%s%n",belle,belle.empire,belle.mans);
- System.out.printf(" 相关事件:%s%n", belle.mainEvent() );
- }
- }
- }
我们为每个美人增加了一个方法String mainEvent();同时,我们也必须在此枚举类型内增加一个抽象的方法声明:abstract String mainEvent();
和类型一样,通过 枚举对象.方法(…) 来调用枚举类型的方法。
上面的例子在eclipse 3.1M3下显示有错误,因为目前的eclipse还认为抽象方法只能在抽象类中声明,没关系,在命令行中直接编译吧: javac -source 5 -target 5 -d bin src/com/kuaff/jdk5/EnumShow3.java。
[4]J2SE5.0新特性之元数据
元数据,在java中也叫注释、注解。微软的.net从开始设计时就有这个功能,不过它的术语叫属性。
这时一个强大的功能,程序员如果想挣钱,得好好研究它,因为
在将来的j2ee开发中,广泛的使用它,包括ejb的声明,IOC中的注入等。
IBM网站有篇文章详细介绍了它,挺好的一篇文章。
http://www-900.ibm.com/developerWorks/cn/java/j-annotate1/
http://www-900.ibm.com/developerworks/cn/java/j-annotate2.shtml
我曾兴致勃勃的根据例子在eclipse中测试了一把,可怎么也得不到注释信息。后来,在命令行直接编译java文件,运行才正常。虽然现在的eclipse 编辑器可以识别java的注释语法,但是在编译的时候并没有生成带注释的java类。我没有仔细深究,可能时eclipse在编译的时候枚加上-target 5参数吧,猜测而已。
新建一个注释类型,这个类型指明了一本名著的作者和他的email。
使用这个注释为我们的方法加上注解:
- package com.kuaff.jdk5;
- import java.lang.annotation.Annotation;
- public class MetadataShow
- {
- @BookAuthor(name="曹雪芹",email="caoxueqin@hongloumeng.books")
- public void introHongLouMeng()
- {
- System.out.println("这是一本好书啊");
- }
- public static void main(String[] args)
- {
- MetadataShow metadata = new MetadataShow();
- try
- {
- Annotation[] annotation = metadata.getClass().getMethod("introHongLouMeng").getAnnotations();
- for(Annotation a : annotation)
- {
- System.out.printf("作者:%s%n", ((BookAuthor)a).name());
- System.out.printf("他的电子邮件(可能已被注销):%s%n", ((BookAuthor)a).email());
- }
- }
- catch (SecurityException e)
- {
- e.printStackTrace();
- }
- catch (NoSuchMethodException e)
- {
- e.printStackTrace();
- }
- }
- }
请注意,要想在程序运行时能读取这些注释,需要在注释的声明的时候加上
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) //也可能时其他类型,如针对声明的注释
这是对注释的注释。
编译这两个文件:
javac -source 5 -target 5 -d bin src/com/kuaff/jdk5/*.java
[5]J2SE5.0新特性之范型编程
本章主要参考sun公司文档。
C++程序员对范型编程肯定不陌生,尤其在STL大行其道的时候,C#2.0也将实现范型编程的功能。Java也不甘示弱,也推出了范型编程的语言新特性。
1.一个简单的范型示例
在以前,你可能遇到过这样的代码:
注意,第三行需要强制转换。而使用范型:
这里将list声明成String类型的List。List是有一个类型参数的范型接口。这个例子中类型参数是String。
2.定义简单的范型
看j2se5.0中List和Iterator接口的实现(片断):
- public interface List<E>
- {
- void add(E x);
- Iterator<E> iterator();
- }
- public interface Iterator<E>
- {
- E next();
- boolean hasNext();
- }
上面的代码我们比较熟悉,但是其中增加了尖括号。尖括号中的内容定义了接口List和Iterator的形式类型参数。类型参数可以用在范型声明中,如类和接口的声明。
一旦声明了范型,你就可以使用它。在上面的例子中使用了List<String>。这里使用String是实参,代替了形参E。如果使用List<Integer>,则用实参Integer代替了形参E。
不管List<Integer>还是List<String>,它们的类只有一个。考虑下面的代码:
输出结果为true。
一般来说,形式类型参数都是大写,尽量使用单个字母,许多容器类都使用E作为参数。
3.范型和继承
考虑下面的代码,你认为它会出错吗?
当然,String类继承Object类,这样做不会出错。但下面的代码呢?
编译出错!
是的,List<Object>和List<String>没有继承关系。
4.通配符
考虑下面一个方法:
事实上,上面这个方法并不通用,它只能打印Collection<Object>类型的集合,象其他的如Collection<String>、Collection<Integer>并不能被打印,因为对象类型不一致。
为了解决这个问题,可以使用通配符:
Collection<?>被称作未知类型的集合。问号代表各种类型。
上面的读取集合中的数据时,我们采用Object类型。这样做时可以的,因为不管未知类型最终代表何种类型,它的数据都继承Object类,那么再考虑一下下面的代码:
这样做时错误的,因为我们不知道?代表何种类型,所以我们不能直接将Object增加到集合中,这会出现类型不匹配的情况。
5.有限制的通配符
考虑下面的代码
考虑下面的范型方法:
- public void printName(List<Man> men)
- {
- for(Man man:men)
- {
- System.out.println(“姓名:” + man.name);
- }
- }
这个范型方法只能显示List<Man>类型的数据,下面的代码允许显示Man和它的子类。
- public void printName(List<? extends Man> men)
- {
- for(Man man:men)
- {
- System.out.println(“姓名:” + man.name);
- }
- }
这里使用? extends Man代替Man,表明接受任何Man的子类做为参数。
和前面的代码类似,下面的代码也是不正确的:
- public void adman(List<? extends Man> men)
- {
- GoodMan good = new GoodMan();
- good.name = “晁岳攀”;
- men.add(good);
- }
原因也很简单,因为?代表一切继承Man的类,你并不能保证就一定时GoodMan类。
和这种用法类似:
- public void adman(List<? super GoodMan> men)
- {
- GoodMan good = new GoodMan();
- good.name = “晁岳攀”;
- men.add(good);
- }
6.范型方法
考虑下面的代码,我们将一个数组的内容加到一个集合中
- public void copyArrayToCollection(Man[] men, Collection<?>c)
- {
- for(Man man:men)
- {
- c.add(man);
- }
- }
这段代码时错的!
因为我们并不知道集合C的类型,所以不能将Man类型的数据加到集合中。
可以使用范型方法解决:
- public <T> void copyArrayToCollection(T[] men, Collection<T>c)
- {
- for(T man:men)
- {
- c.add(man);
- }
- }
这里T时一个形式类型参数。
何时该采用通用方法?何时该采用通配符?
考虑下面的例子:
- interface Collection<E>
- {
- public boolean containsAll(Collection<?> c);
- public boolean addAll(Collection<? extends E> c);
- }
改写成通用方法
- interface Collection<E>
- {
- public <T> boolean containsAll(Collection<T> c);
- public <T extends E> boolean addAll(Collection<T> c);
- }
然而,在这里每个方法T只使用了一次,返回值不依赖形式参数,其他参数也不依赖形式参数。这说明实参被用作多态,这种情况下就应该用通配符。
[6]J2SE5.0新特性之监控与管理
j2se 5.0使用 Java Management Extensions (JMX)来管理和监控java平台。
我们以一个例子来测试一下:
- import java.lang.management.ClassLoadingMXBean;
- import java.lang.management.CompilationMXBean;
- import java.lang.management.ManagementFactory;
- import java.lang.management.MemoryMXBean;
- import java.lang.management.MemoryManagerMXBean;
- import java.lang.management.MemoryPoolMXBean;
- import java.lang.management.OperatingSystemMXBean;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.List;
- public class JDKMBean
- {
- public static <T> void printMXBean(Class<T> t,Object object)
- {
- Method[] methods = t.getMethods();
- T instance = (T)object;
- System.out.printf("%n---%s---%n", t.getName());
- for(Method m:methods)
- {
- if (m.getName().startsWith("get"))
- {
- try
- {
- Object rtValue = m.invoke(instance,new Object[0]);
- System.out.printf("%s:%s%n",m.getName().substring(3),rtValue);
- }
- catch (IllegalArgumentException e1)
- {
- }
- catch (IllegalAccessException e)
- {
- }
- catch (InvocationTargetException e)
- {
- }
- }
- }
- }
- public static <T> void printMXBeans(Class<T> t,List<T> list)
- {
- for(T bean:list)
- {
- printMXBean(t,bean);
- }
- }
- public static void main(String[] args)
- {
- JDKMBean.printMXBean(OperatingSystemMXBean.class,ManagementFactory.getOperatingSystemMXBean());
- JDKMBean.printMXBean(CompilationMXBean.class,ManagementFactory.getCompilationMXBean());
- JDKMBean.printMXBean(ClassLoadingMXBean.class,ManagementFactory.getClassLoadingMXBean());
- JDKMBean.printMXBean(MemoryMXBean.class,ManagementFactory.getMemoryMXBean());
- JDKMBean.printMXBeans(MemoryManagerMXBean.class,ManagementFactory.getMemoryManagerMXBeans());
- JDKMBean.printMXBeans(MemoryPoolMXBean.class,ManagementFactory.getMemoryPoolMXBeans());
- }
- }
运行结果:
---java.lang.management.OperatingSystemMXBean---
Arch:x86
AvailableProcessors:2
Name:Windows 2000
Version:5.0
---java.lang.management.CompilationMXBean---
TotalCompilationTime:5
Name:HotSpot Client Compiler
---java.lang.management.ClassLoadingMXBean---
LoadedClassCount:431
UnloadedClassCount:0
TotalLoadedClassCount:431
---java.lang.management.MemoryMXBean---
HeapMemoryUsage:init = 0(0K) used = 458288(447K) committed = 2031616(1984K) max = 66650112(65088K)
NonHeapMemoryUsage:init = 29556736(28864K) used = 12541248(12247K) committed = 29851648(29152K) max = 121634816(118784K)
ObjectPendingFinalizationCount:0
---java.lang.management.MemoryManagerMXBean---
MemoryPoolNames:[Ljava.lang.String;@6ca1c
Name:CodeCacheManager
---java.lang.management.MemoryManagerMXBean---
MemoryPoolNames:[Ljava.lang.String;@1bf216a
Name:Copy
---java.lang.management.MemoryManagerMXBean---
MemoryPoolNames:[Ljava.lang.String;@12ac982
Name:MarkSweepCompact
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:null
MemoryManagerNames:[Ljava.lang.String;@c20e24
PeakUsage:init = 196608(192K) used = 482048(470K) committed = 491520(480K) max = 33554432(32768K)
Usage:init = 196608(192K) used = 524352(512K) committed = 557056(544K) max = 33554432(32768K)
UsageThreshold:0
UsageThresholdCount:0
Name:Code Cache
Type:Non-heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 524288(512K) used = 0(0K) committed = 0(0K) max = 4194304(4096K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@2e7263
PeakUsage:init = 524288(512K) used = 511160(499K) committed = 524288(512K) max = 4194304(4096K)
Usage:init = 524288(512K) used = 521688(509K) committed = 524288(512K) max = 4194304(4096K)
Name:Eden Space
Type:Heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 65536(64K) used = 0(0K) committed = 0(0K) max = 458752(448K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@157f0dc
PeakUsage:init = 65536(64K) used = 65528(63K) committed = 65536(64K) max = 458752(448K)
Usage:init = 65536(64K) used = 65528(63K) committed = 65536(64K) max = 458752(448K)
Name:Survivor Space
Type:Heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 1441792(1408K) used = 0(0K) committed = 0(0K) max = 61997056(60544K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@863399
PeakUsage:init = 1441792(1408K) used = 142120(138K) committed = 1441792(1408K) max = 61997056(60544K)
Usage:init = 1441792(1408K) used = 142120(138K) committed = 1441792(1408K) max = 61997056(60544K)
UsageThreshold:0
UsageThresholdCount:0
Name:Tenured Gen
Type:Heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 8388608(8192K) used = 0(0K) committed = 0(0K) max = 67108864(65536K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@a59698
PeakUsage:init = 8388608(8192K) used = 641040(626K) committed = 8388608(8192K) max = 67108864(65536K)
Usage:init = 8388608(8192K) used = 641040(626K) committed = 8388608(8192K) max = 67108864(65536K)
UsageThreshold:0
UsageThresholdCount:0
Name:Perm Gen
Type:Non-heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 8388608(8192K) used = 0(0K) committed = 0(0K) max = 8388608(8192K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@141d683
PeakUsage:init = 8388608(8192K) used = 5601632(5470K) committed = 8388608(8192K) max = 8388608(8192K)
Usage:init = 8388608(8192K) used = 5601632(5470K) committed = 8388608(8192K) max = 8388608(8192K)
UsageThreshold:0
UsageThresholdCount:0
Name:Perm Gen [shared-ro]
Type:Non-heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 12582912(12288K) used = 0(0K) committed = 0(0K) max = 12582912(12288K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@16a55fa
PeakUsage:init = 12582912(12288K) used = 5850024(5712K) committed = 12582912(12288K) max = 12582912(12288K)
Usage:init = 12582912(12288K) used = 5850024(5712K) committed = 12582912(12288K) max = 12582912(12288K)
UsageThreshold:0
UsageThresholdCount:0
Name:Perm Gen [shared-rw]
Type:Non-heap memory