从C#到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