java学习笔记嵌套,Java学习笔记

2019-10-01 14:35 来源:未知

嵌套类

嵌套类有两种类别:static and non-static,分别对应为静态嵌套类和内部类。

1 class OuterClass {
2     ...
3     static class StaticNestedClass {
4         ...
5     }
6     class InnerClass {
7         ...
8     }
9 }

 

其中静态嵌套类只能访问外部类的静态成员,内部类可以访问外部类的任意成员;它们可以被声明为privatepublicprotected, 或 package private。

  • 静态嵌套类实例化方式为: OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
  • 内部类实例化方式:OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 即通过外部类实例才能访问内部类。

有两个比较特殊的内部类,分别为局部内部类和匿名类。

Java学习笔记-嵌套类,java学习笔记嵌套

局部内部类

  • 局部内部类(Local CLasses)可声明在类中任意块(block)中,如方法、for或if块中
  • 局部内部类可以访问外部类的成员,若局部内部类声明在静态块中,则可访问外部类的静态成员;若声明在非静态块中,则可访问外部类所有成员;
  • 局部内部类可以访问所在块的局部变量,但该局部变量必须声明为final;在JDK8中进行了改进,局部变量可以声明为final或effectively final;
  • 其他特性类似于普通内部类

其中effectively final与final局部变量的区别在于,前者可以不显式声明变量为final,只要在整个过程中,该变量不会被修改(编译器默认该情况为final)。具体为什么局部内部类为什么必须引用final变量,可参考

java为什么匿名内部类的参数引用时final? 。大致意思是局部内部类引用局部变量,其实是进行的值引用(或者说是值拷贝)。可以认为避免外部代码块在内部类运行结束前结束,导致局部变量回收而出错。

嵌套类

嵌套类有两种类别:static and non-static,分别对应为静态嵌套类和内部类。

1 class OuterClass {
2     ...
3     static class StaticNestedClass {
4         ...
5     }
6     class InnerClass {
7         ...
8     }
9 }

 

其中静态嵌套类只能访问外部类的静态成员,内部类可以访问外部类的任意成员;它们可以被声明为privatepublicprotected, 或 package private。

  • 静态嵌套类实例化方式为: OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
  • 内部类实例化方式:OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 即通过外部类实例才能访问内部类。

有两个比较特殊的内部类,分别为局部内部类和匿名类。

匿名类

匿名类与局部内部类相似,只是没有命名,并且同时进行声明和实例化。如下:

 1 HelloWorld frenchGreeting = new HelloWorld() {
 2             String name = "tout le monde";
 3             public void greet() {
 4                 greetSomeone("tout le monde");
 5             }
 6             public void greetSomeone(String someone) {
 7                 name = someone;
 8                 System.out.println("Salut " + name);
 9             }
10         };

 匿名内部类适用于只用一次的情况。其他的特性与局部内部类相同。

局部内部类

  • 局部内部类(Local CLasses)可声明在类中任意块(block)中,如方法、for或if块中
  • 局部内部类可以访问外部类的成员,若局部内部类声明在静态块中,则可访问外部类的静态成员;若声明在非静态块中,则可访问外部类所有成员;
  • 局部内部类可以访问所在块的局部变量,但该局部变量必须声明为final;在JDK8中进行了改进,局部变量可以声明为final或effectively final;
  • 其他特性类似于普通内部类

其中effectively final与final局部变量的区别在于,前者可以不显式声明变量为final,只要在整个过程中,该变量不会被修改(编译器默认该情况为final)。具体为什么局部内部类为什么必须引用final变量,可参考

java为什么匿名内部类的参数引用时final? 。大致意思是局部内部类引用局部变量,其实是进行的值引用(或者说是值拷贝)。可以认为避免外部代码块在内部类运行结束前结束,导致局部变量回收而出错。

Lambda表达式

 在使用匿名内部类的时候,无需提供类名。对于只有一个方法的接口,使用Lambda显然比匿名类的实现简单明了。如下所示,定义一个LambdaTest接口,该接口只包含一个opt方法:

1 interface LambdaTest {
2     int opt(int a , int b);
3 }
4 
5 LambdaTest sumTest = (a,b) -> a+b;

第5行即为Lambda表达式声明,其中(a,b)为方法的参数,a+b为方法体,->表示将参数传递给方法体。 

  • Lambda表达式的方法体中,可以是一个表达式,也可以是代码块。若为表达式,Java运行期会计算表达式,并返回结果;若为代码块,可以添加return语句,将结果返回。
  • Lambda表达式其实是一个方法的声明,可以认为Lambda表达式是匿名方法
  • Lambda表达式与局部内部类和匿名类相似,可以访问外部类和外部代码块的变量;但与后两者不同,其不存在变量覆盖的问题,可以认为没有引入新的代码块,其与外部代码块中的局部变量同级
  • 由于第三条,所以在表达式的参数中,不能声明与同级作用域相同的变量名,否则会出现重复定义的异常。
  • Lambda表达式是匿名内部类实现形式的一种,其访问的外部变量必须是final或effectively final。

举例如下:

 1 public class Lambda {
 2     
 3     private int var = 100;
 4     private String x = "hello";
 5     
 6     interface Cal{
 7         int op(int a, int b);
 8     }
 9     
10     interface Print{
11         void print(String msg);
12     }
13     
14     public int operator(int a, int b, Cal cal) {
15         return cal.op(a, b);
16     }
17 
18     public void operator1(String msg, Print print) {
19         print.print(msg);
20     }
21     
22     public void operator2(String x) {
23         
24 //        x = "";
25         
26         Print print = (msg) -> {
27             System.out.println("Lambda访问外部变量:");
28             System.out.println(x);
29             System.out.println(msg);
30             System.out.println(Lambda.this.x);
31         };
32         
33         print.print(x);
34     }
35     
36     public static void main(String[] args) {
37         Cal add = (a,b) -> {return a+b;};
38         Cal mul = (a,b) -> a*b;
39         
40         Lambda lambda = new Lambda();
41         System.out.println("2+3="+lambda.operator(2, 3, add));
42         System.out.println("2*3="+lambda.operator(2, 3, mul));
43         
44         lambda.var = 200;
45         Print print = (msg) -> {
46             System.out.println(msg);
47             System.out.println(lambda.var);
48         };
49         lambda.operator1("Hello World", print);
50 
51         lambda.operator2("Hello Lambda");
52     }
53 
54 }

运行结果:

1 2+3=5
2 2*3=6
3 Hello World
4 200
5 Lambda访问外部变量:
6 Hello Lambda
7 Hello Lambda
8 hello

 其中operator2方法可以验证后三条,如果将24行的注释取消,28行就会报“local variables referenced from a lambda expression must be final or effectively final”的异常。

匿名类

匿名类与局部内部类相似,只是没有命名,并且同时进行声明和实例化。如下:

 1 HelloWorld frenchGreeting = new HelloWorld() {
 2             String name = "tout le monde";
 3             public void greet() {
 4                 greetSomeone("tout le monde");
 5             }
 6             public void greetSomeone(String someone) {
 7                 name = someone;
 8                 System.out.println("Salut " + name);
 9             }
10         };

 匿名内部类适用于只用一次的情况。其他的特性与局部内部类相同。

TAG标签:
版权声明:本文由金沙澳门官网4166发布于世界史,转载请注明出处:java学习笔记嵌套,Java学习笔记