key words:
constructor 构造函数 method 方法 instance 实例
object 对象 modifier 修饰符 return type 返回类型
static method 静态方法 superclass 超类 Inheritance 继承
platypus 鸭嘴兽
我们说一个构造函数是方法就好比说澳洲鸭嘴兽是另一个哺乳动物一样。 为了了解鸭嘴兽,知道其与其他的哺乳动物的差别对我们来说非常重要。同理,了解构造函数,知道构造函数与其他方法的区别对我们同样重要。对于任何学习Java,尤其是为了获得资格证书的学生来说,都需要知道这些区别。在这篇文章中,我将会一一道来。在文章结尾,Table1 总结了constructor(构造函数)和method(方法)的重要区别。
Purpose and Function (目的与功能)
构造函数都有一个目的:创建一个类的实例。也可以叫做创建一个对象,如下:
相比之下,方法(method)的目的显得更为普通. 一个方法的基本功能就是为了执行Java的代码.
Signature differences(签名区别)(Signature 不知道怎么翻译好)
构造函数(constructors)和方法(methods)在以下三个方面存在差别:
· 修饰符 (modifiers)
· 返回类型(return type)
· 名字 (name)
像方法一样,构造函数可以有任意一种访问修饰符(access modifiers):公共的(public),保护的(protected),私有的(private)或者没有(常被称为package或者friendly)。不同于方法的是,构造函数只能被访问修饰符进行限定。因此,构造函数不能是abstract, static, final, natice or synchronized的。
两者的返回类型(return type)也是截然不同的。方法可以拥有任何有效的返回类型,或者方法没有返回值,这种情况下方法的返回类型为void。构造函数没有返回类型,也没有void。
最后,构造函数和方法在取名方面也有很大的不同。构造函数名字与其类名(class name)相同;按照惯例,方法使用其他与类名不相同的名字。如果Java程序员遵循通常惯例,方法名将会以小写字母开头,构造函数名字以大写字母开头。并且,因为与类名相同,构造函数名字通常是个名词,方法名字是个动词。
The use of "this" (this的使用)
构造函数和方法使用关键字 this 差别很大。
方法中的 this 指的是执行该方法的类的实例(instance)。静态方法(static method)不使用 this 。因为静态方法不属于任何一个类的实例,所以 this 无所指向。静态方法总体上属于一个类而非一个类的实例。
构造函数中的 this 指的是,在同一个类中拥有不同的参数列表的另一个构造函数。代码如下:
String name;
Platypus(String input) {
name = input;
}
Platypus() {
this ( " John/Mary Doe " );
}
public static void main(String args[]) {
Platypus p1 = new Platypus( " digger " );
Platypus p2 = new Platypus();
}
}
在代码中,有两个构造函数。
第一个构造函数通过一个String参数input给name进行赋值。
第二个构造函数没有参数,通过默认的名字"John/Mary Doe"来调用第一个构造函数。
如果在构造函数中使用 this,则必须在构造函数的第一行代码当中,否则编译器会报错。
注:在我这里的报错信息为 Constructor call must be the first statement in a constructor。
The use of "super"(super的使用)
方法和构造函数使用 super 的时候,指的都是超类(superclass),但也有所不同。
方法中使用 super 将会执行超类中被覆盖的方法,如下所示:
void getBirthInfo() {
System.out.println( " born alive. " );
}
}
class Platypus extends Mammal {
void getBirthInfo() {
System.out.println( " hatch from eggs " );
System.out.print( " a mammal normally is " );
super .getBirthInfo();
}
}
在上面代码中,super.getBirthInfo() 将会调用超类 Mammal 中被覆盖的方法 getBirthInfo().
构造函数中使用 super 将会调用超类中的构造函数。
如果在构造函数中使用 super,则必须在构造函数的第一行代码当中,否则编译器会报错。
注:在我这里的报错信息为 Constructor call must be the first statement in a constructor。
代码如下:
SuperClassDemo() {}
}
class Child extends SuperClassDemo {
Child() {
super ();
}
}
Complier -- supplied code(编译器提供的代码)
当编译器自动为构造函数提供代码的时候,Java初学者可能会感到困惑。如果你的类中没有构造函数,编译器将会为你自动提供一个没有参数的构造函数。如果你的代码如下:
功能上它等同于如下代码:
Example() {}
}
如果在你的构造函数的第一行代码当中没有使用 super,那么编译器会自动为你提供代码,插入 super。
如果你的代码如下:
TestConstructors() {}
}
功能上它等同于如下代码:
TestConstructors() {
super();
}
}
初学者可能会有疑问:TestConstructors 并没有继承任何类,为什么它会调用父类的构造函数呢?
答案是:在 Java 中如果没有显示的继承一个类,则默认为继承自 Object 类。
如果没有显示的声明一个构造函数,编译器自动提供一个没有参数的构造函数;如果一个构造函数没有显示的 super 调用,编译器自动提供一个没有参数的 super 调用。所以下面的两段代码在功能上是等价的:
和
Example() {
super() ;
}
}
Inheritance(继承)
下面情况有什么不对?
律师阅读类A的遗嘱。所有家庭成员围坐在大会议桌旁,并且有些人在轻声呜咽。律师说到:“我,类A,头脑清楚身体健康,将我所有的构造函数留给我的孩子”。
问题是构造函数不是通过继承得到的。然而幸运的是,子类可以自动的继承父类所有的方法,所以子类并不是一无所有。
记住:Java 方法可以通过继承得到,而构造函数不行。看下面代码:
public void sayHi {
system.out.println( " Hi " );
}
Example() {}
}
public class SubClass extends Example {
}
类 SubClass 自动继承父类的 sayHi 方法。然而,构造函数 Example() 不会被类 SubClass 所继承。
Summarizing the differences
构造函数与方法的区别就像鸭嘴兽与典型的哺乳动物一样。尤其是在目的(purpose),签名(signature),和 this 与 super 的使用方面。另外,在继承和编译器提供代码方面也有很大差异。记住所有的区别可能会非常辛苦,所以下面提供的一个表格,简单的概括了重要的差异方面。
Topic | Constructors | Methods |
---|---|---|
Purpose | Create an instance of a class | Group Java statements |
Modifiers | Cannot be abstract, final, native, static, or synchronized | Can be abstract, final, native, static, or synchronized |
Return type | No return type, not even void | void or a valid return type |
Name | Same name as the class (first letter is capitalized by convention) -- usually a noun | Any name except the class. Method names begin with a lowercase letter by convention -- usually the name of an action |
this | Refers to another constructor in the same class. If used, it must be the first line of the constructor | Refers to an instance of the owning class. Cannot be used by static methods |
super | Calls the constructor of the parent class. If used, must be the first line of the constructor | Calls an overridden method in the parent class |
Inheritance | Constructors are not inherited | Methods are inherited |
Compiler automatically supplies a default constructor | If the class has no constructor, a no-argument constructor is automatically supplied | Does not apply |
Compiler automatically supplies a default call to the superclass constructor | If the constructor makes no zero-or-more argument calls to super, a no-argument call to super is made | Does not apply |