Java内部类和Lambda表达式(入门)

Java内部类和Lambda表达式

主要内容来源:华科-辜老师ppt

一、内部类

内部类也称为嵌套类,是在一个类的内部定义的类。通常一个内部类仅被其外部类使用时,同时也不想暴露出去,才定义为内部类。内部类不能定义在方法中

实例内部类内部不允许定义静态成员。创建实例内部类的对象时需要使用外部类的实例变量.new 实例内部类类名( )。(即只有当有了外部类的实例,才能实例化 实例内部类的对象)

静态内部类用static定义,其内部允许定义实例成员和静态成员。

静态内部类的方法不能访问外部类的实例成员变量。

创建静态内部类的对象时需要使用new 外部类.静态内部类( )

注意静态和实例两种内部类的声明方式。

个人理解:因为实例内部类不能通过类名访问到,只能通过实例访问,而静态内部类就可以。

class Wrapper{
    private int x=0;
    private static int z = 0;
    //内部静态类
    static class A{
        int y=0;
        //可以定义静态成员,
        //不能访问外部类的实例成员x,可访问外部类静态成员z
        static int q=0;
        int g() {  return ++q + ++y + ++z; }
    }
    //内部实例类,不能定义静态成员,
    //内部实例类可访问外部类的静态成员如z,实例成员如x
    class B{
        int y=0;
        public int g( ) {
            x++; y++;z++;
            return x+y;
        }
        public int getX(){return x;}
    }
}

public static void main(String[] args){
        Wrapper w = new Wrapper();  //w.x = 0;
        //创建内部静态类实例
        Wrapper.A a = new Wrapper.A(); 	//a.y=0, a.q=0;
        Wrapper.A b = new Wrapper.A();	 //b.y=0, b.q=0;
        a.g();
        //a,b的实例成员彼此无关,因此执行完a.g()后,a.y = 1, b.y = 0;
        //a,b共享静态成员q,所以a.q=b.q = 1;
        
        //创建内部实例类实例
        //不能用new Wrapper.B();必须通过外部类对象去实例化内部类对象
        Wrapper.B  c = w.new B(); //类型声明还是外部类.内部类
        c.y=0;
        c.g(); //c.y = 1 ,c.gextX() = 1
        
        //在外部类体外面,不能通过内部类对象访问外部类成员,只能在内部类里面访问,       
        //编译器在这里只能看到内部类成员
//        System.out.println(a.z); //错误
//        System.out.println(c.x); //错误
        //不能通过c直接访问外部类的x,可通过c.gextX()
        System.out.println(c.getX());
}

一个内部类被编译成名为OuterClassName$InnerClassName的类

内部类作用:如果一个类A仅仅被某一个类B使用,且A无需暴露出去,可以把A作为B的内部类实现,内部类也可以避免名字冲突:因为外部类多了一层名字空间的限定。例如类Wrapper1、Wrapper2可以定义同名的内部类A而不会导致冲突。

匿名内部类:没有名字的内部类

匿名内部类可以简化变成,简化时视同匿名内部类的父类或者接口代替匿名内部类。

//内部类
public class HandleWindowEvent extends Application {
    public void start(Stage primaryStage) throws Exception {
        //其它代码省略
        primaryStage.setOnCloseRequest(new WindowEventHandlerClass ( ) );
    }
    class WindowEventHandlerClass implements 
	EventHandler<WindowEvent> {
        public void handle(WindowEvent e) { //处理语句 }
    }
}
//匿名内部类
public class HandleWindowEvent extends Application {
    public void start(Stage primaryStage) throws Exception {
        //其它代码省略
        primaryStage.setOnCloseRequest(
                         new  EventHandler<WindowEvent>( ) {
                               public void handle(WindowEvent e) { //处理语句 }
                         }	
        );
        //匿名内部类没有类名,用这个类所实现的接口作为匿名内部类的类名 new
}
        //new一个内部匿名类对象时,new 后面直接用这个匿名内部类的父类或者所实现接口作为类型

匿名内部类总是使用父类的无参构造方法产生实例,对于接口使用Object( )。

匿名内部类必须实现父类或者接口的所有抽象方法,事件处理接口通常只有1个方法。

一个匿名内部类被编译成OuterClassName$n.class,如Test$1.class, Test$2.class

二、Lambda表达式

  • Lambda表达式可以进一步简化事件处理的程序编写

  • 只有一个方法的接口称为功能接口(函数式接口),每个 Lambda 表达式都能隐式地赋值给函数式接口,lamda表达式中的{ }就是函数式接口中接口方法的方法体。

  • Lambda表达式本质上更像匿名函数。

  • Java里规定Lambda表达式只能赋值给函数式接口。

  • Lambda表达式的语法为:

(type1 para1, …, typen paran)->expression 或者

(type1 para1, …, typen paran)->{ 一条或多条语句}

  • 当把Lambda表达式赋值给函数式接口时, Lambda表达式的参数的类型是可以推断的;如果只有一个参数,则可以省略圆括弧。从而使Lambda表达式简化为:
    e->处理e的expression 或者
    e->{ 处理e的statements; }
(int a, int b) -> { return a + b; } 
() -> System.out.println("Hello World")
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 ;}

Lambda 表达式的结构:

  • 一个 Lambda 表达式可以有零个或多个参数

  • 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同(当可以推断类型时)

  • 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
    空圆括号代表参数集为空。例如:() -> 42

  • 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> {return a*a;}

  • Lambda 表达式的主体可以是表达式或者是block,如果是表达式,不能有{};如果是block,则必须加 { }

每个 Lambda 表达式都能隐式地赋值给函数式接口:

  • Runnable接口就是函数式接口,里面定义接口方法void run( ),我们可以通过 Lambda 表达式创建一个接口实例 。
  • 上面语句的含义是:将一个实现了Runnable接口的类的实例赋值给Runnable接口引用r, Lambda 表达式的主体就是接口方法void run( )的具体实现
  • 当不是显式赋值给函数式接口时,编译器会自动解释这种转化:
new Thread( 
	() -> System.out.println("hello world") 
).start(); 
  • 在上面的代码中,编译器会自动推断:根据线程类的构造函数签名 public Thread(Runnable r) { },将该 Lambda 表达式赋给 Runnable 接口。

lambda表达式和Runnable接口天然合适

//定义一个函数式接口 
public interface WorkerInterface { 
	public void doSomeWork(); 
} 

public class WorkerInterfaceTest { 
	public static void exec(WorkerInterface worker) { 
		worker.doSomeWork(); 
	} 

	public static void main(String [] args) { 
		//invoke doSomeWork using Annonymous class 
        //匿名类
		exec( new WorkerInterface() { 
			@Override public void doSomeWork() { 
			System.out.println("Worker invoked using Anonymous class"); } 
		} ); 
        //invoke doSomeWork using Lambda expression 
		//Lambda表达式
        exec( () -> System.out.println("Worker invoked using Lambda expression") ); 
	}
 } 
//Old way: 
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7); 
int sum = 0; 
for(Integer n : list) { 
	int x = n * n; 
	sum = sum + x;
 } 
System.out.println(sum); 

//New way: 
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
 int sum = list.stream().map(x -> x*x).reduce((x,y) -> x + y).get(); 
System.out.println(sum); 

补充

闭包的理解:闭包(Closure)并不是一个新鲜的概念,很多函数式语言中都使用了闭包。例如在JavaScript中,当你在内嵌函数中使用外部函数作用域内的变量时,就是使用了闭包。用一个常用的类比来解释闭包和类(Class)的关系:类是带函数的数据,闭包是带数据的函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值