Java编程思想阅读笔记(第10章内部类)

内部类

  • 内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的
  • 可以将一个类的定义放在另一个类定义内部,这就是内部类
  • 内部类自动拥有对包裹它的基类所有成员的访问权限
  • 内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限)
  • 内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类

内部类的共性

  • 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
  • 内部类不能用普通的方式访问。
  • 内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。
  • 外部类不能直接访问内部类的的成员,但可以通过内部类对象来访问

- 内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。因为当某个外围类的对象创建内部类的对象时,此内部类会捕获一个隐式引用,它引用了实例化该内部对象的外围类对象。通过这个指针,可以访问外围类对象的全部状态。

通过反编译内部类的字节码,分析之后主要是通过以下几步做到的: 

1 编译器自动为内部类添加一个成员变量,这个成员变量的类型和外部类的类型相同,这个成员变量就是指向外部类对象的引用 
2 编译器自动为内部类的构造方法添加一个参数,参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值; 
3 在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。

在方法或者任意作用域定义内部类的两个理由

  • 实现了某类型的接口,于是可以创建内部类并返回对其的引用
  • 想解决一个问题,需要一个类协助解决问题,但是不希望这个类是公共可用的

为什么需要内部类?

  • 内部类方法可以访问该类定义所在的作用域的数据,包括私有的数据
  • 内部类可以对同一个包中的其他类隐藏起来,一般的非内部类,是不允许有 private 与protected权限的,但内部类可以
  • 可是实现多重继承
  • 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷
  • 每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。大家都知道Java只能继承一个类,它的多重继承在我们没有学习内部类之前是用接口来实现的。但使用接口有时候有很多不方便的地方。比如我们实现一个接口就必须实现它里面的所有方法。而有了内部类就不一样了。它可以使我们的类继承多个具体类或抽象类。
  • 内部类使用得多继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了多重继承,也就是说,内部类允许继承多个非接口类型(类或者抽象类)。

成员内部类:

即在一个类中直接定义的内部类, 成员内部类与普通的成员没什么区别,可以与普通成员一样进行修饰和限制。成员内部类不能含有static的变量和方法

public class TestParcel {

        //每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响
        private  class  PContents implements Contents{
//          private static int i=11;
            private  int i=11;
            @Override
            public int value(){
                return i;
            }   
        }

    public static void main(String[] args) {
        TestParcel t=new TestParcel();
        //内部类不能用普通的方式访问
        TestParcel.PContents p=t.new PContents();


    }
}       

局部内部类:

  • 在方法中定义的内部类称为局部内部类。与局部变量类似,局部内部类不能有访问说明符,因为它不是外围类的一部分,但是它可以访问当前代码块内的常量,和此外围类所有的成员。
需要注意的是:
  • (1)、方法内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
  • (2)、方法内部类对象不能使用该内部类所在方法的非final局部变量。
public class Outer {
      private int s = 100;
      private int out_i = 1;
      public void f(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);
                      System.out.println(i);
                     // 如果内部类中有与外部类同名的变量,直接用变量名访问的是内部类的变量
                     System.out.println(s);
                     // 用this.变量名访问的也是内部类变量
                     System.out.println(this.s);
                     // 用外部类名.this.内部类变量名访问的是外部类变量
                     System.out.println(Outer.this.s);
                 }
            }
            new Inner(k);
      }
      public static void main(String[] args) {
            // 访问局部内部类必须先有外部类对象
            Outer out = new Outer();
            out.f(3);
        }
}

静态内部类(嵌套类):

  • 如果你不需要内部类对象与其外围类对象之间有联系,那你可以将内部类声明为static。这通常称为嵌套类(nested class)。想要理解static应用于内部类时的含义,你就必须记住,普通的内部类对象隐含地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时,就不是这样了。
嵌套类意味着:
  • 要创建嵌套类的对象,并不需要其外围类的对象。

- 不能从嵌套类的对象中访问非静态的外围类对象。

public class Outer {
        private static int i = 1;
        private int j = 10;

        public static void outer_f1() {}

        public void outer_f2() {}

        // 静态内部类可以用public,protected,private修饰
        // 静态内部类中可以定义静态或者非静态的成员
        private static class Inner {
            static int inner_i = 100;
            int inner_j = 200;

            static void inner_f1() {
                // 静态内部类只能访问外部类的静态成员(包括静态变量和静态方法)
                System.out.println("Outer.i" + i);
                outer_f1();
            }

            void inner_f2() {
                // 静态内部类不能访问外部类的非静态成员(包括非静态变量和非静态方法)
                // System.out.println("Outer.i"+j);
//               outer_f2();
            }
        }

        public void outer_f3() {
            // 外部类访问内部类的静态成员:内部类.静态成员
            System.out.println(Inner.inner_i);
            Inner.inner_f1();
            // 外部类访问内部类的非静态成员:实例化内部类即可
            Inner inner = new Inner();
            inner.inner_f2();
        }

        public static void main(String[] args) {
            new Outer().outer_f3();
        }
}

匿名内部类:

简单地说:匿名内部类就是没有名字的内部类

什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:
  • 只用到类的一个实例。
  • 类在定义后马上用到。
  • 类非常小(SUN推荐是在4行代码以下)
  • 给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
  • 匿名内部类不能有构造方法。
  • 匿名内部类不能定义任何静态成员、方法和类。
  • 匿名内部类不能是public,protected,private,static。
  • 只能创建匿名内部类的一个实例。
  • 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
  • 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
public class Parcel8 {
      public Destination dest(final String name, String city) {
          return new Destination(name, city) {
                private String label = name;

                public String getName() {
                    return label;
                }
            };
      }
      public static void main(String[] args) {
            Parcel8 p = new Parcel8();
            Destination d = p.dest("Tanzania", "gz");
        }

        abstract class Destination {
            Destination(String name, String city) {
                System.out.println(city);
            }

            abstract String getName();
        }
}

猜你喜欢

转载自blog.csdn.net/u010391342/article/details/79796148