Java学习笔记-嵌套类

嵌套类

嵌套类有两种档次: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(); 即通过外部类实例才能访问内部类。

有多少个比较新鲜的中间类,分别为一些内部类和匿名类。

局地内部类

  • 部分内部类(Local
    CLasses)可注脚在类中任意块(block)中,如方法、for或if块中
  • 有的内部类可以访问外部类的积极分子,若有些内部类表明在静态块中,则可访问外部类的静态成员;若表明在非静态块中,则可访问外部类具有成员;
  • 有些内部类能够访问所在块的片段变量,但该部分变量必须声明为final;在JDK8中展开了考订,局地变量可以注脚为final或effectively
    final;
  • 其余特色类似于一般性内部类

内部effectively
final与final局地变量的分别在于,前者可以不显式声明变量为final,只要在整个经过中,该变量不会被修改(编译器默许该情状为final)。具体怎么有些内部类为啥必须引用final变量,可参看

java为何匿名内部类的参数引用时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         };

 匿名内部类适用于只用一次的情况。其他的表征与一些内部类相同。

Lambda表达式

 在动用匿名内部类的时候,无需提供类名。对于唯有一个艺术的接口,使用拉姆da分明比匿名类的兑现不难明了。如下所示,定义一个拉姆daTest接口,该接口只含有一个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为方法体,->表示将参数传递给方法体。 

  • 拉姆da表达式的方法体中,可以是一个表明式,也可以是代码块。若为表明式,Java运行期会计算表明式,并回到结果;若为代码块,可以添加return语句,将结果回到。
  • Lambda表明式其实是一个主意的宣示,能够认为拉姆da表达式是匿名格局
  • 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”的不行。

指标项目(Target Type)

对象项目为外部类形式期望调用的花色,如上例中operator期望调用的对象措施为Cal。Java会按照兰姆da表明式所处的语境和上下文音信判断目标项目,并落到实处调用。

比喻如下:

 1 public class TargetType {
 2     
 3     interface Cal{
 4         String op();
 5     }
 6     
 7     interface Cal1{
 8         int op1();
 9     }
10     
11     interface Cal2{
12         void op1();
13     }
14     
15     public static String invoke(Cal cal) {
16         return cal.op();
17     }
18     
19     public static void invoke(Cal1 cal1) {
20         cal1.op1();
21     }
22     
23     public static void invoke(Cal2 cal2) {
24         cal2.op1();
25     }
26 
27     public static void main(String[] args) {
28         invoke(() -> "done");
29         invoke(() -> 100);
30         invoke(() -> {return;});
31     }
32 }

宣称七个接口(Cal Cal1
Cal2),具有同样名称的方法,但她们的重返值不一致。另注明了3个invoke方法,分别收到3个类,即希望的靶子项目差异。然后开展测试:

main方法中的多少个语句都因而编译,并且eclipse提醒28行调用目的项目为Cal的invoke,29行调用目的项目为Cal1的invoke,30行调用目标项目为Cal2的invoke,目的项目如下图所示:

图片 1

(1)借使再添加一句如:invoke(() -> 100.0);  则编译器会报错,Type
mismatch: cannot convert from double to String;

(2)假诺将Cal接口方法的重返值改为int,则除外28行报错,29行也报错:The
method invoke(TargetType.Cal) is ambiguous for the type
TargetType,即编译器无法确定调用哪个目的项目。

 官网文档中举的例子为Runnable和Callable,原理一样,如下:

1 public interface Runnable {
2     void run();
3 }
4 
5 public interface Callable<V> {
6     V call();
7 }

 方法注明:

1 void invoke(Runnable r) {
2     r.run();
3 }
4 
5 <T> T invoke(Callable<T> c) {
6     return c.call();
7 }

 

 依据上下文确定目的项目,由于有返回值,所以会调用参数为Callable的invoke方法:

1 String s = invoke(() -> "done");

 总结:

  • 静态嵌套类与其中类分别
  • 两类卓殊的里边类,局地内部类和匿名内部类;
  • 匿名内部类的例外落成:Lambda表明式,可认为匿有名的模特式的贯彻;
  • 拉姆da表明式会根据上下文环境确定目的项目

参考:

 

 

相关文章