程序员人生 网站导航

Java核心类库——内部类那点事儿

栏目:php教程时间:2017-02-06 08:05:23

学习Java的同学注意了!!! 
学习进程中遇到甚么问题或想获得学习资源的话,欢迎加入Java学习交换群,群号码:183993990  我们1起学Java!


内部类 ———定义在类的内部的类

为何需要内部类?

  典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。
  java中的内部类和接口加在1起,可以实现多继承。
  可使某些编码根简洁。
  隐藏你不想让他人知道的操作。

使用内部类最吸引人的缘由是:

  每一个内部类都能独立地继承自1个(接口的)实现,所以不管外围类是不是已继承了某个(接口的)实现,对内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,1些设计与编程问题就很难解决。从这个角度看,内部类使很多重继承的解决方案变得完全。接口解决了部份问题,而内部类有效地实现了“多重继承”。

 内部类分为: 成员内部类、静态嵌套类、方法内部类、匿名内部类。

特点:

    1、内部类依然是1个独立的类,在编译以后内部类会被编译成独立的.class文件,但是前面冠之外部类的类命和$符号。

  2、内部类可以直接或利用援用访问外部类的属性和方法,包括私有属性和方法(但静态内部类不能访问外部类的非静态成员变量和方法)。内部类所访问的外部属性的值由构造时的外部类对象决定。  

  3、而外部类要访问内部类的成员,则只能通过援用的方式进行,可问内部类所有成员

   4、访问机制:

  System.out.println(this.x);或System.out.println(x);//内部类访问内部类的成员变量或成员方法可用此方法。

  System.out.println(OuterClass.this.x);//内部类访问外部类的同名变量时可用此方法,如果没有同名可用System.out.println(x);

  5、内部类可使用任意的范围限定:public/private/protected class InnerClass,且严格依照这几种访问权限来控制内部类能使用的范围。普通类的范围限定只可以是public或不加。

   6、内部类的命名不允许与外部类 重名,内部类可以继承同级的内部类,也可继承其它类(除内部类和外部类)。

  7、内部类可以定义为接口,并且可以定义另外1个类来实现它
  8、内部类可以定义为抽象类,可以定义另外1个内部类继承它
  9、内部类使用static修饰,自动升级为顶级类,外部类不可以用static修饰,用OuterClass.InnerClass inner=new OuterClass.InnerClass();创建实例。内部类还可定义为final.

  10、内部类可以再定义内部类(基本不用)
    101、方法内的内部类:
   方法内的内部类不能加范围限定(protected public private)
   方法内的内部类不能加static修饰符

   方法内的内部类只能在方法内构建其实例
  方法内的内部类如果访问方法局部变量,则此局部变量必须使用final修饰

1)静态内部类(静态嵌套类)

  从技术上讲,静态嵌套类不属于内部类。由于内部类与外部类同享1种特殊关系,更确切地说是对实例的同享关系。而静态嵌套类则没有上述关系。它只是位置在另外一个类的内部,因此也被称为顶级嵌套类。

  静态的含义是该内部类可以像其他静态成员1样,没有外部类对象时,也能够访问它。静态嵌套类不能访问外部类的成员和方法。
语法

复制代码
 1 package com.tarena.day13;
 2 
 3 import com.tarena.day13.Foo.Koo;
 4 /**
 5  * 静态类内部语法演示
 6  */
 7 public class StaticInner {
 8  public static void main(String[] args) {
 9   Koo koo = new Koo();
10   System.out.println(koo.add());//4
11  }
12 
13 }
14 class Foo{
15  int a = 1;
16  static int b = 3;
17  /** 静态内部类,作用域类似于静态变量,属于类的 */
18  static class Koo{
19   public int add(){
20    //a ,不能访问a
21    return b+1;
22   }
23  }
24 }
复制代码

2)成员内部类

 *  1 成员内部类必须利用外部类实例创建
 *  2 成员内部类可以同享外部类的实例变量

复制代码
 1 import com.tarena.day13.inn.Goo.Moo;
 2 
 3 public class InnerClassDemo {
 4  public static void main(String[] args) {
 5   //Moo moo = new Moo(); //编译毛病,必须创建Goo的实例
 6   Goo goo = new Goo();
 7   Moo moo = goo.new Moo();//利用goo实例创建Moo实例
 8   Moo moo1 = goo.new Moo();
 9   //moo和moo1同享同1个goo实例的实例变量
10   System.out.println(moo.add());//2
11   System.out.println(moo1.add());//2
12   Goo goo1 = new Goo();
13   goo1.a = 8;
14   Moo m1 = goo1.new Moo();
15   Moo m2 = goo1.new Moo();
16   System.out.println(m1.add());//9
17   System.out.println(m2.add());//9
18   
19  }
20 }
21 class Goo{
22  int a = 1;
23  /**成员内部类*/
24  class Moo{
25   public int add(){
26    return a+1;
27   }
28  }
29 }
复制代码

 

3)局部内部类(方法内部类)
    (1)、方法内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。

  (2)、方法内部类对象不能使用该内部类所在方法的非final局部变量。 

  由于方法的局部变量位于栈上,只存在于该方法的生命期内。当1个方法结束,其栈结构被删除,局部变量成为历史。但是该方法结束以后,在方法内创建的内部类对象可能依然存在于堆中!例如,如果对它的援用被传递到其他某些代码,并存储在1个成员变量内。正由于不能保证局部变量的存活期和方法内部类对象的1样长,所之内部类对象不能使用它们。用法

复制代码
 1 package com.tarena.day13.inn;
 2 
 3 import java.util.Comparator;
 4 
 5 /**
 6  * 局部内部类
 7  */
 8 public class LocalInnerClassDemo {
 9  public static void main(String[] args) {
10   int a = 5;
11   final int b = 5;
12   //局部内部类,定义在方法内部,作用域类似于局部变量
13   //仅仅在方法内部可见
14   //在局部内部类中可以访问方法中的局部final变量
15   class Foo{
16    public int add(){
17     return  b;//正确
18     //return a;//编译毛病
19    }
20   }
21   
22   Foo foo = new Foo();
23   //临时的自定义比较规则
24   class ByLength implements Comparator<String>{
25    public int compare(String o1,String o2){
26     return o1.length()-o2.length();
27    }
28   }
29  }
30 
31 }
复制代码

 

4)匿名内部类

 顾名思义,没着名字的内部类。表面上看起来它们似乎着名字,实际那不是它们的名字。 

  匿名内部类就是没着名字的内部类。甚么情况下需要使用匿名内部类?如果满足下面的1些条件,使用匿名内部类是比较适合的:

  ·只用到类的1个实例。

  ·类在定义后马上用到。

  ·类非常小(SUN推荐是在4行代码以下)

  ·给类命名其实不会致使你的代码更容易被理解 

  在使用匿名内部类时,要记住以下几个原则: 

  ·匿名内部类不能有构造方法。

  ·匿名内部类不能定义任何静态成员、方法和类。

  ·匿名内部类不能是public,protected,private,static。

  ·只能创建匿名内部类的1个实例。

  ·1个匿名内部类1定是在new的后面,用其隐含实现1个接口或实现1个类。

  ·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效

A、继承式的匿名内部类和接口式的匿名内部类。

复制代码
 1 import java.util.Arrays;
 2 import java.util.Comparator;
 3 
 4 /**匿名内部类 语法*/
 5 public class AnnInnerClass {
 6 
 7  public static void main(String[] args) {
 8   // TODO Auto-generated method stub
 9   Yoo yoo = new Yoo();//创建Yoo的实例
10   Yoo y1 = new Yoo(){};
11   //new Yoo(){}创建匿名类实例
12   //匿名类new Yoo(){}是继承Yoo类,并且同时创建了对象
13   //new Yoo(){}是Yoo的子类型,其中{}是类体(class Body)
14   //类体中可以定义任何类内的语法,如:属性,方法,方法重载,方法覆盖,等
15   //子类型没着名字,所以叫匿名类!
16   Yoo y2 = new Yoo(){
17    public String toString(){//方法重写(覆盖)
18     return "y2"; //y2是子类的实例
19    }
20   };
21   System.out.println(y2);//"y2",调用了匿名类对象toString()
22   //匿名内部类可以继承/实现 于 类,抽象类,接口等
23   //依照继承的语法,子类型必须实现所有的抽象方法
24   
25   //Xoo x = new Xoo(){};//编译毛病,没有实现方法
26   final int b = 5;
27   Xoo xoo = new Xoo(){ //是实现接口,并且创建匿名类实例,不是创建接口对象
28    public int add(int a){//实现接口中的抽象方法
29     return a+b; //要访问局部变量b,只能访问final变量
30    }
31   };
32   System.out.println(xoo.add(5));//10,调用对象的方法
33   //Comparator接口也能够使用匿名类的方式
34   Comparator<String> byLength = new Comparator<String>(){
35    public int compare(String o1,String o2){
36     return o1.length()-o2.length();
37     
38    }
39   };
40   String[] names = {"Andy","Tom","Jerry"};
41   Arrays.sort(names,byLength);
42   System.out.println(Arrays.toString(names));
43   //也能够这样写,工作中经常使用
44   Arrays.sort(names,new Comparator<String>(){
45    public int compare(String o1,String o2){
46     return o1.length()-o2.length();
47    }
48   });
49  }
50 
51 }
复制代码

接口式的匿名内部类是实现了1个接口的匿名类。而且只能实现1个接口。

 

B。参数式的匿名内部类。

 

复制代码
 1 class Bar{   
 2     void doStuff(Foo f){
 3      }   
 4 }   
 5 interface Foo{   
 6     void foo();   
 7 }   
 8 class Test{  
 9  static void go(){  
10      Bar b = new Bar();  
11      b.doStuff(new Foo(){  
12          public void foo(){  
13              System.out.println("foofy");  
14          }   
15       }); 
16  }   
17 }
复制代码

 

 

构造内部类对象的方法有:
1、内部类在自己所处的外部类的静态方法内构建对象或在另外一个类里构造对象时利用以下情势:

(1)OuterClass out = new OuterClass();
         OuterClass.InnerClass in = out.new InnerClass();
(2)OuterClass.InnerClass in=new OuterClass().new InnerClass();
         其中OuterClass是外部类,InnerClass是内部类。
2、内部类在它所在的外部类的非静态方法里或定义为外部类的成员变量时,则可用以下方式来构造对象:
        InnerClass in = new InnerClass();
3、如果内部类为静态类,则可用以下情势来构造函数:
        OuterClass.InnerClass in = new OuterClass.InnerClass();
       无需再利用外部类的对象来来构造内部类对象,如果静态内部类需要在静态方法或其它类中构造对象就必须用上面的方式来初始化。

学习Java的同学注意了!!! 
学习进程中遇到甚么问题或想获得学习资源的话,欢迎加入Java学习交换群,群号码:183993990  我们1起学Java!

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐