内部类(转载)

来源:互联网 发布:手机游戏网络修改器 编辑:程序博客网 时间:2024/05/16 05:18

内部类详解
1、定义
  一个类的定义放在另一个类的内部,这个类就叫做内部类。

Java代码  

public class First {   

public class Contents{   

    public void f(){   

    System.out.println("In Class First's inner Class Contents method f()");   

    }   

}   

 }  

 public class First {

   public class Contents{

       public void f(){

      System.out.println("In Class First's inner Class Contents method f()");

       }

   }

  }


像这样的,Contents就叫做内部类
内部类了解外围类,并能与之通信(后面详细讲)

2、链接到外围类
  创建了内部类对象时,它会与创造它的外围对象有了某种联系,于是能访问外围类的所有成员,不需任何特殊条件。
 

Java代码  

   public class First {   

public class Contents{   

         public void getStr(){   

        System.out.println("First.str="+str);   

     }   

}   

private String str;   

    }   

   

    public class First {

   public class Contents{

         public void getStr(){

         System.out.println("First.str="+str);

        }

   }

   private String str;

     }

 


  在内部类Contents中,可以使用外围类First的字段str。
  那么,它是如何实现的呢?
  是这样的,用外围类创建内部类对象时,此内部类对象会秘密的捕获一个指向外围类的引用,于是,可以通过这个引用来访问外围类的成员。
  通常,这些都是编译器来处理,我们看不到,也不用关心这个。
  正是因为如此,我们创建内部类对象时,必须与外围类对象相关联。
  注:嵌套类(后面会讲到)除外。

3、使用关键字.this与.new
  内部类中得到当前外围类对象的引用,可以使用.this关键字,注意与new的区别
 

Java代码  

    private int num ;   

public Test2(){   

       

}   

  

public Test2(int num){   

    this.num = num;   

}   

  

private class Inner{   

    public Test2 getTest2(){   

        return Test2.this;   

    }   

       

    public Test2 newTest2(){   

        return new Test2();   

    }   

}   

  

public static void main(String [] args){   

    Test2 test = new Test2(5);   

    Test2.Inner inner = test.new Inner();   

    Test2 test2 = inner.getTest2();   

    Test2 test3 = inner.newTest2();   

    System.out.println(test2.num);   

    System.out.println(test3.num);   

}   

   

     private int num ;

   public Test2(){

     

   }

  

   public Test2(int num){

      this.num = num;

   }

  

   private class Inner{

      public Test2 getTest2(){

         return Test2.this;

      }

     

      public Test2 newTest2(){

         return new Test2();

      }

   }

  

   public static void main(String [] args){

      Test2 test = new Test2(5);

      Test2.Inner inner = test.new Inner();

      Test2 test2 = inner.getTest2();

      Test2 test3 = inner.newTest2();

      System.out.println(test2.num);

      System.out.println(test3.num);

   }

 


  输出结果为5 0
  使用.this后,得到时创建该内部类时使用的外围类对象的引用,new则是创建了一个新的引用。

  .new关键字
  如果想直接创建一个内部类对象,而不是通过外围类对象的方法来得到,可以使用.new关键字
  形式是这样的:
 

Java代码  

OutClass.InnerClass obj = outClassInstance.new InnerClass();   

    OutClass.InnerClass obj = outClassInstance.new InnerClass();

 


  必须是外围类对象.new,而不能是外围类.new
 

Java代码  

   public class First {   

public class Contents{   

    public void f(){   

        System.out.println("In Class First's inner Class Contents method f()");   

    }   

    public void getStr(){   

        System.out.println("First.str="+str);   

    }   

}   

  

public static void main(String [] args){   

    First first = new First();   

    First.Contents contents = first.new Contents();   

    contents.f();   

}   

    }       public class First { public class Contents{

      public void f(){

         System.out.println("In Class First's inner Class Contents method f()");

      }

      public void getStr(){

         System.out.println("First.str="+str);

      }

   }

  

   public static void main(String [] args){

      First first = new First();

      First.Contents contents = first.new Contents();

      contents.f();

   }

     }

 


  必须通过外围类First的对象first来创建一个内部类的对象
  而且需要注意的是,在创建外围类对象之前,不可能创建内部类的对象(嵌套类除外)。
4、内部类与向上转型
  将内部类向上转型为基类型,尤其是接口时,内部类就有了用武之地。
 

Java代码  

    public interface Shape {   

public void paint();   

    }   

    public class Painter {   

       

       private class InnerShape implements Shape{   

    public void paint(){   

        System.out.println("painter paint() method");   

    }   

}   

  

public Shape getShape(){   

    return new InnerShape();   

}      

       

       public static void main(String []args){   

    Painter painter = new Painter();   

    Shape shape = painter. getShape();   

    shape.paint();   

}   

    }   

   

     public interface Shape {

   public void paint();

     }

     public class Painter {

    

        private class InnerShape implements Shape{

      public void paint(){

         System.out.println("painter paint() method");

      }

   }

  

   public Shape getShape(){

      return new InnerShape();

   }  

    

        public static void main(String []args){

      Painter painter = new Painter();

      Shape shape = painter. getShape();

      shape.paint();

   }

     }

 


  此时,内部类是private的,可以它的外围类Painter以外,没人能访问。
  这样,private内部类给累的设计者提供了一种途径,通过这种方式可以完全阻止任何依赖于类型的编码,并完全隐藏实现的细节。

5、方法内的类
  可以在方法内创建一个类。
 

Java代码  

public void test(){   

ass Inner{   

 public void method(){   

ystem.out.println("在方法内创建的类");   

 }   

  

}   

   public void test(){

   class Inner{

      public void method(){

      System.out.println("在方法内创建的类");

      }

   }

   }

 


  值得注意的是:方法内创建的类,不能加访问修饰符。
  另外,方法内部的类也不是在调用方法时才会创建的,它们一样也被编译了(怎么知道的?后面会有讲解)。

6、匿名内部类
 

Java代码  

  public class Painter {   

ublic Shape getShape(){   

return new Shape(){   

    public void paint(){   

        System.out.println("painter paint() method");   

    }   

};   

  

      public static void main(String [] args){   

            Painter painter = new Painter();   

            Shape shape = painter.getShape();   

            shape.paint();   

      }   

  }   

  public interface Shape {   

ublic void paint();   

  }   

    public class Painter {

   public Shape getShape(){

      return new Shape(){

         public void paint(){

            System.out.println("painter paint() method");

         }

      };

   }

        public static void main(String [] args){

              Painter painter = new Painter();

              Shape shape = painter.getShape();

              shape.paint();

        }

    }

    public interface Shape {

   public void paint();

    }

 

 


  注意,匿名内部类后面的分号不可缺少!
   匿名类,顾名思义,就是没有名称。
  getShape()方法里,就使用了匿名内部类。
  看上去很奇怪,不符合传统的写法?
  第一眼看上去确实是这样的。

  这样写,意思是创建了一个实现了Shape的匿名类的对象。
  匿名类可以创建,接口,抽象类,与普通类的对象。创建接口时,必须实现接口中所有方法。
 
  这是无参的,如果需要参数呢?
  可以直接传。
 

Java代码  

   public class B {   

public A getA(int num){   

    return new A(num){   

           

    };   

}   

   }   

   public class A {   

private int num;   

public A(int num){   

    this.num = num;   

}   

public A(){   

       

}   

   }   

   

    public class B {

   public A getA(int num){

      return new A(num){

        

      };

   }

    }

    public class A {

   private int num;

   public A(int num){

      this.num = num;

   }

   public A(){

     

   }

    }

 


  Ok,在这个例子中,可以为A的构造方法传入一个参数。在匿名内部类中,并没有使用到这个参数。
  如果使用到了这个参数,那么这个参数就必须是final的。
 

Java代码  

   public class B {   

public A getA(final int num){   

    return new A(num){   

       public int getNum(){   

                     return num;   

                  }   

    };   

}   

   }   

   public class A {   

private int num;   

public A(int num){   

    this.num = num;   

}   

public A(){   

       

}   

   }       public class B {

   public A getA(final int num){

      return new A(num){

         public int getNum(){

                      return num;

                   }

      };

   }

    }

    public class A {

   private int num;

   public A(int num){

      this.num = num;

   }

   public A(){

     

   }

    }

 


  如果不是final的,编译器就会提示出错。
  另外,还可以在匿名内部类里定义属性
  由于类是匿名的,自然没有构造器,如果想模仿构造器,可以采用实例初始化({})

Java代码  

   public A getA(){   

return new A(){   

    int num = 0;   

    String str;   

    {   

        str = "javaeye";   

        System.out.println("hello robbin");   

    }   

};   

   }       public A getA(){

   return new A(){

      int num = 0;

      String str;

      {

         str = "javaeye";

         System.out.println("hello robbin");

      }

   };

    }

 


  匿名内部类通过实例初始化,可以达到类似构造器的效果~

另外可以通过匿名内部类来改造工厂方法。

Java代码  

  public interface Service {   

public void method1();   

  }   

  public interface ServiceFactory {   

Service getService();   

  }   

  public class Implemention1 implements Service{   

public void method1(){   

    System.out.println("In Implemention1 method method1()");   

}   

  

public static ServiceFactory factory = new ServiceFactory(){   

    public Service getService(){   

        return new Implemention1();   

    }   

};   

  }   

  public class Implemention2 implements Service {   

public void method1(){   

    System.out.println("in Implemention2 method method1()");   

}   

  

public static ServiceFactory factory = new ServiceFactory(){   

    public Service getService(){   

        return new Implemention2();   

    }   

};   

  

  }   

  public class Test {   

public static void main(String []args){   

    service(Implemention1.factory);   

    service(Implemention2.factory);   

       

    ServiceFactory factory1 = Implemention1.factory;   

    Service service1 = factory1.getService();   

    service1.method1();   

       

    ServiceFactory factory2 = Implemention1.factory;   

    Service service2 = factory2.getService();   

    service2.method1();   

}   

  }   

   public interface Service {

   public void method1();

   }

   public interface ServiceFactory {

   Service getService();

   }

   public class Implemention1 implements Service{

   public void method1(){

      System.out.println("In Implemention1 method method1()");

   }

  

   public static ServiceFactory factory = new ServiceFactory(){

      public Service getService(){

         return new Implemention1();

      }

   };

   }

   public class Implemention2 implements Service {

   public void method1(){

      System.out.println("in Implemention2 method method1()");

   }

  

   public static ServiceFactory factory = new ServiceFactory(){

      public Service getService(){

         return new Implemention2();

      }

   };

  

   }

   public class Test {

   public static void main(String []args){

      service(Implemention1.factory);

      service(Implemention2.factory);

     

      ServiceFactory factory1 = Implemention1.factory;

      Service service1 = factory1.getService();

      service1.method1();

     

      ServiceFactory factory2 = Implemention1.factory;

      Service service2 = factory2.getService();

      service2.method1();

   }

   }

 


在Implemention1和2中匿名内部类用在字段初始化地方。
这样定义的工厂方法,代码上看起来是不是优雅一些?
7、嵌套类
static的内部类就叫做嵌套类
前面提到了很多次,嵌套类是个例外
使用嵌套类时有两点需要注意:
   a、创建嵌套类对象时,不需要外围类
   b、在嵌套类中,不能像普通内部类一样访问外围类的非static成员

Java代码  

  public class StaticClass {   

private int num;   

private static int sum = 2;   

private static class StaticInnerClass{   

    public int getNum(){   

    //只能访问sum,不能访问num   

               return sum;   

    }   

}   

  }   

  public class Test {   

public static void main(String [] args){   

               //可以直接通过new来创建嵌套类对象   

    StaticClass.StaticInnerClass inner = new StaticClass.StaticInnerClass();   

    inner.getNum();   

}   

  }   

   public class StaticClass {

   private int num;

   private static int sum = 2;

   private static class StaticInnerClass{

       public int getNum(){

      //只能访问sum,不能访问num

                return sum;

       }

   }

   }

   public class Test {

   public static void main(String [] args){

                //可以直接通过new来创建嵌套类对象

      StaticClass.StaticInnerClass inner = new StaticClass.StaticInnerClass();

      inner.getNum();

   }

   }

 


  另外,嵌套类还有特殊之处,就是嵌套类中可以有static方法,static字段与嵌套类,而普通内部类中不能有这些。

  8、内部类标识符
  我们知道每个类会产生一个.class文件,文件名即为类名
  同样,内部类也会产生这么一个.class文件,但是它的名称却不是内部类的类名,而是有着严格的限制:外围类的名字,加上$,再加上内部类名字。
  前面说到得定义在方法内的内部类,不是在调用方法时生成,而是与外围类一同编译,就可以通过查看.class文件的方式来证明。

  9、为何要内部类?
    a、内部类提供了某种进入外围类的窗户。
    b、也是最吸引人的原因,每个内部类都能独立地继承一个接口,而无论外围类是否已经继承了某个接口。
  因此,内部类使多重继承的解决方案变得更加完整。
  在项目中,需要多重继承,如果是两个接口,那么好办,接口支持多重继承。
  如果是两个类呢?这时只有使用内部类了。
 

Java代码  

   public interface One {   

public void inOne();   

   }   

   public interface Two {   

public void inTwo();   

   }   

   //两个接口,用普通类就可实现多重继承   

   public class CommonClass implements One,Two {   

public void inOne(){   

    System.out.println("CommonClass inOne() method");   

}   

  

public void inTwo(){   

    System.out.println("CommonClass inTwo() method");   

}   

   }   

   public abstract class Three {   

public abstract void inThree();   

   }   

   public abstract class Four {   

public abstract void inFour();   

   }   

   //两个抽象类,使用普通类无法实现多重继承   

      

   //使用内部类可以实现   

   public class Contents extends Three {   

public void inThree(){   

    System.out.println("In Contents inThress() method");   

}   

  

public class InnerFour extends Four{   

    public void inFour(){   

        System.out.println("In Contents");   

    }   

       

}   

   }   

   

    public interface One {

   public void inOne();

    }

    public interface Two {

   public void inTwo();

    }

    //两个接口,用普通类就可实现多重继承

    public class CommonClass implements One,Two {

   public void inOne(){

      System.out.println("CommonClass inOne() method");

   }

  

   public void inTwo(){

      System.out.println("CommonClass inTwo() method");

   }

    }

    public abstract class Three {

   public abstract void inThree();

    }

    public abstract class Four {

   public abstract void inFour();

    }

    //两个抽象类,使用普通类无法实现多重继承

   

    //使用内部类可以实现

    public class Contents extends Three {

   public void inThree(){

      System.out.println("In Contents inThress() method");

   }

  

   public class InnerFour extends Four{

      public void inFour(){

         System.out.println("In Contents");

      }

     

   }

    }

 


  另外,还有好多地方可以使用内部类。读过hibernate源代码的同学,应该可以发现,里面有好多内部类。
  最常见的内部类,应该是Map.Entry了,可以看看源代码~ 

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机QQ浏览器看视频有广告怎么办 手机显示网络连接但不可上网怎么办 华为手机关机后开不了机怎么办 华为畅享8p相机拍照模糊怎么办 手机触屏不准怎么办荣耀青春版九 华为手机锁屏手势密码忘了怎么办 荣耀手机锁屏密码忘了怎么办 华为p20隐私空间密码忘了怎么办 安全管家隐私保护的密码忘了怎么办 华为手机自带截图键删除了怎么办 飞科电吹风吹一会就断电怎么办 住酒店时电吹风吹坏了怎么办 把话费充到停机的号码上去了怎么办 电信手机卡充值了还停机怎么办 电信手机一直没用却欠费了怎么办 苹果se开起4g信号不好怎么办 触屏华为手机充不了电怎么办 华为手机自拍出来的字反向怎么办 华为微信隐藏了怎么弄出来怎么办 酷派手机酷管家密码忘了怎么办 手机磁盘目录不具有读写权限怎么办 魅族手机像素突然变模糊了怎么办 手机忽然所有软件都没了怎么办 魅族读书下架的书怎么办 我的电信大王卡激活了没信号怎么办 三星翻盖手机忘记锁屏密码怎么办 小米2s电信版信号不好怎么办 4s微信版本过低怎么办 换了一个城市牵的电信网线怎么办 联通电话卡注销了里面的钱怎么办 红米4a上网太慢怎么办 华为光猫网线接囗接触不良怎么办? 苹果电信4g信号变3g怎么办 苹果7的4g变3g了怎么办 华为路由器的登录密码忘记了怎么办 华为手机有4g但不能上网怎么办 移动4g 手机开密码忘了怎么办 华为安卓8.0屏幕上圆怎么办 苹果5s不能用4g怎么办 电动车的锁住了钥匙丢了怎么办 小米蓝牙耳机青春版开不了机怎么办