论坛首页 入门技术论坛

对JAVA内部类的初步研究

浏览 1628 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-03-18  
昨天看了THANKING JAVA中的内部类,结合自己的经历,在这里做个小节,算是读后感吧
public class Parent {
protected String p ="p";   //这里的P不能为private,必须为protected或public,不然c无法调用 至于为什么,自己想想吧。
protected boolean p() {
  return true;
}
}

public class A extends Parent {
private String a = "a";
private boolean a() {
  return true;
}
public class B extends A {
  private String b = "b";
  private boolean b() {
   return true;
  }
     public void vistorAllParentClass(){
    System.out.println("b:"+b);
    System.out.println("a:"+a);
    System.out.println("p:"+p);
    System.out.println("b():"+b());
    System.out.println("a():"+a());
    System.out.println("p():"+p());
   }
}
}
public class Test {
public static void main(String[] a){
  A.B b =  new A().new B();  //注意 非静态内部类必须依赖于外围类的对象才能创建,所以有以上语法。
  b.vistorAllParentClass();
}
}
可以看出上述代码 实现了 b这个内部类能同时访问父类A,以及A的父类Parent属性极其方法,
这就间接的实现C++中的多重继承特性
同时比继承更进一步,能访问父类的PRIVATE属性及其方法!!!!
仔细看上面的代码,会发现
A.B b =  new A().new B();  这种编码方式有股坏味道。
因为如果没有研究过A类的代码,将无法了解A的继承体系,从而无法得知B,
同时将作为内部类B设置为PUBLIC暴露出A类的大量内部细节,也不是什么好的设计。
如何解决这种粗糙的编码方式呢?
这就涉及到接口了,定义一个 接口:
public interface Vistor{
  void vistorAllParentInfo();
}
然后 将A的代码改成:
public class A extends Parent {
private String a = "a";
private boolean a() {
  return true;
}
private class B extends A implements Vistor{
  private String b = "b";
  private boolean b() {
   return true;
  }
  public void vistorAllParentInfo(){
   System.out.println("b:"+b);
   System.out.println("a:"+a);
   System.out.println("p:"+p);
   System.out.println("b():"+b());
   System.out.println("a():"+a());
   System.out.println("p():"+p());
  }
}
  public Vistor getVistor(){
   return new A().new B();
  }
}
然后 将Test的代码改成:
public class Test {
public static void main(String[] args){
  A a =  new A();
  Vistor vistor = a.getVistor();
  vistor.vistorAllParentInfo();
}
}
此时就能通过 Vistor vistor = a.getVistor();
将实现了多重继承,携带了所有父类内部细节的B类以接口形式暴露出部分行为。
这种方式带来的好处出来便于使用B类,同时也体现了面向对象中的封装性,使用安全的接口操作对象的属性和行为,而无需知道实际对象的内部细节。
注意看 A中B类的访问权限是private,而Vistor是public,并且Test能捕获转型后的B类,即B的接口方法作为PUBLIC抛到了外围类。
这一点将"接口行为与具体类的实现无关"这一继承特性 体现的淋漓尽致!!!


让我们再来看看内部类是如何化解继承中"is a"的困惑的。
在编程时,我们有时会遇到这种困境:
//行为
public interface Behavior{
void addItem(String data);
void delItem(int i);
};
//数据
public class DataSource{
private List dataList = new ArrayList();
}
public class Deal{
public static void main(String[] a){
//下面我们要使用Behavior的接口来操作dataSource。 该如何办呢?
}
}
上面Deal提出的疑问我们该如何解决呢?Behavior并没有提供方法可以获取一个dataSource的应用。
简单考虑有两种方法能解决上述问题:
1 定义一个Behavior具体类BehaviorImpl 并加入方法setDataSource(DataSource data);然后操作。
2 将DataSource继承Behavior,然后重载接口行为。
来看看两种方式缺点:
首先方法1
将导致创建新类,同时Behavior的实现必须和Deal的main方法实现耦合在一起,并且暴露了Behavior与DataSource关联的细节。
因为只有在Deal的main中使用behaviorImpl.setDataSource(data);的形式来使方法1成立。
然后是方法2
DataSource继承Behavior  将导致"is a"的困惑出现:DataSource究竟是一个数据源对象还是一个行为对象呢?
这模糊DataSource对象的语义。
如果使用内部类就能解决上述问题了~~~~~~
改造下DataSource
public class DataSource{
private List dataList = new ArrayList();
public Behavior getBehavior(){
     return new Behavior(){
         public void addItem(String data){
         dataList.add(data);
         }
         public void delItem(int i){
         dataList.remove(i);
         }
     };
}
}
public class Deal{
public static void main(String[] a){
   DataSource d = new DataSource();
   Behavior b = d.getBehavior();
    b.addItem("12121";
  b.delItem(0);
}
}
这样就将具体DataSource对象的具体行为封装到DataSource中了,避免了添加新类,同时也封装了DataSource 与 Behavior的关联实现。
并且达到对象语义上的清晰-------"DataSource对象是一个数据源,并带有一个在其数据上进行操作的具体行为对象Behavior"

至于内部类对回调的支持,主要也是通过接口和匿名内部类实现,方式与上面的差不多,不说也罢。
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics