内部类就是在一个外部类的内部在定义一个类。
java中的内部类共分为四种:
成员内部类(member inner class)
局部内部类(local inner class)
静态内部类(static inner class/nested class)
匿名内部类(anonymous inner class)
为什么需要内部类?
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

【1】成员内部类(作为外部类的一个成员存在,与外部类的属性方法并列)

/*
* 成员内部类
*
*/
public class Outer1 {
  private static int i = 1 ;
  private int j = 10 ;
  private int k = 20 ;
  public static void method1(){
    System.out.println("-----数据1-----");
  }
  public void method2(){
    System.out.println("-----数据2-----");
  }
  public class Inner{
    public int j = 100;
    public int o = 1;
    //public static int num = 100;//编译错误,成员内部类不允许定义静态变量
    void inner_method(){
      System.out.println(o);
      System.out.println(j);
      System.out.println(this.j); //内部类访问内部类自己的变量可以直接调用也可以使用this,同时可以与外部类定义相同名称的变量
      System.out.println(Outer1.this.j);//内部类中访问与内部类相同名称的外部类变量是“外部类类名.this.变量名”
      System.out.println(k); //内部类直接可以访问与外部类不同名的变量
      method1(); //可以直接访问外部类静态方法
      method2(); 
    }
  }
//外部类非静态方法访问成员内部类
  public void method3(){
    Inner inner = new Inner();
    inner.inner_method();
  }
  //外部类静态方法访问成员内部类
  public static void method4(){
    Outer1 outer = new Outer1();
    Inner inner = outer.new Inner();
    inner.inner_method();
  }
  public static void main(String[] args) {
    //method4();
    //要想通过Inner的对象调用方法如下
    Outer1 outer = new Outer1();
    Inner inner = outer.new Inner();
    inner.inner_method();
    /*Inner inner = new Inner();
    inner.inner_method()*/ //内部内为静态方法
  }
}

【2】局部内部类

在方法中定义的内部类称为局部内部类。与局部变量类似,局部内部类不能有访问说明符,因为它不是外围类的一部分,但是它可以访问当前代码块内的常量,和此外围类所有的成员

/**
* 
*局部内部类
*/
public class Outer2 {
  private int s = 100 ;
  private int out_i = 1;
  public void method(final int k){
    final int s = 200;
    int i = 1 ;
    final int j = 10 ;
  class Inner{ //局部内部类不能有修饰符
    int s = 300 ;
    //static int m = 20;	 //不可以定义静态变量
    Inner(int k){
    inner_f(k);
  }
    int inner_i =100;
    void inner_f(int k){
      System.out.println(out_i);
      System.out.println(j);//可以访问外部类的局部变量,但必须是finnal修饰
      System.out.println(this.s);//访问的是内部类的变量
      System.out.println(Outer2.this.s);//访问的是外部类的变量
    }
  }
  new Inner(k);
  }
  public static void main(String[] args) {>
  //访问局部内部类必须现有外部对象
  Outer2 out = new Outer2();
  out.method(3);
  }
}

【3】静态内部类

/ * 
*静态内部类(嵌套类)
*/
public class Out3 {
  public static int i = 1;
  private int j = 10 ;
  public static void out_f1(){
    System.out.println("外部静态方法");
  }
  public void out_f2(){
    System.out.println("外部非静态方法");
  }
  static class Inner{
  //静态内部类可以使用public、private、protected修饰
  //静态内部类可以定义静态和非静态变量
    static int inner_i = 100;
    int inner_j = 200;
    static void inner_f1(){
      System.out.println("测试方法"+i);
      out_f1();//静态内部类只能访问外部类的静态变量和方法
    }
    void inner_f2(){
      System.out.println("测试方法");
    }
  }
  public void out_f3(){
    System.out.println(Inner.inner_i);//外部类访问内部类静态变量通过“内部类名.变量名”
    Inner.inner_f1();<
    //外部类访问内部类非静态变量:实例化内部类
    Inner inner = new Inner();
    inner.inner_f2();
  }
  public static void main(String[] args) {
    new Out3().out_f3();
  }
}

【4】匿名内部类


实例1:不使用匿名内部类来实现抽象方法

abstract class Person {
  public abstract void eat();
}
  class Child extends Person {
    public void eat() {
      System.out.println("eat something");
    }
  }
  public class Demo {
    public static void main(String[] args) {
      Person p = new Child();
      p.eat();
    }
  }

运行结果:eat something 可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用 但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦? 这个时候就引入了匿名内部类


实例2:匿名内部类的基本实现


abstract class Person {
  public abstract void eat();
}
public class Demo {
  public static void main(String[] args) {
    Person p = new Person() {
      public void eat() {
        System.out.println("eat something");
      }
    };
    p.eat();
  }
}

运行结果:eat something


可以看到,我们直接将抽象类Person中的方法在大括号中实现了 这样便可以省略一个类的书写 并且,匿名内部类还能用于接口上 

实例3:在接口上使用匿名内部类

interface Person {
  public void eat();
}
public class Demo {
  public static void main(String[] args) {
    Person p = new Person() {
      public void eat() {
        System.out.println("eat something");
      }
    };
     p.eat();
  }
}




运行结果:eat something


由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现


最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口


实例4:Thread类的匿名内部类实现


public class Demo {
  public static void main(String[] args) {
    Thread t = new Thread() {
      public void run() {
        for (int i = 1; i <= 5; i++) {
          System.out.print(i + " ");
        }
      }
    };
    t.start();
  }
}

运行结果:1 2 3 4 5


实例5:Runnable接口的匿名内部类实现


public class Demo {
  public static void main(String[] args) {
    Runnable r = new Runnable() {
      public void run() {
        for (int i = 1; i <= 5; i++) {
          System.out.print(i + " ");
        }
      }
    };
    Thread t = new Thread(r);
    t.start();
  }
}

运行结果:1 2 3 4 5