匿名类的构造函数很特殊

简介:

在上一个建议中我们讲到匿名类虽然没有名字,但可以有一个初始化块来充当构造函数,那这个构造函数是否就和普通的构造函数完全一样呢?我们来看一个例子,设计一个计算器,进行加减乘除运算,代码如下:

复制代码
 1 // 定义一个枚举,限定操作符
 2 enum Ops {
 3     ADD, SUB
 4 }
 5 
 6 class Calculator {
 7     private int i, j, result;
 8 
 9     // 无参构造
10     public Calculator() {
11     }
12 
13     // 有参构造
14     public Calculator(int _i, int _j) {
15         i = _i;
16         j = _j;
17     }
18 
19     // 设置符号,是加法运算还是减法运算
20     protected void setOperator(Ops _op) {
21         result = _op.equals(Ops.ADD) ? i + j : i - j;
22     }
23 
24     // 取得运算结果
25     public int getResult() {
26         return result;
27     }
28 }
复制代码

代码的意图是,通过构造函数输入两个int类型的数字,然后根据设置的操作符(加法还是减法)进行计算,编写一个客户端调用:

复制代码
1 public static void main(String[] args) {  
2     Calculator c1 = new Calculator(1,2) {  
3          {  
4              setOperator(Ops.ADD);  
5          }  
6     };  
7     System.out.println(c1.getResult());  
8 } 
复制代码

这段匿名类的代码非常清晰:接收两个参数1和2,然后设置一个操作符号,计算其值,结果是3,这毫无疑问,但是这中间隐藏着一个问题:带有参数的匿名类声明时到底是调用的哪一个构造函数呢?我们把这段程序模拟一下:

复制代码
1 //加法计算  
2 class Add extends Calculator {  
3      {  
4           setOperator(Ops.ADD);  
5      }  
6      //覆写父类的构造方法  
7      public Add(int _i, int _j) {  
8      }  
9 } 
复制代码

匿名类和这个Add类是等价的吗?可能有人会说:上面只是把匿名类增加了一个名字,其他的都没有改动,那肯定是等价的啦!毫无疑问!那好,你再写个客户端调用Add类的方法看看。是不是输出结果为0(为什么是0?这很容易,有参构造没有赋值)。这说明两者不等价,不过,原因何在呢?

原来是因为匿名类的构造函数特殊处理机制,一般类(也就是具有显式名字的类)的所有构造函数默认都是调用父类的无参构造的,而匿名类因为没有名字,只能由构造代码块代替,也就无所谓的有参和无参构造函数了,它在初始化时直接调用了父类的同参数构造,然后再调用了自己的构造代码块,也就是说上面的匿名类与下面的代码是等价的:

复制代码
 1 //加法计算  
 2 class Add extends Calculator {  
 3      {  
 4           setOperator(Ops.ADD);  
 5      }  
 6      //覆写父类的构造方法  
 7      public Add(int _i, int _j) {  
 8           super(_i,_j);  
 9      }  
10 } 
复制代码

它首先会调用父类有两个参数的构造函数,而不是无参构造,这是匿名类的构造函数与普通类的差别,但是这一点也确实鲜有人细细琢磨,因为它的处理机制符合习惯呀,我传递两个参数,就是希望先调用父类有两个参数的构造,然后再执行我自己的构造函数,而Java的处理机制也正是如此处理的!

 


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5430256.html,如需转载请自行联系原作者

相关文章
|
2月前
|
C++
派生类的构造函数
派生类的构造函数
51 9
|
1月前
静态方法和实例方法有何不同?
静态方法和实例方法的区别主要体现在两个方面: 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制
|
3月前
|
编译器 C++
C++ 类构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
81 30
|
2月前
|
Java 程序员 C#
【类的应用】C#应用之派生类构造方法给基类构造方法传参赋值
【类的应用】C#应用之派生类构造方法给基类构造方法传参赋值
15 0
|
7月前
|
编译器 C++
C++程序中的派生类构造函数
C++程序中的派生类构造函数
69 1
|
JavaScript 前端开发
构造函数。
构造函数。
44 1
|
编译器 C++
C++中虚继承时的构造函数
在虚继承中,虚基类是由最终的派生类初始化的,换句话说,最终派生类的构造函数必须要调用虚基类的构造函数。对最终的派生类来说,虚基类是间接基类,而不是直接基类。这跟普通继承不同,在普通继承中,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。 下面我们以菱形继承为例来演示构造函数的调用: #include <iostream> using namespace std; //虚基类A class A{ public: A(int a); protected: int m_a; }; A:
115 1
|
编译器
匿名对象与构造器
匿名对象与构造器
80 0
为什么子类会调用父类无参的构造函数
为什么子类会调用父类无参的构造函数
|
Java 编译器
构造函数中为什么要用this关键字?
构造函数中为什么要用this关键字?
82 0

热门文章

最新文章