首页 > 代码库 > 内部类

内部类

内部类

1.内部类概述

在类中定义类,叫内部类

2.内部类访问特点

1) 内部类可以直接访问外部类的成员,包括私有。

2) 外部类要访问内部类的成员,必须创建对象。

外部类名.内部类名 对象名 = 外部类对象.内部类对象;

Outer.Inner oi = new Outer().new Inner();

//Inner如同外部类的成员

3.成员内部类私有使用

 

成员内部类被私有,如同成员私有,在外部(本类外) 不能直接创建内部类对象了,需在本类创建公共访问方式

  1. . class Demo2_InnerClass {
  2. . public static void main(String[] args) {
  3. Outer o = new Outer();    //通过外部类对象调用
  4. o.print();
  5. . }
  6. . }
  7. .
  8. . class Outer {
  9. . private int num = 10;
  10. . private class Inner { //如同成员私有,在外部(本类外) 不能直接创建内部类对象了,需在本类创建公共访问方式
  11. . public void method() {
  12. . System.out.println(num);
  13. . }
  14. . }
  15. .
  16. . public void print() {
  17. . Inner i = new Inner();
  18. . i.method();
  19. . //本类中访问,提供一个公共的访问方式,
  20.          }
  21. . }

4.静态成员内部类

1) 被static修饰的成员内部类    static class Inner

2) 成员内部类被静态修饰后的访问方式是:

外部类名.内部类名 对象名 = 外部类名.内部类对象;

Outer.Inner oi = new Outer.Inner();    //Outer.new Inner,书写习惯是把new放在前面

Outer.Inner2.print();//静态内部类,静态方法一路点就行了

案例:

  1. . class Demo1_InnerClass {
  2. . public static void main(String[] args) {
  3. . //外部类名.内部类名 对象名 = 外部类名.内部类对象;
  4. . Outer.Inner oi = new Outer.Inner();
  5. . oi.method();
  6. . Outer.Inner2.print();//静态内部类,静态方法一路点就行了
  7. . }
  8. . }
  9. . class Outer {
  10. . static class Inner {//静态的内部类,看成静态的成员
  11. . public void method() {//类里面有个非静态的方法,需创建对象去看
  12. . System.out.println("method");
  13. . }
  14. . }
  15. .
  16. . static class Inner2 {
  17. . public static void print() {
  18. . System.out.println("print");
  19. . }
  20. . }
  21. . }

5.成员内部类案例

要求:使用已知的变量,在控制台输出30,20,10。

  1. . class Outer {
  2. . public int num = 10;
  3. . class Inner {
  4. . public int num = 20;
  5. . public void show() {
  6. . int num = 30;
  7. . System.out.println(?);//就近原则直接给num即可
  8. . System.out.println(??);//20属于内部类的成员变量所以this.num
  9. . System.out.println(???);//Outer.this.num,内部类之所以能够访问外部类成员,因为它获取了外部类的引用Outer.this//Outer下面的this成员变量
  10. . }
  11. . }
  12. . }
  13. . class InnerClassTest {
  14. . public static void main(String[] args) {
  15. . Outer.Inner oi = new Outer().new Inner();
  16. . oi.show();
  17. . }
  18. . }

     

6.局部内部类访问局部变量

局部内部类,在方法中定义的内部类

局部内部类访问局部变量必须用final修饰

但是jdk1.8取消了这个事情,所以我认为这是个bug

案例:

  1. . class Demo1_InnerClass {
  2. . public static void main(String[] args) {
  3. . Outer o = new Outer();    //内部类在外部类中创建了对象
  4. . o.method();
  5. //有名内部类在外部类成员方法中创建了对象(相当于提供访问方式),然后在主方法中,通过外部类对象调用访问方式,再调用内部类里的方法
  6. . }
  7. . }
  8. . //局部内部类
  9. . class Outer {
  10. . public void method() {
  11. . final int num = 10;
  12. . class Inner {//局部内部类和局部变量一样,只在方法中有效,出了方法就无效了
  13. . public void print() {
  14. . System.out.println(num);
  15. . }
  16. . }
  17. .
  18. . Inner i = new Inner();        //在外部类中创建对象
  19. . i.print();
  20. . }
  21. .
  22. . /*public void run() {
  23. . Inner i = new Inner(); //局部内部类只能在所在的方法中访问
  24. . i.print();
  25. . }*/
  26. . }

说明:Final在类加载的时候,会进方法区中的常量池,常量池属于方法区的一部分.作用延长num的声明周期

7.匿名内部类

匿名内部类就是内部类的简化写法。

1) 前提

存在一个类或者接口:这里的类可以是具体类也可以是抽象类。没有名字类,需要想办法去表示它,去实现一个接口或继承一个类,去和外面的某个类或某个借口与其发生关系.

匿名内部类是局部内部类的一种,所以必须写在方法里.

2) 格式

new 类名或者接口名(){    //继承类,或实现接口

重写方法;

}

3) 本质

是一个继承了该类或者实现了该接口的子类匿名对象。

 

  1. class bj10_13 {
  2.    public static void main(String[] args) {
  3.       Outer o = new Outer();
  4.       o.method();
  5. //匿名内部类,直接通过外部类对象,调用方法,在调用匿名内部类的重写方法实现接口
  6.    }
  7. }
  8.  
  9. interface Inter { //接口
  10.    public void print();//抽象方法
  11. }
  12.  
  13. class Outer {
  14.    public void method() {
  15.       //new 接口名(){重写方法} 叫匿名内部类实现接口—子类
  16.       //new 类名(){重写方法} 叫匿名内部类继承类—子类
  17.        new Inter() { //匿名内部类实现inter接口,实现接口要重写方法
  18.           public void print() { //必须重写抽象方法
  19.             System.out.println("print");
  20.           }
  21.       }.print();
  22.    // new 接口名(){重写方法} 整个代表inter的子类对象,再调用子类对象的print方法
  23.       //把重写实现和重写的步棸,包括创建对象都写在一起了,整个代表inter的子类对象
  24.    }
  25. }
  26. }

 

8.匿名内部类重写多个方法调用

  1. class bj10_14 {
  2.    public static void main(String[] args) {
  3.       Outer o = new Outer();
  4.       o.method();
  5.       System.out.println("Hello World!");
  6.    }
  7. }
  8. interface Inter { //接口
  9.    public void show1(); //抽象方法
  10.    public void show2();
  11. }
  12. class Outer { //外部类
  13.    public void method() { //方法
  14.       /*new Inter() { //匿名内部类(实现接口,就要重写方法有几个重写几个)
  15.          public void show1() { //重写方法
  16.             System.out.println("show1");
  17.          }
  18.          public void show2() { //重写方法
  19.             System.out.println("show2");
  20.          }
  21.       }.show1();//实现一个方法对其调用还比较好,再调用show2时,这个对象就得再创建一次.
  22.    //建议匿名内部类只针对重写一个方法的时候使用
  23.    //要是多个方法的时候就要用有名字的类了
  24.    */
  25. //改进
  26.       Inter i = new Inter() { //父类引用指向子类对象
  27.          public void show1() { //重写方法
  28.             System.out.println("show1");
  29.          }
  30.          public void show2() { //重写方法
  31.             System.out.println("show2");
  32.          }
  33.       i.show1();
  34.       i.show2();//编译时看接口中的show2方法,运行时是子类对象中的show2方法.因此可以实现多个方法.
  35.    }
  36. }
  37. //当子类中有自己特有的方法时:
  38.          /*public void show3() {
  39.             System.out.println("show3");
  40.          }
  41.          i.show3();……多态
  42. */
  43.          //有个弊端,当对象里有自己的方法时是无法调用的//编译不通过
  44.          //匿名内部类是不能向下转型的,向下强转得有子类类名,这个没有.

 

9.匿名内部类在开发中的应用---当做参数传递

  1. class bj10_15 {
  2.    public static void main(String[] args) {
  3.       PersonDemo pd = new PersonDemo ();
  4.       //用有名字的子类做,匿名对象赋值给父类引用
  5. pd.method(new Student());
  6. //其中new Student()是有名字的子类对象
  7. //把new Student()赋值给Person p父类引用指向子类对象(传person的子类对象)(多态的特性,可以父类引用指向子类对象,即可以将子类对象赋值给父类引用)
  8.       //method里面的p.show,编译的时候看的是Person里的show方法,运行的是看的Student里面的show方法
  9.       //匿名内部类 赋值给父类引用
  10. //匿名内部类在开发中的应用当做参数传递,本质把匿名内部类看做一个对象.
  11.       //method(里面是person类型),下面整个括号里是person的子类对象
  12.       //new Person(){}继承Person类,里面要重写Person的抽象方法
  13.  
  14.       pd.method(new Person(){
  15.          public void show() {
  16.             System.out.println("show1");//继承类要重写抽象方法
  17.          }
  18.       });
  19.  
  20.    }
  21. }
  22. abstract class Person {//抽象类,不能不实例化(不能new),传一个person子类对象
  23.    public abstract void show();
  24. }
  25. class Student extends Person {//继承了Person,相当于他的子类//有名字的类
  26.    public void show() {
  27.       System.out.println("show");
  28.    }
  29. }
  30. class PersonDemo {
  31.    public void method(Person p) { //要传一个person类型的引用 p.show();
  32.    }
  33. }

 

 

10匿名内部类案例

//链式编程,每次调用方法之后还能调用方法,证明调用方法返回的是对象

//要求在控制台输出"HelloWorld"

  1. class bj10_16 {
  2.    public static void main(String[] args) {
  3. Outer.method().show();
  4.    }
  5. }
  6. interface Inter {
  7.    void show();
  8. }
  9.  
  10. class Outer {
  11.    //补齐代码 //从主方法中开始分析
  12. 下面是答案
  13.    public static Inter method() {
  14.       //返回类型是Inter,返回Inter子类对象就可以
  15.       //但是inter是个借口,调用show方法没有意义,
  16.       return new Inter() {
  17.          public void show() {
  18.             System.out.println("HelloWorld");
  19.          }
  20.       };
  21.    }
  22. }

思考过程:

     1. //补齐代码 //从主方法中开始分析Outer.method().show();

2.用类名.调用方法,说明method这个方法是静态的,返回值类型不确定

    3.非静态的一定要创建对象才能调用,调用完method后还能调用.show,说明method调用完后返回的是一个对象

    4.show方法只有在Inter中,因此method返回值类型是Inter.

5.Inter i = Outer.method();//Outer.method 返回的是Inter类型的对象,因此用Inter接收

6.new Inter(){}.show子类对象调用自己里面的show方法,其实是父类引用指向子类对象.i.show()编译看Inter接口里面的show方法,运行看子类重写的show方法

内部类