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

java

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){

//...

}

}

缺省为静态的内部接口

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

以上是 从C#到Java入门指引之三——内部类 的全部内容, 来源链接: utcz.com/z/391200.html

回到顶部