接口

导学

在Java中,只能支持单继承。那么,如果想要在一个类型中能够兼容多种类型特征,代码该如何编写呢?如果多个不同的类型在不具有相同父类的情况下,仍然要具有相同的特征,那代码又该如何编写呢?
比如,我们可以使用一个案例来描述一下。
案例:要求描述手机的发展史?
7. 接口与内部类 - 图1
实现:

  1. /**
  2. * 最原始的手机
  3. * @author LiXinRong
  4. *
  5. */
  6. public class Telphone {
  7. private String brand;
  8. private int price;
  9. public Telphone() {
  10. }
  11. public void call() {
  12. System.out.println("手机可以打电话");
  13. }
  14. public String getBrand() {
  15. return brand;
  16. }
  17. public void setBrand(String brand) {
  18. this.brand = brand;
  19. }
  20. public int getPrice() {
  21. return price;
  22. }
  23. public void setPrice(int price) {
  24. this.price = price;
  25. }
  26. }
  1. package com.dodoke.phone.model;
  2. /**
  3. * 二代手机
  4. * @author LiXinRong
  5. *
  6. */
  7. public class SecondPhone extends Telphone{
  8. public void message() {
  9. System.out.println("手机可以发短信");
  10. }
  11. }
  1. package com.dodoke.phone.model;
  2. /**
  3. * 三代手机
  4. * @author LiXinRong
  5. *
  6. */
  7. public class ThirdPhone extends SecondPhone {
  8. public void video() {
  9. System.out.println("手机可以看视频");
  10. }
  11. public void music() {
  12. System.out.println("手机可以听音乐");
  13. }
  14. }
  1. package com.dodoke.phone.model;
  2. /**
  3. * 最新一代手机
  4. * @author LiXinRong
  5. *
  6. */
  7. public class FourthPhone extends ThirdPhone {
  8. public void photo() {
  9. System.out.println("手机可以拍照");
  10. }
  11. public void network() {
  12. System.out.println("手机可以上网");
  13. }
  14. public void game() {
  15. System.out.println("手机可以玩游戏");
  16. }
  17. }
  1. package com.dodoke.phone.test;
  2. import com.dodoke.phone.model.FourthPhone;
  3. public class Test {
  4. public static void main(String[] args) {
  5. FourthPhone phone = new FourthPhone();
  6. phone.call();
  7. phone.message();
  8. phone.video();
  9. phone.game();
  10. phone.network();
  11. phone.photo();
  12. }
  13. }

我们可以看到,无论是其他几代的什么功能都可以在四代手机中实现。我们可以很简单的实现这样一个手机演变史的记录。
但是,现在相机可以拍照,电脑可以上网、 玩游戏, 智能手表也可以打电话。那么当程序中需要继续满足这个需求的时候,代码该如何调整? 电话,电脑,相机,智能手表。 他们没有办法抽取一个公共的父类。因为他们的行为是相互交叉,具有相似的能力。但硬性拆出一个公共父类, 就不太合理。那就得创建一个电脑类,智能手表类,相机类,在每个类中增加相应的功能等等.。只要在测试类中生成这几个类的实例对象, 调用他们的方法就可以实现相应的内容。

  1. public class Camera {
  2. public void photo() {
  3. System.out.println("相机可以拍照");
  4. }
  5. }
  1. public class Computer {
  2. public void video() {
  3. System.out.println("电脑可以看视频");
  4. }
  5. public void music() {
  6. System.out.println("电脑可以听音乐");
  7. }
  8. public void network() {
  9. System.out.println("电脑可以上网");
  10. }
  11. public void game() {
  12. System.out.println("电脑可以玩游戏");
  13. }
  14. }

但是这几种类型中间真的就没办法建立关联了吗? 他们之间的确不能抽取具有公共特征的父类, 但是他们当中很多类型中间是具有相同行为能力的。
那么,在Java中,就可以通过接口实现这些行为的关联

接口实现

接口不是类,但具有类的某些特征,接口也是引用数据类型
接口称之为最彻底的抽象类,这是因为在接口中,jdk1.8之前是几乎没有带方法体的方法的
接口如同抽象类,当中的抽象方法,abstract可以省略,这些方法必须要被其实现类实现

  1. public interface IPhoto {
  2. //public abstract void photo();
  3. public void photo();
  4. }

当某一个类实现某个接口时,一定要重写接口中的抽象方法,否则该类需要改写为抽象类

  1. package com.dodoke.phone.model;
  2. import com.dodoke.phone.interfaces.IPhoto;
  3. public class Camera implements IPhoto{
  4. @Override
  5. public void photo() {
  6. System.out.println("相机可以拍照");
  7. }
  8. }
  1. public class FourthPhone extends ThirdPhone implements IPhoto {
  2. @Override
  3. public void photo() {
  4. System.out.println("手机可以拍照");
  5. }
  6. public void network() {
  7. System.out.println("手机可以上网");
  8. }
  9. public void game() {
  10. System.out.println("手机可以玩游戏");
  11. }
  12. }
  1. public class Test {
  2. public static void main(String[] args) {
  3. FourthPhone phone = new FourthPhone();
  4. phone.call();
  5. phone.message();
  6. phone.video();
  7. phone.game();
  8. phone.network();
  9. phone.photo();
  10. System.out.println("=====================");
  11. //要求相机拍照可以,手机拍照也可以
  12. IPhoto ip = new Camera();
  13. ip.photo();
  14. ip = new FourthPhone();
  15. ip.photo();
  16. }
  17. }

小结:

  1. 接口中的方法没有方法体。
  2. 类使用implements关键字来实现接口。例如:public class Camera implements IPhoto{}
  3. 如果一个类实现了某个接口,那么必须重写此接口中的所有方法(如果不实现则此类必须设置为抽象类)。
  4. 接口没有构造器,接口无法直接实例化出对象,用接口的引用指向实现类的实例对象。例如:IPhoto ip=new FourthPhone(); 实例化的对象ip只能调用IPhoto这个接口中的方法,调用方法具体的实现细节则由其实例化对象时使用的类决定(如在此如果ip.photo(); 实际上是运行的FourthPhone类中的photo()方法)。

    接口成员

    在讲接口给的成员之前,我们再来提一下接口,就如同抽象类是利用继承给子类指定规范一样,接口也是给一些没有关系的类制定了需要遵守的规范。接口不关心这些类的内部数据,也不关心这些类里面的方法的实现细节,它只规定这些类里面必须提供某些细节。
    接下来,我们继续结合具体案例来看一看接口中的内容

    抽象方法和常量

接口中 抽象方法如果没有访问修饰符,默认为public,接口中的抽象方法只能使用public修饰
接口中可以存放常量,接口中定义的属性一定是常量,即在定义常量的时候,public static final 可以省略

  1. package com.dodoke.phone.interfaces;
  2. //访问修饰符 只能是public 和 默认default
  3. public interface INet {
  4. //接口中抽象方法可以不写abstract关键字
  5. public void network();
  6. //接口中抽象方法可以不写public,但是依然会按照public的限定范围使用
  7. void connection();
  8. //接口中,可以包含常量
  9. public static final int TEMP = 20;
  10. //关于常量的修饰符可以省略,默认public static final
  11. int TEMP2 = 15;
  12. }

测试

  1. System.out.println(INet.TEMP);
  2. INet it = new Computer();//接口引用指向具体实现类
  3. System.out.println(it.TEMP);

如果在实现类中存在和接口同名的常量,在接口引用指向实现类时,调用的是接口中定义的常量信息

默认方法和静态方法

接口中除了有抽象方法和常量,在jdk1.8以后新增了两个特殊方法 - 默认方法和静态方法
默认方法使用default修饰,重写默认方法需要用public修饰
默认方法可以被重写,也可以不被重写,可以通过接口的引用调用,也可以通过实现接口的类的引用调用

静态方法也是可以携带方法体,但是不能被重写,且只能通过接口名调用

  1. //访问修饰符 只能是public 和 默认default
  2. public interface INet {
  3. //接口中抽象方法可以不写abstract关键字
  4. public void network();
  5. //接口中抽象方法可以不写public,但是依然会按照public的限定范围使用
  6. void connection();
  7. //接口中,可以包含常量
  8. public static final int TEMP = 20;
  9. //关于常量的修饰符可以省略,默认public static final
  10. int TEMP2 = 15;
  11. /**
  12. * jdk 1.8 以后提供了默认方法
  13. * 可以带方法体,默认方法不一定要被实现
  14. */
  15. default void Connection() {
  16. System.out.println("我是接口中的默认链接");
  17. }
  18. /**
  19. * jdk 1.8 以后提供了静态方法
  20. * 可以带方法体
  21. */
  22. static void stop() {
  23. System.out.println("我是接口中的静态方法");
  24. }
  25. }

测试:

  1. INet it = new Computer();
  2. it.Connection();
  3. //it.stop();不能调用
  4. INet.stop();

默认方法可以在实现类中重写,也可以不重写,并可以通过接口的引用调用。静态方法不可以在实现类中重写,只能通过接口名调用。

多接口重名处理

在Java中,只能单继承,但是可以实现多个接口
同名方法

  1. public class SmartWatch implements INet,IPhoto{
  2. public void call() {
  3. System.out.println("智能手表可以打电话");
  4. }
  5. public void message() {
  6. System.out.println("智能手表可以发短信");
  7. }
  8. @Override
  9. public void photo() {
  10. System.out.println("智能手表可以拍照");
  11. }
  12. @Override
  13. public void network() {
  14. System.out.println("智能手表可以上网");
  15. }
  16. }

如果在接口中存在同名的默认方法,要么删除其中一个接口的方法,要么在实现类中,自己定义一个同名的方法。在接口引用指向实现类的时候,调用的是实现类中的方法。
一个类可以继承一个父类,同时实现若干接口
在多个接口中需要注意,如果默认方法重名,最好返回值相同,否则一起使用时会导致实现类报错并难以解决
在多个接口中最好不要定义同名的抽象方法

  1. public class FourthPhone extends ThirdPhone implements IPhoto,INet {
  2. @Override
  3. public void photo() {
  4. System.out.println("手机可以拍照");
  5. }
  6. @Override
  7. public void network() {
  8. System.out.println("手机可以上网");
  9. }
  10. public void game() {
  11. System.out.println("手机可以玩游戏");
  12. }
  13. }

如果在父类和接口中都存在同名方法,在FourthPhone 没有重写该方法不会报错,但最终指向的是父类中的同名方法。如果重写了该方法,最终指向的是FourthPhone中重写的方法。
同名常量

  1. interface One {
  2. static int X = 11;
  3. }
  4. interface Two {
  5. final int X = 22;
  6. }
  7. class Three {
  8. public int X = 33;//父类中的属性与接口中的常量同名的时候,无法解析
  9. }
  10. public class Test1 extends Three implements One,Two{
  11. public void test() {
  12. System.out.println(One.X);
  13. System.out.println(Two.X);
  14. //System.out.println(X);报错
  15. }
  16. public static void main(String[] args) {
  17. new Test1().test();
  18. }
  19. }

类实现了多接口时,如果多接口中出现了重名常量,在此类中通过接口名.变量的方式访问。
类继承父类又实现了多接口时,如果父类、多接口中出现了重名常量,只能在该实现类中自己再定义这个重名的变量,才能消除歧义。
当要实现的接口和继承的类中存在同名的常量时,Java虚拟机无法辨认该常量到底来源于谁,于是该类存在此常量,但是默认不会给该类的常量赋值,如果想要使用该常量,则需要对此常量进行赋值。此时该常量与父类和接口中的常量无关。

接口的继承

接口之间同样也是存在继承关系的。在Java中,接口之间可以实现多继

  1. public interface IFather1 {
  2. void say();
  3. default void connection() {
  4. System.out.println("我是IFather1中的连接方法");
  5. }
  6. }
  1. public interface IFather2 {
  2. void fly();
  3. default void connection() {
  4. System.out.println("我是IFather2中的连接方法");
  5. }
  6. }
  1. public interface ISon extends IFather1,IFather2{
  2. void run();
  3. default void connection() {
  4. System.out.println("我是儿子的连接方法");
  5. }
  6. }
  1. public class Demo implements ISon{
  2. @Override
  3. public void say() {
  4. // TODO Auto-generated method stub
  5. }
  6. @Override
  7. public void fly() {
  8. // TODO Auto-generated method stub
  9. }
  10. @Override
  11. public void run() {
  12. // TODO Auto-generated method stub
  13. }
  14. }

总结:
1.子接口允许有多个父接口
2.子接口继承多个父接口,子接口的实现类需重写父接口中所有的抽象方法
3.多个父接口默认方法重名时子接口会报错,解决方案:子接口重写重名的默认方法

内部类

导学

在程序开发中为了更加准确的描述结构体的作用,通常拥有各种嵌套结构。而程序也是允许嵌套的!
内部类(内部定义普通类,抽象类,接口的统称)是指一种嵌套的结构关系,即在一个类的内部除了定义属性和方法外还可以定义一个类结构,这样的形式使得程序的结构定义更加灵活。

内部类是一种常见的嵌套结构,利用这样的结构可以使内部类与外部类共存,并且方便的进行使用操作的访问。内部类也可以进一步扩展到匿名内部类的使用,在jdk 1.8后所提供的Lambda表达式与方法引用也可以简化代码结构

示例:

  1. package lamda.dodoke.demo1;
  2. class Outer {//外部类(非公有类)
  3. private String msg = "Hello,World";//定义私有成员属性
  4. public void fun() {//定义普通方法
  5. Inner in = new Inner();//实例化内部类对象
  6. in.print();//调用内部类方法
  7. }
  8. class Inner {//在Outer类的内部定义Inner内部类
  9. public void print() {//定义内部类的方法
  10. System.out.println(Outer.this.msg);//调用Outer类的属性
  11. }
  12. }
  13. }
  14. public class JavaDemo {//在一个Java文件中可以有多个类,但是只能有一个public修饰的类
  15. public static void main(String[] args) {
  16. Outer out = new Outer();//实例化外部类对象
  17. out.fun();//执行外部类方法
  18. }
  19. }

准确来说,内部类会使一个类的内部充斥着其他的类结构,所以内部类在整体设计中最大的缺点就是破坏了良好的程序结构,造成代码结构的混乱。但他最大的优点在于可以方便的访问外部类的私有成员。所以我们使用内部类,更多的时候是希望某一个类只为单独一个类服务

内部类注意点

  • 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,前面冠以外部类的类名和$符号。
  • 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
  • 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。

    成员内部类

    成员内部类(实例内部类)是指没有用 static 修饰的内部类,有的地方也称为非静态内部类。示例如下:

    1. public class Out {
    2. class Inner {}
    3. }
  • 在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例。

    1. public class Outer {
    2. class Inner {}
    3. Inner inner = new Inner(); // 不需要创建外部类实例
    4. public void method1() {
    5. Inner i = new Inner(); // 不需要创建外部类实例
    6. }
    7. public static void method2() {
    8. Inner i = new Outer().new Inner(); // 需要创建外部类实例
    9. }
    10. }
    11. //注意是否在同一个包中
  • 在实例内部类中,可以访问外部类的所有成员。

    1. public class Outer {
    2. public int a = 100;
    3. static int b = 100;
    4. final int c = 100;
    5. private int d = 100;
    6. public String method3() {
    7. return "实例方法";
    8. }
    9. public static String method4() {
    10. return "静态方法";
    11. }
    12. class Inner {
    13. int a2 = a + 1; // 访问 public 的 a
    14. int b2 = b + 1; // 访问 static 的 b
    15. int c2 = c + 1; // 访问 final 的 c
    16. int d2 = d + 1; // 访问 private 的 d
    17. String str1 = method1(); // 访问实例方法method1
    18. String str2 = method2(); // 访问静态方法method2
    19. }
    20. public static void main(String[] args) {
    21. Inner in = new Outer().new Inner();
    22. System.out.println(in.a2); // 输出 101
    23. System.out.println(in.b2); // 输出 101
    24. System.out.println(in.c2); // 输出 101
    25. System.out.println(in.d2); // 输出 101
    26. System.out.println(in.str1); // 输出实例方法
    27. System.out.println(in.str2); // 输出静态方法
    28. }
    29. }
  • 在外部类中不能直接访问内部类的成员,而必须通过内部类的实例去访问。如果类 A 包含内部类 B,类 B 中包含内部类 C,则在类 A 中不能直接访问类 C,而应该通过类 B 的实例去访问类 C。

  • 外部类实例与内部类实例是一对多的关系,也就是说一个内部类实例只对应一个外部类实例,而一个外部类实例则可以对应多个内部类实例。

    1. public class Outer {
    2. int a = 10;
    3. class Inner {
    4. int a = 20;
    5. int a1 = this.a;
    6. int b3 = Outer.this.a;
    7. }
    8. }
  • 在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰。

    静态内部类

    静态内部类是指使用 static 修饰的内部类。示例代码如下:

    1. public class Outer {
    2. static class Inner {} // 静态内部类
    3. }
  • 在创建静态内部类的实例时,不需要创建外部类的实例。

    1. class OtherClass {
    2. Outer.Inner oi = new Outer.Inner();
    3. }
  • 静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例。

    1. public class Outer {
    2. static class Inner {
    3. int a = 0;
    4. static int b = 0;
    5. }
    6. }
    7. class OtherClass {
    8. Outer.Inner oi = new Outer.Inner();
    9. int a2 = oi.a; // 访问实例成员
    10. int b2 = Outer.Inner.b; // 访问静态成员
    11. }
  • 静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。

    1. public class Outer {
    2. int a = 0;
    3. static int b = 0;
    4. static class Inner {
    5. Outer o = new Outer();
    6. int a2 = o.b; // 访问实例变量
    7. int b2 = b; // 访问静态变量
    8. }
    9. }

    方法内部类

    局部内部类(方法内部类)是指在一个方法中定义的内部类。示例代码如下:

    1. public class Test {
    2. public void method() {
    3. class Inner {} // 局部内部类
    4. }
    5. }
  • 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。

  • 局部内部类只在当前方法中有效。

    1. public class Test {
    2. Inner i = new Inner(); // 编译出错
    3. Test.Inner ti = new Test.Inner(); // 编译出错
    4. Test.Inner ti2 = new Test().new Inner(); // 编译出错
    5. public void method() {
    6. class Inner {}
    7. Inner i = new Inner();
    8. }
    9. }
  • 局部内部类中不能定义 static 成员。

  • 局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
  • 在局部内部类中可以访问外部类的所有成员。
  • 在局部内部类中可以直接访问当前方法中的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用外部类.this.变量的形式访问外部类中的成员。

    1. public class Test {
    2. int a = 0;
    3. int d = 0;
    4. public void method() {
    5. int b = 0;
    6. final int c = 0;
    7. final int d = 10;
    8. class Inner {
    9. int a2 = a; // 访问外部类中的成员
    10. int b2 = b; // 访问外部类中的成员
    11. int c2 = c; // 访问方法中的成员
    12. int d2 = d; // 访问方法中的成员
    13. int d3 = Test.this.d; //访问外部类中的成员
    14. }
    15. Inner i = new Inner();
    16. System.out.println(i.d2); // 输出 10
    17. System.out.println(i.d3); // 输出 0
    18. }
    19. }

    匿名内部类

    匿名内部类

    匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下:

    1. new <类或接口>() {
    2. // ....
    3. }

    这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。使用匿名类可使代码更加简洁、紧凑,模块化程度更高。
    匿名类有两种实现方式:

  • 继承一个类,重写其方法。

  • 实现一个接口(可以是多个),实现其方法

    1. public class Out {
    2. void show() {
    3. System.out.println("调用 Out 类的 show() 方法");
    4. }
    5. }
    6. public class Test {
    7. public static void main(String[] args) {
    8. Out o = new Out() {
    9. void show() {
    10. System.out.println("调用匿名类中的 show() 方法");
    11. }
    12. }
    13. o.show(); // 调用匿名类中的 show() 方法
    14. }
    15. }
  • 匿名类和局部内部类一样,可以访问外部类的所有成员。

    1. public static void main(String[] args) {
    2. int a = 10;
    3. final b = 10;
    4. Out o = new Out() {
    5. void show() {
    6. System.out.println(a); // 编译通过
    7. System.out.println(b); // 编译通过
    8. }
    9. }
    10. o.show();
    11. }
  • 匿名类中允许使用非静态代码块进行成员初始化操作。

    1. Out o = new Out() {
    2. int i;
    3. {
    4. i = 10;
    5. }
    6. public void show() {
    7. System.out.println("i");
    8. }
    9. }
  • 匿名类的非静态代码块会在父类的构造方法之后被执行。

什么是内部类

可以将一个类的定义放在里另一个类的内部,这就是内部类。广义上我们将内部类分为四种:成员内部类、静态内部类、局部(方法)内部类、匿名内部类。

为什么要用内部类

使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。——《Think in java》

也就是说内部类拥有类的基本特征。(eg:可以继承父类,实现接口。)在实际问题中我们会遇到一些接口无法解决或难以解决的问题,此时我们可以使用内部类继承某个具体的或抽象的类,间接解决类无法多继承引起的一系列问题。(注:内部类可以嵌套内部类,但是这极大的破坏了代码的结构,这里不推荐使用。)

成员内部类

内部类、外部类

Plain Text
public class Outer {
private int outerVariable = 1;
private int commonVariable = 2;
private static int outerStaticVariable = 3;
public void outerMethod() {
System.out.println(“我是外部类的outerMethod方法”);
}
public static void outerStaticMethod() {
System.out.println(“我是外部类的outerStaticMethod静态方法”);
}
class Inner {
private int commonVariable = 20;
public Inner() {
}
public void innerShow() {
//当和外部类冲突时,直接引用属性名,是内部类的成员属性
System.out.println(“内部的commonVariable:” + commonVariable);
//内部类访问外部属性
System.out.println(“outerVariable:” + outerVariable);
//当和外部类属性名重叠时,可通过外部类名.this.属性名
System.out.println(“外部的commonVariable:” + Outer.this.commonVariable);
System.out.println(“outerStaticVariable:” + outerStaticVariable);
//访问外部类的方法
outerMethod();
outerStaticMethod();
}
}
}

其他类使用成员内部类

Plain Text
/
其他类使用成员内部类
/
public class Other {
public static void main(String[] args) {
//外部类对象
Outer outer = new Outer();
//创造内部类对象
Outer.Inner inner = outer.new Inner();
inner.innerShow();
/

可在Outer中定义get方法,获得Inner对象,那么使用时,只需outer.getInnerInstance()即可。
public Inner getInnerInstance(Inner类的构造方法参数){
return new Inner(参数);
}
*/
}
}

小结

  1. 成员内部类当成Outer的成员信息存在
  2. 可以是任何的访问修饰符
  3. 内部类的内部不能有静态信息
  4. 内部类也是类,该继承继承,该重写重写,该重载重载,this和super随便用
  5. 外部类如何访问内部类信息,必须new之后访问
  6. 内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突,调用外部类.this.属性或者方法
  7. 其它类如何访问内部类

Plain Text
Outer outer=new Outer();
//创造内部类对象
Outer.Inner inner=outer.new Inner();
inner.inner_show();

静态内部类

外部类、内部类

Plain Text
/
外部类、内部类定义
/
public class Outer {
private int outerVariable = 1;
private int commonVariable = 2;
private static int outerStaticVariable = 3;
static {
System.out.println(“Outer的静态块被执行了……”);
}
public void outerMothod() {
System.out.println(“我是外部类的outerMethod方法”);
}
public static void outerStaticMethod() {
System.out.println(“我是外部类的outerStaticMethod静态方法”);
}
public static class Inner {
private int innerVariable = 10;
private int commonVariable = 20;
private static int innerStaticVariable = 30;
static {
System.out.println(“Outer.Inner的静态块执行了……”);
}
public void innerShow() {
System.out.println(“innerVariable:” + innerVariable);
System.out.println(“内部的commonVariable:” + commonVariable); System.out.println(“outerStaticVariable:”+outerStaticVariable);
outerStaticMethod();
}
public static void innerStaticShow() {
//被调用时会先加载Outer类
outerStaticMethod();
System.out.println(“outerStaticVariable”+outerStaticVariable);
}
}
/

外部类的内部如何和内部类打交道
/
public static void callInner() {
System.out.println(Inner.innerStaticVariable);
Inner.innerStaticShow();
}
}

其他类使用成员内部类

Plain Text
public class Other {
public static void main(String[] args) {
//访问静态内部类的静态方法,Inner类被加载,此时外部类未被加载,独立存在,不依赖于外围类。
Outer.Inner.innerStaticShow();
//访问静态内部类的成员方法
Outer.Inner oi = new Outer.Inner();
oi.innerShow();
}
}

小结

  1. 内部可以包含任意的信息
  2. 静态内部类的方法只能访问外部类的static关联的信息
  3. 访问内部类的静态信息,直接外部类.内部类.静态信息就可以了
  4. 静态内部类可以独立存在,不依赖于其他外围类
  5. 利用 外部类.内部类 引用=new 外部类.内部类(); 然后利用引用.成员信息(属性、方法)调用
  6. 静态内部类可以独立存在,不依赖于其他外围类

    局部内部类

    外部类、内部类

    Plain Text
    /
    外部类、内部类
    /
    public class Outer {
    private int outerVariable = 1;
    private int commonVariable = 2;
    private static int outerStaticVariable = 3;
    /

    成员外部方法
    /
    public void outerMethod() {
    System.out.println(“我是外部类的outerMethod方法”);
    }
    /
    静态外部方法
    /
    public static void outerStaticMethod() {
    System.out.println(“我是外部类的outerStaticMethod静态方法”);
    }
    /

    程序的入口
    /
    public static void main(String[] args) {
    Outer outer = new Outer();
    outer.outerCreatMethod(100);
    }
    /
    成员方法,内部定义局部内部类
    /
    public void outerCreatMethod(int value) {
    /

    女性
    /
    boolean sex = false;
    /
    局部内部类,类前不能有访问修饰符
    /
    class Inner {
    private int innerVariable = 10;
    private int commonVariable = 20;
    /

    局部内部类方法
    /
    public void innerShow() {
    System.out.println(“innerVariable:” + innerVariable);
    //局部变量
    System.out.println(“是否男性:” + sex);
    System.out.println(“参数value:” + value);
    //调用外部类的信息
    System.out.println(“outerVariable:” + outerVariable);
    System.out.println(“内部的commonVariable:” + commonVariable);
    System.out.println(“外部的commonVariable:” + Outer.this.commonVariable);
    System.out.println(“outerStaticVariable:” + outerStaticVariable);
    outerMethod();
    outerStaticMethod();
    }
    }
    //局部内部类只能在方法内使用
    Inner inner = new Inner();
    inner.innerShow();
    }
    }

    小结

  7. 类前不能有访问修饰符

  8. 仅在此方法内使用
  9. 无法创造静态信息
  10. 可以直接访问方法内的局部变量和参数(有限制,下面详谈),但是不能更改
  11. 可以随意的访问外部类的任何信息

    匿名内部类

    定义接口

    Plain Text
    /*
    接口中方法默认为public
    */
    public interface IAnimal{
    void speak();
    }

    匿名内部类使用

    Plain Text
    /*
    外部内、内部类
    */
    public class Outer {
    public static IAnimal getInnerInstance(String speak){
    return new IAnimal(){
    @Override
    public void speak(){
    System.out.println(speak);
    }};
    //注意上一行的分号必须有
    }

    public static void main(String[] args){
    //调用的speak()是重写后的speak方法。
    Outer.getInnerInstance(“小狗汪汪汪!”).speak();
    }
    }

    小结

  12. 匿名内部类常常被用来重写某个或某些方法

  13. 匿名内部类是没有访问修饰符的
  14. 用匿名内部类时,这个new之后的类首先是要存在的,其次我们要重写new后的类的某个或某些方法
  15. 匿名内部类访问方法参数时也有和局部内部类同样的限制
  16. 匿名内部类没有构造方法