从C#到Java入门指引之三——内部类

来源:互联网 发布:windows education 编辑:程序博客网 时间:2024/06/07 06:00

C#和Java对static关键字的理解有很大分歧,主要就是在内部类上。此外,由于Java没有类似委托这种数据结构,内部类还要担当封装方法和响应事件这样的重要责任。

从C#到Java入门指引之一——基本类型和字符串
从C#到Java入门指引之二——类
从C#到Java入门指引之三——内部类

截然不同的内部类

与C#不一样,Java不允许外部类使用static关键字修饰。那么我们来看看static关键字修饰内部类的一个例子(来自《细说Java》)

public class Circle {    private static int radius;    public static class Center{        // 静态内部类也可声明静态成员        private static Center defaultCenter;        static {            defaultCenter = new Center(10, 10);            // 访问外部类的私有成员            System.out.println(radius);        }         public int x, y;        public Center(int x, int y){            this.x = x;            this.y = y;        }    }} public class Main{    public static void main(String[] args){        // 静态内部类可以不依赖外部来实例的存在而存在        Circle.Center center = new Circle.Center(15, 20);    }}

习惯C#的同学只怕又会觉得纳闷,明明这个内部类都static了,为啥还有构造方法?!
这是两种语言对static的不同解读造成的:
在C#中,static修饰内部类,表示这是个不能够实例化的静态类;而在Java中,这表示这个内部类可以不依赖于外部类的实例而实例化。

所以,Java中加了static的内部类相当于C#中普通的内部类。
那么,没加static修饰的内部类,又表示什么呢?自然是依赖于外部类的实例才能实例化的内部类嘛!

public class Circle {    private int radius;    public class Center{        // 普通内部类也可声明静态成员        //private static Center defaultCenter;         // 但是可以含有静态常量        private static final int FINAL_STATIC = 10;         public int x, y;        private int radius;        public Center(int x, int y){            this.x = x;            this.y = y;            radius = 3; // 访问内部类的成员            this.radius = 3; // this指向内部类            Circle.this.radius = 3; // Circle.this指向外部类        }    }} public class Main{    public static void main(String[] args){        // 普通内部类必须依赖外部类的实例        //Circle.Center center = new Circle.Center(15, 20);         // 必须先创建外部类的实例        Circle circle = new Circle();        Circle.Center center = circle.new Center(15, 20);    }}

看到创建内部类实例的那行代码,是否觉得很别扭?
没错,而且如果又涉及到继承的话,比如继承某个类的内部类,那就更加繁琐了。所以我的建议是,非static的内部类,能不用就不用。

方法内声明的局部类

普通内部类可以在语句块(比如方法)内声明,那就是局部类。
局部类只在当前语句块内可访问。
局部类可以访问语句块中的局部变量(但必须用final修饰),以及外部类中的成员。

更为常用的匿名类

如果局部类只是用一次,就可以声明为匿名类。例子同样来自《细说Java》:

interface Center{} public class Circle {    public Center getCenter(final int pointX, final int pointY){        return new Center(){            public int x, y;            {                x = pointX;                y = pointY;            }        };    }} public class Main{    public static void main(String[] args){        Circle circle = new Circle();        Center center = circle.getCenter(10, 15);    }}

匿名类不能声明构造方法,所以只能用初始化块的方式对成员初始化。
匿名类也不是new后面的那个类型:如果new后面是一个类,那么匿名类的类型是这个类的子类;如果new后面是一个接口,那么匿名类的类型是这个接口的一个实现。

比如我们常常会给Activity添加一个Handler,以处理各种消息。每个Activity的Activity各不相同,所以也就没有重用的必要,用匿名类即可:

private Handler mHandler = new Handler() {    @Override    public void handleMessage(Message msg) {        //...    }};

匿名类用于封装方法

许多时候,我们需要把方法当成一个变量处理,传给另一个方法。C/C++可以用函数指针,C#可以用委托。Java没有比较直观的方式,但一般可以这么做:
1.创建接口IFunc,里面放一个方法的原型,比如void func();
2.创建实现了IFunc的类FuncClass,实现其中的func方法;
3.创建类FuncClass的对象funcObject,传递给别的方法。

很麻烦是不,好在有匿名类,可以将创建类和创建对象合成一步。比如,想要把一段代码放到新线程去跑,就得把代码塞到很麻烦是不,好在有匿名类,可以将创建类和创建对象合成一步。
比如,想要把一段代码放到新线程去跑,就需要创建Runnable接口的实现,把代码塞到run方法,传给Thread的构造方法:

Thread thread = new Thread(new Runnable() {    @Override    public void run() {        //...    }});thread.start();

注:实际使用时,只需要直接重写Thread的run方法,这么写其实是绕了弯路。

实现那个方法人们会把需要传递的方法放在一个类里面,然后用这个类创建一个对象,通过传递这个对象来实现传递方法。这时候,匿名类就可以大显身手了。

匿名类与事件响应机制

许多时候,我们需要把方法当成一个变量处理,传给另一个方法。C/C++可以用函数指针,C#可以用委托,但Java没有比较直观的方式。通常,在Java代码中,人们会把需要传递的方法放在一个类里面,然后用这个类创建一个对象,通过传递这个对象来实现传递方法。这时候,匿名类就可以大显身手了。

最简单的例子,响应按钮的点击事件:

mButton.setOnClickListener(new View.OnClickListener(){    @Override    public void onClick(View view){        //...    }}

缺省为静态的内部接口

声明在类内部的接口,即为内部接口。
内部接口缺省就是静态的————这个也容易理解,既然是接口,难道还要依赖于外部类的实例而存在么。

 

 


<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>