java 中构造方法是一个重要的概念, 初学时有人会对此构造方法的使用特别是其作用不清楚, 下面我就来谈谈我对 java 中构造方法的理解, 有不对或不清楚的地方希望各位看官提出意见, 谢谢!
一. 构造方法的定义声明
构造方法的名字必须和所在类的名字一致, 没有返回值, 但不能声明 void, 访问权限可以为任意, 但是一般情况下使用 public 方法权限, 构造方法中的参数可以根据需要自行定义, 参数的不同的构造方法构成重载;
例:
- class Fu
- {
- public Fu(){} // 无参的公有构造方法
- public Fu(int i){} // 参数类型为 int 的公有构造方法
- ......
- }
- public class Demo extends Fu
- {
- public Demo(){} // 无参的公有构造方法
- public Demo(int i){} // 参数类型为 int 的公有构造方法
- public Demo(int i,double d){} // 参数类型为 int 和 double 的公有构造方法
- ...
- }
二. 构造方法的使用
java 中构造方法的使用有两个地方, 一个是跟在关键字 new 后面, 类名加上一个小括号 (), 小括号内根据实际加上实参, 另外一个是跟在关键字 super 或 this 后加上一个小括号 (), 小括号内根据实际添加实参, 下面进行举例.
例 1:
Demo demo = new Demo(); // 这里是调用的是一个无参的构造方法, 必须声明在方法中, 最好声明在主方法
上面构造方法的参数根据实际添加实参, jvm 根据构造方法的参数不同加载不同的构造方法;
例 2:
- public Demo(){
- this(2); // 这里调用参数为 int 类型的本类的构造方法
- }
例 3:
- public Demo(){
- super(1); // 调用参数为 int 类型的父类的构造方法
- }
注意: 例 2 和例 3 中 this 或 super 调用构造方法只能出现在构造方法中, 而且必须出现在第一行, 所以一个构造方法中第一行只能为 this 或 super 调用构造方法, 两者不能同时调用构造方法出现, 而且注意 this 或 super 调用构造方法时, 要留构造方法出口, 意思就是最后调用的构造方法中没有再调用别的构造方法!
三. 构造方法的作用
1. 为了初始化成员属性, 而不是初始化对象, 初始化对象是通过 new 关键字实现的
2. 通过 new 调用构造方法初始化对象, 编译时根据参数签名来检查构造函数, 称为静态联编和编译多态
(参数签名: 参数的类型, 参数个数和参数顺序)
3. 创建子类对象会调用父类构造方法但不会创建父类对象, 只是调用父类构造方法初始化父类成员属性;
我总是要把构造器和方法混淆, 后来发现,
方法, 实际上, 是需要用于执行 java 代码的, 而构造器,
构造器,,, 是一个类的实例!!
为什么呢?
类的实例, 我们需要用类来创建对象, 进而访问其属性, 因为实例是需要被用来调用的, 但是调用的话, 我们不得不去考虑一个问题, 就是对象, 最终是被存储在内存里面的, 而存储的时候, 我们的内存不得不需要给他再另外开辟新的内存空间, 那么, java 是如何给这种我们所需要的类来开辟内存空间的呢? 这就涉及到了 java 的内存机制, 就是说, 我们必须要给这个类制作一个构造器, 而且这个构造器的名称必须和这个类的名称是一致的, 这样, 我们的 java 编译器才能识别这个类, 进而给这个类在内存中开辟内存空间, 也就是我们所说的, 我们手动, 人为的给他进行 "初始化", 事例如下:
- class Rock {
- Rock() {
- System.out.print("Rock");
- }
- }
这样, 当我们在对 Rock 类进行调用的时候, 我们的 java 编译器就会事先对他进行 "自动" 地初始化, 开辟内存空间
那么现在问题又来了, 举个例子, 我们的 Rock() 方法需要带有一个参数, 形参, 但是整个代码中, 需要不仅仅是带有形参的 Rock(); 还需要不带形参的 Rock(), 在我们的构造器对类进行构造的时候, 需要将功能类似的, 但形参不同的方法同时打包在该类下, 以便在我们调用某个方法的时候, 直接重载构造器中的该方法, 可以说, 这种构造形式, 满足了我们对功能类似, 形参不同的方法, 调用的时候, 进行重载, 而满足了编译器自动初始化, 人不需要手动初始化的需求.
而且有个, 问题, 本来两个方法, 功能上是类似的, 一棵树和一株树苗, 你非得要给他们起不同的名字, 多别扭, 好在有了构造器, 能够是功能相似的方法起相同的名字, 不同的参数, 而能够在被调用的时候得以重载, 多么牛逼的构造器 啊
我们说构造器是一种方法, 就象讲澳大利亚的鸭嘴兽是一种哺育动物.(按: 老外喜欢打比喻, 我也就照着翻译). 要理解鸭嘴兽, 那么先必须理解它和其他哺育动物的区别. 同样地, 要理解构造器, 那么就要了解构造器和方法的区别. 所有学习 java 的人, 尤其是对那些要认证考试的, 理解构造器是非常重要的. 下面将简单介绍一下 , 最后用一个表作了些简单的总结.
功能和作用的不同
构造器是为了创建一个类的实例. 这个过程也可以在创建一个对象的时候用到: Platypus p1 = new Platypus();
相反, 方法的作用是为了执行 java 代码.
修饰符, 返回值和命名的不同
构造器和方法在下面三个方便的区别: 修饰符, 返回值, 命名. 和方法一样, 构造器可以有任何访问的修饰: public, protected, private 或者没有修饰 (通常被 package 和 friendly 调用). 不同于方法的是, 构造器不能有以下非访问性质的修饰: abstract, final, native, static, 或者 synchronized.
返回类型也是非常重要的. 方法能返回任何类型的值或者无返回值 (void), 构造器没有返回值, 也不需要 void.
最后, 谈谈两者的命名. 构造器使用和类相同的名字, 而方法则不同. 按照习惯, 方法通常用小写字母开始, 而构造器通常用大写字母开始. 构造器通常是一个名词, 因为它和类名相同; 而方法通常更接近动词, 因为它说明一个操作.
"this" 的用法
构造器和方法使用关键字 this 有很大的区别. 方法引用 this 指向正在执行方法的类的实例. 静态方法不能使用 this 关键字, 因为静态方法不属于类的实例, 所以 this 也就没有什么东西去指向. 构造器的 this 指向同一个类中, 不同参数列表的另外一个构造器, 我们看看下面的代码:
- public class Platypus {
- 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();
- }
- }
在上面的代码中, 有 2 个不同参数列表的构造器. 第一个构造器, 给类的成员 name 赋值, 第二个构造器, 调用第一个构造器, 给成员变量 name 一个初始值 "John/Mary Doe".
在构造器中, 如果要使用关键字 this, 那么, 必须放在第一行, 如果不这样, 将导致一个编译错误.
"super" 的用法
构造器和方法, 都用关键字 super 指向超类, 但是用的方法不一样. 方法用这个关键字去执行被重载的超类中的方法. 看下面的例子:
- class Mammal {
- 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 中被重载的方法.
构造器使用 super 去调用超类中的构造器. 而且这行代码必须放在第一行, 否则编译将出错. 看下面的例子:
- public class SuperClassDemo {
- SuperClassDemo() {
- }
- }
- class Child extends SuperClassDemo {
- Child() {
- super();
- }
- }
在上面这个没有什么实际意义的例子中, 构造器 Child() 包含了 super, 它的作用就是将超类中的构造器 SuperClassDemo 实例化, 并加到 Child 类中.
编译器自动加入代码
编译器自动加入代码到构造器, 对于这个, java 程序员新手可能比较混淆. 当我们写一个没有构造器的类, 编译的时候, 编译器会自动加上一个不带参数的构造器, 例如: public class Example {}
编译后将如下代码:
- public class Example {
- Example() {
- }
- }
在构造器的第一行, 没有使用 super, 那么编译器也会自动加上, 例如:
- public class TestConstructors {
- TestConstructors() {
- }
- }
编译器会加上代码, 如下:
- public class TestConstructors {
- TestConstructors() {
- super;
- }
- }
仔细想一下, 就知道下面的代码
public class Example {}
经过会被编译器加代码形如:
- public class Example {
- Example() {
- super;
- }
- }
继承
构造器是不能被继承的. 子类可以继承超类的任何方法. 看看下面的代码:
- public class Example {
- public void sayHi {
- system.out.println("Hi");
- }
- Example() {
- }
- }
- public class SubClass extends Example {
- }
类 SubClass 自动继承了父类中的 sayHi 方法, 但是, 父类中的构造器 Example() 却不能被继承.
总结
主题 构造器 方法
功能 建立一个类的实例 java 功能语句
修饰 不能用 bstract, final, native, static, or synchronized 能
返回类型 没有返回值, 没有 void 有返回值, 或者 void
命名 和类名相同; 通常为名词, 大写开头 通常代表一个动词的意思, 小写开头
this 指向同一个类中另外一个构造器, 在第一行 指向当前类的一个实例, 不能用于静态方法
super 调用父类的构造器, 在第一行 调用父类中一个重载的方法
继承 构造器不能被继承 方法可以被继承
编译器自动加入一个缺省的构造器 自动加入 (如果没有) 不支持
编译器自动加入一个缺省的调用到超类的构造器 自动加入 (如果没有) 不支持
来源: http://www.jianshu.com/p/6c71b11f2e15