现在让我们考察一下 Java 语言与 Visual Basic .NET 之间的区别。
类型
Java 语言和 Visual Basic .NET 都是单继承的面向对象语言,它们具有一个作为其他所有类的基类的类:Visual Basic .NET 中的 System.Object 和 Java 语言中的 java.lang.Object 。这意味着对于您开发的类层次,两种语言是相似的。如果沿着层次树往上,您最终会到达对应的根类。
Java 语言使用了原始类型(primitive type)的概念,它们非常类似 C 和 C++ 中的对应概念。它们不是任何类层次的一部分,也不具有任何方法。此外,当使用它们作为参数时,它们总是按值传递。表 1 列出了 Java 语言中的原始类型和它们在 Visual Basic .NET 中的等价类型:
表 1 Java 语言中的原始类型和它们在 Visual Basic .NET 中的等价类型 Java 原始类型 描述 等价的 Visual Basic .NET 类型 描述 int
32 位有符号整数 Integer
32 位有符号整数 long
64 位有符号整数 long
32 位有符号整数 short
16 位有符号整数 short
16 位有符号整数 char
16 位无符号整数 Char
16 位无符号整数 byte
8 位无符号整数 Byte
8 位无符号整数 boolean
有效值是 true或者 false Boolean
有效值为 true或者 false float
32 位浮点数 Single
32 位浮点数 double
64 位浮点数 Double
64 位浮点数
在 Java 语言中,每种原始类型具有一个对应的包装类,可以使用它将该类型作为对象而不是作为原始类型来处理。每个包装类具有一个构造函数,允许您根据原始类型中的数据创建该包装类型的一个实例。在 Visual Basic .NET 中,您可以隐式地将对应的类型转换为 Object 的一个实例,因此不需要在这种情形下使用包装类。清单 2 中的例子突出了它们之间的区别。
清单 2. 原始类型和它们的包装类
2 Module Foo public class Foo
3 {
4 Sub someMethod(ByRef arg As Object) private void someMethod(Object arg) {
5 ' do something with arg // do something with arg
6 end Sub }
7 Sub Main() public static void main(String[] args) {
8 Dim i = 0 As Integer int i=0;
9 Foo x = new Foo();
10 someMethod(i); x.someMethod(new Integer(i));
11 End Sub }
12 End Module }
13
清单 2 中的 Java 原始类型被显式地包装在 Object 的一个派生类中,而在 Visual Basic .NET 中,这种转换是隐式的。
注意在 Java 语言中,原始类型是按值传递的。对象实例内部地使用指针来表示,这些指针也是按值传递的(也就是指针的值,而不是指针所指向的内容)。在 Visual Basic .NET 中,默认的行为是值类型按值传递,引用类型按引用传递。Java 语言中没有等价于 Visual Basic .NET ByRef 和 ByVal 的关键字。表 2 显示了等价于 Visual Basic .NET 类型但是没有映射到 Java 原始类型的 Java 语言类型。
表 2 常用的 Java 系统类和它们在 Visual Basic .NET 中的等价类型
Java 类 | 描述 | 等价的 Visual Basic .NET 类 | 描述 |
java.lang.Object | 任何非原始类型都是 Object 的派生类 | Object | 每种类型都是 Object 的派生类 |
java.lang.String | Unicode 字符 | String | Unicode 字符 |
java.math.BigDecimal | 可调整进位制的 32 位小数 | Decimal | 可调整进位制的 32 位小数 |
java.util.Date | 日期(排除时间部分) | Date | 日期(排除时间部分) |
Java 语言与 Visual Basic .NET 不同,它没有结构和模块。所有 Java 代码都必须是某个类或接口的一部分。如果要移植包含模块和结构的 Visual Basic .NET 代码,您必须将它们改写为 Java 类。
继承和接口
两种语言都仅允许单继承,但是都允许实现多个接口。这在两种语言中的实现方式有所不同。例如,清单 3 显示了如何从一个名为 Parent 的类派生子类并实现两个分别名为 IOne 和 ITwo 的接口。
清单 3 派生子类并实现接口
2 Public Class Child public class Child extends Parent implements IOne, ITwo
3 Inherits Parent {
4 Implements IOne ...
5 Implements ITwo }
6 ...
7 End Class
8
End Class
在 Java 语言中, extends 关键字表示继承, implements 关键字表示实现一个或多个接口,接口之间用逗号分隔。
包
如果熟悉 Visual Basic .NET 中的名称空间,那么对 Java 语言中的包就不应该有任何概念问题。像名称空间一样,包允许您组织类以避免当您在不同上下文中使用相同名称的类时存在的名称冲突。名称空间的逻辑类分组促进了类复用,使得导航大量的类成员更加容易。在 Java 语言中,您需要通过两种方式处理这种分组:如何将类声明为特定包的成员,以及如何引用特定包中的类。清单 4 中的例子说明了名称空间和包的处理。
清单 4. 名称空间和包
2 'Foo will be in this namespace // Foo will be in this package
3 Namespace MyApp.Utilities package com.mycompany.myapp.utilities;
4 Public class Foo public class Foo
5 {
6 ... ...
7 End Class }
8 End Namespace
9 'using Foo in another class // using Foo in another class
10 Imports MyApp.Utilities.Foo import com.mycompany.myapp.utilities.Foo;
11 Public Class Foo2 public class Foo2
12 ... {
13 ...
14 End Class }
15
在 Java 语言中,约定的做法是包名称全部使用小写,并使用反向的 Internet 域名作为每个包的前缀。上述清单使用 Java import 语句(类似 Visual Basic .NET Imports 语句)来引用 Foo2 中的 Foo 类,而没有使用完全限定的名称(Visual Basic .NET 中的 MyApp.Utilities.Foo 或 Java 代码中的 com.mycompany.myapp.utilities.Foo )。
打包以供复用
在 Visual Basic .NET 中,您可以编写一组类,把它们生成程序集(assembly),程序集在文件系统中表示为动态链接库。其他类可以引用这些程序集,以便使用它们所包含的类。Java 语言也允许把一组类打包到一个称为“Java 归档(Java Archive,JAR)文件”的文件中以供复用。您可以将一组类组合到一个带有 .jar 扩展名的文件中,然后在其他类中引用该 JAR 文件。具有 .jar 扩展名的文件是标准的 zip 文件,可以使用 WinZip 或其他压缩实用程序来操作它们。不过为方便起见,Java SDK 包含了一个名为 jar.exe 的实用程序(在 Windows 平台上),可以使用它来把一组类组合到一个具有 .jar 扩展名的文件中。
在考察使用 jar.exe 实用程序的例子之前,理解包名称和 Java 平台用于生成类以及在运行时加载它们的目录结构之间的关系是很重要的。请考虑一个名为 Test 的类,它的源代码在一个名为 Test.java 的文件中。如果将 Test.java 定义为包 com.mycompany.test 的一部分,那么编译器会为结果类模块创建一个目录树。该目录树就建立在包名称的基础上。此例中该目录树为 com\mycompany\test,并且包名称中的点号被转换为目录边界(分隔符 \)。
现在打开一个命令提示符窗口,然后创建一个目录(例如 c:\javapack)。切换到该目录( cd javapack )。使用您最喜欢的文本编辑器,将清单 5 中的代码添加到一个名为 Test.java 的新文件中。
清单 5. 使用包的例子
2 public class Test
3 {
4 public static void main(String[] args) {
5 System.out.println("In test");
6 }
7 }
8
现在使用以下命令编译 Test.java。( -d 选项应该指向您为这个例子创建的目录):
2
现在在 c:\javapack 目录下应该有一个名为 com 的子目录。 事实上,您可以看到编译所产生的 comTest.class 文件的完全限定名称是 Test.class。注意包名称( com.mycompany.test )是如何转换为对应目录结构(com\mycompany\test)的,该目录结构以您使用 -d 选项指定的目录作为根目录。
下面我们将展示如何打包 Test.class 以方便其他类复用。从 c:\javapack 目录运行以下命令:
2
这个命令将创建一个名为 Test.jar 的文件,它包含 com 子目录下的所有类。
运行以下命令来使用 Test.jar 文件中的类:
2
注意您必须使用完全限定的类名称来从命令行运行该命令,而且还要注意使用 -classpath 选项来指向 Test.jar 文件的方式。或者,您可以把 Test.jar 文件添加到 CLASSPATH 环境变量中,该变量是分号分隔的 JAR 文件列表,以及 Java 编译器和 Java 虚拟机(Java virtual machine,JVM)用来寻找需要加载的类的目录列表。
访问修饰符
访问修饰符 public 、 private 和 protected 在两种语言中的工作方式大部分都是相同的。 在 Visual Basic .NET 中,默认的访问修饰符是 Friend 。在 Java 语言中,默认的访问权限是允许任何子类或相同包中的任何类访问当前类、字段或方法。这大致等价于 Visual Basic .NET 中的 Protected Friend 修饰符,该修饰符仅允许从相同程序集或从子类访问。
方法重载
Visual Basic .NET 中的子类如果要重载父内中的某个方法:
该方法一定 不 能在父类中使用 private 访问修饰符来声明。
该方法必须在父类中声明为 Overridable 。
子类中的方法必须与父类中的对应方法具有相同的名称、返回类型和参数签名。
子类中的方法必须使用 Overrides 关键字来声明。(您也可以使用 new 关键字,但是一般不推荐这样做。)
父类中的方法一定 不 能声明为 NotOverridable 。
Java 语言中方法重载的前提条件不太严格:
该方法一定 不 能在父类中使用 private 访问修饰符来声明。
子类中的方法必须与父类中的对应方法具有相同的名称、返回类型和参数签名。
父类中的方法一定 不 能声明为 final 。
这些区别的含义是,在 Java 代码中,子类中不可能包含与父类中的非私有方法具有相同名称和签名的方法而不会隐含地重载它。在 Visual Basic .NET 中,您必须显式地指明何时想要重载父类中的方法。还要注意,Java 语言中的 final 关键字或多或少地等价于 Visual Basic .NET 中的 NotOverridable 关键字。
异常处理
结构化的异常处理在两种语言中几乎完全相同。(两者都可以往后追溯到一份创始性的论文,即 Andrew Koenig 和 Bjarne Stroustrup 于 1990 年撰写的 Exception Handling for C++。) 两种语言都使用两种异常概念:应用程序生成的异常,以及系统运行库(Visual Basic .NET 的公共语言运行库,Java 语言的 JVM)生成的异常。 两种语言都具有 Exception 基类,应用程序异常和系统异常都是由它派生而来的。图 2 显示了每种语言中的 Exception 类层次。
图2. Java 语言和 Visual Basic .NET 中的 Exception 类
然而,两种语言的编译器对您的代码如何处理异常具有不同的预期。在 Visual Basic .NET 中,您可以选择捕获异常,或让它们沿调用堆栈向上传播到类的方法的调用者(和/或构造函数)。Java 语言允许同样的处理,但是对于未捕获的应用程序异常(也就是 java.lang.Exception 的子类),您必须显式地将它们作为方法声明的一部分来列出。因此 Java 编译器预期您或者自己捕获所有应用程序异常,或者告诉编译器关于未捕获的异常的信息。例如,假设 Foo 类的构造函数可能抛出一个应用程序异常,那么清单 6 中的 Visual Basic .NET 或 Java 代码对各自的编译器来说都不会有问题。
清单 6. 处理应用程序异常
2 ... ...
3 Sub SomeMethod() public void someMethod() {
4 Try try {
5 Dim Foo X As New Foo() Foo x = new Foo();
6 }
7 Catch e As ApplicationException catch (Exception e)
8 {
9 ... ...
10 End Try }
11 End Sub }
12
然而,如果改变代码以使其不捕获异常,那么您就必须改变 Java 方法声明(如清单 7 所示)以避免编译器错误。
清单 7. 未捕获的应用程序异常
2 ... ...
3 Sub SomeMethod() public void someMethod() throws Exception {
4 Dim Foo X As New Foo(); Foo x = new Foo();
5 End Sub }
6
两种语言在这方面存在的另一个区别在于,在 Visual Basic .NET 中,每个捕获块的参数是可选的。如果省略它,那么所有异常都会被捕获。Java 语言不允许这样,而是允许一个等价功能( java.lang.Throwable ),它捕获所有异常类的父类,如清单 8 所示。
清单 8. 捕获所有异常
2 ... ...
3 Sub SomeMethod() public void someMethod() {
4 Try try {
5 Dim Foo X As New Foo() Foo x = new Foo();
6 }
7 Catch catch (Throwable e)
8 {
9 ... ...
10 End Try }
11
数组声明
Java 语言提供两种声明数组的方法;Visual Basic .NET 仅提供了一种方法。Java 数组工作起来很像 Visual Basic .NET 中的动态数组:必须通过一个显式的步骤来给它分配内存。清单 9 中的代码说明了这个区别。与在 Visual Basic .NET 中一样,Java 数组的下标从 0 开始。
清单 9. 声明数组
2 ... ...
3 ' This is how an array is // In Java the following
4 'declared in Visual Basic .NET // are both allowed
5 Dim MyArray() As Integer private int[] myArray;
6 // or
7 private int myArray[];
8 'Allocate some storage for the array // Allocate some storage
9 // for the array
10 ReDim MyArray(30) myArray = new int[30];
11
委托
Java 语言没有直接等价于 Visual Basic .NET 委托的结构。可以通过声明并实现一个具有单个方法定义的接口来模拟委托功能。
变量声明
Java 语言是强类型的,控制变量声明的规则等价于打开 Option Explicit 选项后的 Visual Basic .NET 规则。也就是说,您必须在使用变量之前声明它们。Java 语言不允许改变这个性质。
OnError GoTo
Java 语言没有直接等价于 Visual Basic .NET 的 GoTo 语句的结构。不过,您可以使用异常处理机制相当容易地执行异常处理。
构造函数
像 Visual Basic .NET 一样,Java 类可以包含具有不同参数列表的不同构造函数。在 Visual Basic .NET 中,构造函数通过名为 New() 的 Sub 来声明。Java 语言构造函数的名称与类名称相同。清单 10 中的代码说明了这个区别。
清单 10:构造函数
2 Public Class Foo public class Foo {
3 Private MyVar As Integer private int myVar;
4 Public Sub New(ByVal NewVal As Integer) public Foo(int newVal) {
5 MyVar = NewVal myVar = newVal;
6 End Sub }
7 ... ...
8 End Class }
9
属性(property)
等价于 Visual Basic .NET 属性的 Java 结构称为 字段(field)。在 Java 语言中,您不能将 getter 和 setter 定义为字段定义的一部分,但是可以向类中声明那些字段的地方添加 getter 和 setter。清单 11 中的代码说明了这个区别。
清单 11:属性
2 Public Class Foo public class Foo {
3 Private MyPropVal As String private String myProp;
4 Public Property MyProp() As String public String getMyProp() {
5 Get return myProp;
6 Return MyPropVal }
7 End Get
8 Set(ByVal NewValue As String) public void setMyProp(String newValue) {
9 MyPropVal = NewValue myProp = newValue;
10 End Set }
11 End Property
12 ... ...
13 End Class }
14
小结
Visual Basic .NET 的语法类似于以前的 Visual Basic 版本,但是最新的版本包括了许多可从 Java 语言中找到的面向对象特性。继承、接口和异常处理就是两种语言的实现存在相似性的一些方面。与以前版本的 Visual Basic 相比,这种相似性应该使您转向 Java 平台更加容易。我们提倡您首先把 Visual Basic .NET 小程序转换到 Java 语言。不要忘了使用 Java 平台文档,要查找功能上等价于 System... 名称空间中的 Visual Basic .NET 类的 Java 类,您会发现这些文档非常有用