局部内部类

说明:局部内部类是定义在外部类的局部位置,比如方法中,而且有类名.

  1. 可以直接访问外部类的所有成员,包含私有.

  2. 不能添加访问修饰符,因为他的地位就是一个局部变量.局部变量是不能使用修饰符的.但是可以使用 final 修饰,因为局部变量也可以使用 final

  3. 作用域:仅仅在定义它的方法或代码块中.

  4. 局部内部类—-访问—->外部类成员 [访问方式:直接访问]

  5. 外部类—-访问—->局部内部类的成员
    访问方式:创建对象,再访问(注意:必须在作用域内)

  6. 外部其它类—->不能访问—->局部内部类( 因为 局部内部类地位是一个局部变量)

  7. 如果外部类和局部内部类的成员重名时,默认遵循就近元祖,如果想访问外部类的成员,则可以使用(外部类名.this.成员) 其访问 [演示]

    1. System.out.println("外部类的n2" + 外部类名.this.n2)


解释一下 外部类名.this.成员:
本质就是外部类的对象,即哪个对象调用了 m1 , Outer02.this就是哪个对象

记住:

  1. 1. 局部内部类定义在方法中/代码块
  2. 2. 作用域在方法体或者代码块中
  3. 3. 本质仍然是一个类

局部内部类

  1. ublic class LocalInnerClass {//
  2. public static void main(String[] args) {
  3. //演示一遍
  4. Outer02 outer02 = new Outer02();
  5. outer02.m1();
  6. System.out.println("outer02的hashcode=" + outer02);
  7. }
  8. }
  9. class Outer02 {//外部类
  10. private int n1 = 100;
  11. private void m2() {
  12. System.out.println("Outer02 m2()");
  13. }//私有方法
  14. public void m1() {//方法
  15. //1.局部内部类是定义在外部类的局部位置,通常在方法
  16. //3.不能添加访问修饰符,但是可以使用final 修饰
  17. //4.作用域 : 仅仅在定义它的方法或代码块中
  18. final class Inner02 {//局部内部类(本质仍然是一个类)
  19. //2.可以直接访问外部类的所有成员,包含私有的
  20. private int n1 = 800;
  21. public void f1() {
  22. //5. 局部内部类可以直接访问外部类的成员,比如下面 外部类n1 和 m2()
  23. //7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
  24. // 使用 外部类名.this.成员)去访问
  25. // 老韩解读 Outer02.this 本质就是外部类的对象, 即哪个对象调用了m1, Outer02.this就是哪个对象
  26. System.out.println("n1=" + n1 + " 外部类的n1=" + Outer02.this.n1);
  27. System.out.println("Outer02.this hashcode=" + Outer02.this);
  28. m2();
  29. }
  30. }
  31. //6. 外部类在方法中,可以创建Inner02对象,然后调用方法即可
  32. Inner02 inner02 = new Inner02();
  33. inner02.f1();
  34. }
  35. }
  1. 局部内部类是定义在外部类的局部位置,通常在方法

  2. 不能添加访问修饰符,但是可以使用 final 修饰

  3. 作用域 : 仅仅在定义它的方法或代码块中

  4. 可以直接访问外部类的所有成员,包含私有的

  5. 局部内部类可以直接访问外部类的成员,比如下面 外部类 n1

  6. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,使用 外部类名.this.成员)去访问
    Outer02.this 本质就是外部类的对象, 即哪个对象调用了 m1, Outer02.this 就是哪个对象

  7. 外部类在方法中,可以创建 Inner02 对象,然后调用方法即可

内部类:

内部类一般来说共分为4种:常规内部类、静态内部类、局部内部类、匿名内部类

一.常规内部类:常规内部类没有用static修饰且定义在在外部类类体中。

  1. 1.常规内部类中的方法可以直接使用外部类的实例变量和实例方法。
  2. 2.在常规内部类中可以直接用内部类创建对象

第7章 内部类 - 图1

运行结果如下:

第7章 内部类 - 图2

二.静态内部类:与类的其他成员相似,可以用static修饰内部类,这样的类称为静态内部类。静态内部类与静态内部方法相似,只能访问外部类的static成员,不能直接访问外部类的实例变量,与实例方法,只有通过对象引用才能访问。

由于static内部类不具有任何对外部类实例的引用,因此static内部类中不能使用this关键字来访问外部类中的实例成员,但是可以访问外部类中的static成员。这与一般类的static方法想通

  1. 例如:
  2. ![](https://img-blog.csdn.net/20180417211020578?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RydWdmcmVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70#alt=img)

运行结果如下:

  1. ![](https://img-blog.csdn.net/20180417211051394?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RydWdmcmVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70#alt=img)

三.局部内部类:在方法体或语句块(包括方法、构造方法、局部块或静态初始化块)内部定义的类成为局部内部类。
局部内部类不能加任何访问修饰符,因为它只对局部块有效。
1).局部内部类只在方法体中有效,就想定义的局部变量一样,在定义的方法体外不能创建局部内部类的对象
2).在方法内部定义类时,应注意以下问题:
①.方法定义局部内部类同方法定义局部变量一样,不能使用private、protected、public等访问修饰说明符修饰,也不能使用static修饰,但可以使用final和 abstract修饰
②.方法中的内部类可以访问外部类成员。对于方法的参数和局部变量,必须有final修饰才可以访问。

  1. ③.static方法中定义的内部类可以访问外部类定义的static成员

例如:

  1. ![](https://img-blog.csdn.net/20180417211722787?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RydWdmcmVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70#alt=img)
  2. 结果如图所示:
  3. ![](https://img-blog.csdn.net/20180417211758266?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RydWdmcmVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70#alt=img)

四.匿名内部类:定义类的最终目的是创建一个类的实例,但是如果某个类的实例只是用一次,则可以将类的定义与类的创建,放到与一 起完成,或者说在定义类的同时就创建一个类
以这种方法定义的没有名字的类成为匿名内部类。
声明和构造匿名内部类的一般格式如下:
new ClassOrInterfaceName(){

  1. /_类体_/ }

1.匿名内部类可以继承一个类或实现一个接口,这里的ClassOrInterfaceName是匿名内部类所继承的类名或实现的接口名。但匿名内部类不能同时实现一个接口和继承一个类,也不能实现多个接口。如果实现了一个接口,该类是Object类的直接子类,匿名类继承一个类或实现一个接口,不需要extends和implements关键字。
2.由于匿名内部类没有名称,所以类体中不能定义构造方法,由于不知道类名也不能使用关键字来创建该类的实例。实际上匿名内部类的定义、构造、和第一次使用都发生在同样一个地方。此外,上式是一个表达式,返回的是一个对象的引用,所以可以直接使用或将其复制给一个对象变量。例:

TypeName obj=new Name(){

  1. /_此处为类体_/<br />

};
同样,也可以将构造的对象作为调用的参数。例:
someMethod(new Name(){
/此处为类体/ });

例如:

  1. ![](https://img-blog.csdn.net/20180417212216999?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RydWdmcmVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70#alt=img)
  2. 结果如图所示:
  3. ![](https://img-blog.csdn.net/20180417212244110?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RydWdmcmVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70#alt=img)

外部类:

  1. 外部类,顾名思义,就是外部的类。定义一个类A,在A的内部再定义一个类B,则A就是外部了类,B就是内部类

外部类与内部类的区别与联系:

  1. 内部类可以访问外部类所有的方法和属性,如果内部类和外部类有相同的成员方法和成员属性,内部类的成员方法调用要优先于外部类即内部类的优先级比较高(只限于类内部,在主方法内,内部类对象不能访问外部类的成员方法和成员属性),外部类只能访问内部类的静态常量或者通过创建内部类来访问内部类的成员属性和方法。

匿名内部类

  1. /**
  2. * 演示匿名内部类的使用
  3. */
  4. public class AnonymousInnerClass {
  5. public static void main(String[] args) {
  6. Outer04 outer04 = new Outer04();
  7. outer04.method();
  8. }
  9. }
  10. class Outer04 { //外部类
  11. private int n1 = 10;//属性
  12. public void method() {//方法
  13. //基于接口的匿名内部类
  14. //老韩解读
  15. //1.需求: 想使用 IA 接口,并创建对象
  16. //2.传统方式,是写一个类,实现该接口,并创建对象
  17. //3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
  18. //4. 可以使用匿名内部类来简化开发
  19. //5. tiger 的编译类型 ? IA
  20. //6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
  21. /*
  22. 我们看底层 会分配 类名 Outer04$1
  23. 韩顺平循序渐进学 Java 零基础
  24. 第 457页
  25. class Outer04$1 implements IA {
  26. @Override
  27. public void cry() {
  28. System.out.println("老虎叫唤...");
  29. }
  30. }
  31. */
  32. //7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
  33. // 返回给 tiger
  34. //8. 匿名内部类使用一次,就不能再使用
  35. IA tiger = new IA() {
  36. @Override
  37. public void cry() {
  38. System.out.println("老虎叫唤...");
  39. }
  40. };
  41. System.out.println("tiger 的运行类型=" + tiger.getClass());
  42. tiger.cry();
  43. tiger.cry();
  44. tiger.cry();
  45. // IA tiger = new Tiger();
  46. // tiger.cry();
  47. //演示基于类的匿名内部类
  48. //分析
  49. 韩顺平循序渐进学 Java 零基础
  50. 458
  51. //1. father 编译类型 Father
  52. //2. father 运行类型 Outer04$2
  53. //3. 底层会创建匿名内部类
  54. /*
  55. class Outer04$2 extends Father{
  56. @Override
  57. public void test() {
  58. System.out.println("匿名内部类重写了 test 方法");
  59. }
  60. }
  61. */
  62. //4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
  63. //5. 注意("jack") 参数列表会传递给 构造器
  64. Father father = new Father("jack"){
  65. @Override
  66. public void test() {
  67. System.out.println("匿名内部类重写了 test 方法");
  68. }
  69. };
  70. System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
  71. father.test();
  72. //基于抽象类的匿名内部类
  73. Animal animal = new Animal(){
  74. @Override
  75. 韩顺平循序渐进学 Java 零基础
  76. 459
  77. void eat() {
  78. System.out.println("小狗吃骨头...");
  79. }
  80. };
  81. animal.eat();
  82. }
  83. }
  84. interface IA {//接口
  85. public void cry();
  86. }
  87. //class Tiger implements IA {
  88. //
  89. // @Override
  90. // public void cry() {
  91. // System.out.println("老虎叫唤...");
  92. // }
  93. //}
  94. //class Dog implements IA{
  95. // @Override
  96. // public void cry() {
  97. // System.out.println("小狗汪汪...");
  98. // }
  99. //}
  100. class Father {//类
  101. 韩顺平循序渐进学 Java 零基础
  102. 460
  103. public Father(String name) {//构造器
  104. System.out.println("接收到 name=" + name);
  105. }
  106. public void test() {//方法
  107. }
  108. }
  109. abstract class Animal { //抽象类
  110. abstract void eat();
  111. }

匿名内部类练习(复习用)

  1. 1.计算器接口具有work方法,功能是运算,有一个手机类Cellphone
  2. 定义方法testWork测试计算功能,调用计算接口的work方法,
  3. 2.要求调用CellPhone对象 testWork方法,使用上 匿名内部类
  1. public class Homework04 {
  2. public static void main(String[] args) {
  3. Cellphone cellphone = new Cellphone();
  4. //老韩解读
  5. //1. 匿名内部类是
  6. /*
  7. new ICalculate() {
  8. @Override
  9. public double work(double n1, double n2) {
  10. return n1 + n2;
  11. }
  12. }, 同时也是一个对象
  13. 他的编译类型 ICalculate, 他的运行类型就是 匿名内部类
  14. */
  15. cellphone.testWork(new ICalculate() {
  16. @Override
  17. public double work(double n1, double n2) {
  18. return n1 + n2;
  19. }
  20. }, 10, 8);//18.0
  21. cellphone.testWork(new ICalculate() {
  22. @Override
  23. public double work(double n1, double n2) {
  24. return n1 * n2;
  25. }
  26. }, 10, 8);
  27. }
  28. }

lambda表达式

语法:

  1. (parameters) -> expression
  2. (parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。

lambda表达式和匿名内部类

  1. // 1. 不需要参数,返回值为 5
  2. () -> 5
  3. // 2. 接收一个参数(数字类型),返回其2倍的值
  4. x -> 2 * x
  5. // 3. 接受2个参数(数字),并返回他们的差值
  6. (x, y) -> x y
  7. // 4. 接收2个int型整数,返回他们的和
  8. (int x, int y) -> x + y
  9. // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
  10. (String s) -> System.out.print(s)
  1. public class Java8Tester {
  2. public static void main(String args[]){
  3. Java8Tester tester = new Java8Tester();
  4. // 类型声明
  5. MathOperation addition = (int a, int b) -> a + b;
  6. // 不用类型声明
  7. MathOperation subtraction = (a, b) -> a - b;
  8. // 大括号中的返回语句
  9. MathOperation multiplication = (int a, int b) -> { return a * b; };
  10. // 没有大括号及返回语句
  11. MathOperation division = (int a, int b) -> a / b;
  12. System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
  13. System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
  14. System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
  15. System.out.println("10 / 5 = " + tester.operate(10, 5, division));
  16. // 不用括号
  17. GreetingService greetService1 = message ->
  18. System.out.println("Hello " + message);
  19. // 用括号
  20. GreetingService greetService2 = (message) ->
  21. System.out.println("Hello " + message);
  22. greetService1.sayMessage("Runoob");
  23. greetService2.sayMessage("Google");
  24. }
  25. interface MathOperation {
  26. int operation(int a, int b);
  27. }
  28. interface GreetingService {
  29. void sayMessage(String message);
  30. }
  31. private int operate(int a, int b, MathOperation mathOperation){
  32. return mathOperation.operation(a, b);
  33. }
  34. }