将某个class定义置于另一个class定义之中是可行的,这就是内部类。
内部类基础
内部类一般来说包括以下几种:成员内部类,局部内部类,匿名内部类,静态内部类。
- 成员内部类
成员内部类是最普通的内部类,定义在一个外部类的内部,如下:
class Circle {
double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println("drawshape");
}
}
}
看起来Draw就像是Circle的一个成员,Circle是外部类。成员内部类可以无条件访问外部类的成员属性和成员方法(包括私有和静态成员),如下:
class Circle {
private double radius = 0;
public static int count =1;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
System.out.println(count); //外部类的静态成员
}
}
}
不过需要注意的是,如果内部类里面有和外部类同名的成员变量或者方法时,默认的是访问成员内部类的成员,如果要访问外部类的成员,需要用一下形式访问:
外部类.this.成员变量
外部类.this.成员方法
虽然成员内部类可以无条件访问外部类的成员,但是外部类想要访问成员内部类的成员就没有这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个内部类对象,在调用这个对象的引用来访问:一般都会申明一个方法,返回一个reference指向内部类。
class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe(); //必须先创建成员内部类的对象,再进行访问
}
private Draw getDrawInstance() {
return new Draw();
}
class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
}
}
}
成员内部类是依靠于外部类存在的,如果要创建内部类对象,必须现有外部类对象。创建成员内部类对象的一般方式如下
public class Test {
public static void main(String[] args) {
//第一种方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner(); //必须通过Outter对象来创建
//第二种方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
成员内部了可以有private protected public访问权限。如果成员内部类使用private修饰,则只能在外部类的内部访问。如果使用public访问,则任何地方可以访问,如果protected修饰,在同一个包下或者继承了外部类的情况下访问。外部类就不能用private修饰。
- 局部内部类
局部内部类是定义在一个method,或者是一个scope里面的类,他和成员内部类的区别在于:局部内部类的访问权限仅限于作用method和作用scope中
定义在方法中:
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
}
定义在作用域中:
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("chenssy");
String string = ts.getSlip();
}
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}
局部内部类就像是一个局部变量一样,所以是没有private public protected等修饰符的。
- 匿名内部类
匿名内部类是我们比较常见的,在编写事件监听的代码时候,使用匿名内部类不仅方便,而且代码更容易维护,下面这段代码是Android事件 监听代码。
scan_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
history_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
这段代码是为两个按钮设置监听器,这里面就使用了匿名内部类,这段代码中:
new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
代码中需要给按钮设置监听器对象,所以匿名内部类能够在实现父类或者接口方法情况下,同时产生一个相应的对象,但是前提是这个父类或者接口实现存在。当然像下面这种方法也是一样的效果。
private void setListener()
{
scan_bt.setOnClickListener(new Listener1());
history_bt.setOnClickListener(new Listener2());
}
class Listener1 implements View.OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
class Listener2 implements View.OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
这样的代码荣长也难以维护,所以一般匿名内部类的方法用来编写事件监听的代码,同样的匿名内部类也是不能有访问修饰符修饰。
匿名内部类是唯一没有构造器的类,正是因为没有构造器,所以匿名内部类的范围比较有限,大部分匿名内部类用于接口回调,一般来说,匿名内部类适用于继承其他类或者实现接口,并不需要增加额外的方法,只是对继承方法或者接口的重写或者实现。
- 静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。