JavaSE进阶03:内部类、Lambda表达式

系列文章目录

JavaSE进阶01:继承、修饰符
JavaSE进阶02:多态、抽象类、接口
JavaSE进阶03:内部类、Lambda表达式
JavaSE进阶04:API中常用工具类
JavaSE进阶05:包装类、递归、数组的高级操作、异常
JavaSE进阶06:Collection集合、迭代器、List、ArrayList、LinkedList
JavaSE进阶07:泛型、Set集合、TreeSet、二叉树、红黑树
JavaSE进阶08:HashSet、Map集合、HashMap、TreeMap、可变参数、不可变集合
JavaSE进阶09:Stream流、File类
JavaSE进阶10:IO流、字节流、字节缓冲流
JavaSE进阶11:字符流、字符缓冲流、转换流、对象操作流、Properties集合
JavaSE进阶12:多线程、线程同步、线程池
JavaSE进阶13:网络编程入门、UDP通信程序、TCP通信程序、日志、枚举
JavaSE进阶14:类加载器、反射
JavaSE进阶15:XML、注解、单元测试
JavaSE进阶扩充:JDK8 HashMap底层分析(了解)
JavaSE进阶扩充:JDK8 ArrayList线程安全问题和源码分析、集合常见面试题
Java进阶作业



1:内部类

1.1 内部类概述(理解)

内部类:就是在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类

内部类分类:
内部类在类中定义的位置不同,可以分为如下两种形式

  • 在类的成员位置:成员内部类
  • 在类的局部位置:局部内部类

内部类的访问特点:

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象
package lesson0409;
public class Outer {
    private int num = 10;
    public class Inner {
        public void show() {
            System.out.println(num);
        }
    }
    public void method() {
//      show();//外部类要访问内部类的成员,必须创建对象
        Inner i = new Inner();
        i.show();
    }

}
class TestOuter{
    public static void main(String[] args) {
        Outer outer =new Outer();
        outer.method();//10

    }
}

1.2 成员内部类(理解)

成员内部类就是指在类的成员位置定义内部类。

成员内部类分为:

  • 私有成员内部类
  • 静态成员内部类

外界创建成员内部类格式:

  • 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
  • 举例:Outer.Inner oi = new Outer().new Inner();
public class Outer {
    //静态的成员内部列
    public  class Inner{
        public void show(){
            System.out.println("Inner..show");
        }

    }
}
class TestOuter{
    public static void main(String[] args) {
        //非私有内部列创建对象调用方法
        Outer.Inner inner=new Outer().new Inner();
        inner.show();
    }
}

私有成员内部类

将一个类,设计为内部类的目的,大多数都是不想让外界去访问,所以内部类的定义应该私有化,私有化之后,再提供一个可以让外界调用的方法,方法内部创建内部类对象并调用。
私有成员内部类:只能在自己所在的外部类中创建对象访问

私有成员内部类例子:

public class Outer2 {
    //私有的成员内部类的访问特点:只能在自己所在的外部类中创建对象访问
    private static class Inner{
        public void show1(){
            System.out.println("private..Inner..show");
        }
        public static void show2(){
            System.out.println("private..Inner..static..show2");
        }
    }
    public void method(){
        Inner inner=new Inner();
        inner.show1();
        Inner.show2();
    }
}
class TestOuter2{
    public static void main(String[] args) {
//        Outer2.Inner inner=new Outer2.Inner();
//        inner.show();
//        inner.method();
//        Outer2.Inner.method();
//        //以上都报错,因为Inner为私有
        Outer2 outer=new Outer2();
        outer.method();
    }
}

静态成员内部类

  • 静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
  • 静态成员内部类中的静态方法:外部类名.内部类名.方法名();

静态成员内部类例子:

public class Outer {
    //静态的成员内部列
     public static class Inner{
        public void show(){
            System.out.println("Inner..show");
        }
        public static void show2(){
            System.out.println("Inner..static..show2");
        }
    }
}
class TestOuter{
    public static void main(String[] args) {
        //非私有内部列创建对象调用方法
        Outer.Inner inner=new Outer.Inner();
        inner.show();
        inner.show2();
        //静态内部类的静态方法可以直接静态调用方法
        Outer.Inner.show2();
    }
}

1.3 局部内部类(理解)

  • 局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用
  • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
  • 局部内部类能用的修饰符只有final和abstract。因为局部内部类是放在代码块或方法中的,不能有访问控制修饰符,且不能用static修饰。
public class Outer {
    private int num = 10;
    public void method() {
        int num2 = 20;
        class Inner {
            public void show() {
                System.out.println(num);//10
                System.out.println(num2);//20
            }
        }
        Inner i = new Inner();
        i.show();
    }
}
class OuterDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}

1.4 匿名内部类(应用)

匿名内部类是局部内部类的一种特殊形式,所以它归属于局部内部类。
匿名内部类的理解:将 继承或实现、方法重写、创建对象 放在了一步进行。
匿名内部类前提:存在一个或者接口,这里的类可以是具体类也可以是抽象类

/*格式*/
new 类名or接口名(){
	重写方法;
}
/*范例*/
new Inter(){
	public void show(){
	}
}

这里有new,说明最终结果应该是一个对象。但是如果这里是抽象类或者接口,它是不能创建对象的,那这个对象到底是什么对象呢?它里面重写了父类或者接口中的方法,所以,说明这里的对象应该是一个父类的子类对象或者接口的实现类对象。因为该实现类对象没有名字,所以叫做匿名内部类。

匿名内部类本质:是一个继承了该类的子类匿名对象,或者是一个实现了该接口的实现类匿名对象

/*接口*/
public interface InterMore {
    public abstract void show1();
    public abstract void show2();
}

public interface InterOnly {
    public abstract void show3();
}

↓传统创建实现类对象↓

/*
	传统实现接口或抽象类:
	1.创建一个接口
	2.创建一个实现类,通过imlements关键字去实现该接口
	3.重写父类接口的抽象方法
	4.创建实现类对象
	5.调用重写后的方法
*/
/*实现类*/
public class InterImpl implements InterMore {
    @Override
    public void show1() {
        System.out.println("InterImpl...show1");
    }
    @Override
    public void show2() {
        System.out.println("InterImpl...show2");
    }
}
/*测试类*/
public class Anonymous {
    public static void main(String[] args) {
        System.out.println("↓传动实现类↓");
        InterMore inter=new InterImpl();
        inter.show1();
        inter.show2();
}

↓匿名内部类单方法情况↓

public class Anonymous {
    public static void main(String[] args) {
        System.out.println("↓匿名内部类单方法情况↓");
        new InterOnly(){
            @Override
            public void show3() {
                System.out.println("InterOnly...show3");
            }
        }.show3();
}

↓匿名内部类多方法情况↓

public class Anonymous {
    public static void main(String[] args) {
        System.out.println("↓匿名内部类多方法情况↓");
        InterMore interMore = new InterMore() {
            @Override
            public void show1() {
                System.out.println("InterMore...show1");
            }
            @Override
            public void show2() {
                System.out.println("InterMore...show2");
            }
        };
        interMore.show1();
        interMore.show2();
    }
}

1.5 匿名内部类在开发中的应用(应用)

当一个方法的参数是抽象类或接口时,使用匿名内部类非常方便。

/*游泳接口*/
public interface Swimming {
    void goSwimming();
}
/*潜水接口*/
public interface Diving {
    void goDiving();
}
/*测试类*/
public class TestAnoymous {
    public static void goSV(Swimming swimming,Diving diving){
        swimming.goSwimming();
        diving.goDiving();
    }
    public static void main(String[] args) {
        goSV(new Swimming() {
            @Override
            public void goSwimming() {
                System.out.println("去游泳");
            }
        }, new Diving() {
            @Override
            public void goDiving() {
                System.out.println("去潜水");
            }
        });
    }
}

1.6 API 回顾

来,继续啊,学完了面向对象高级部分的知识后,下面呢我们来回顾一下前面学习过的JDK提供的几个API。

当时,不敢多看,是因为好多知识我们还没有学习,现在我们就可以去看看了。

我们重点看以下三个类:

  • String
  • SimpleDateFormat
  • JFrame

接下来,依次来看:

1:String

格式问题:
在这里插入图片描述

equals方法的参数问题:多态
在这里插入图片描述

2:SimpleDateFormat

格式问题:
在这里插入图片描述

格式化和解析的方法问题:来自父类
在这里插入图片描述
在这里插入图片描述

3:JFrame

格式问题:
在这里插入图片描述

添加方法的问题:来自于继承体系,并且参数是多态的形式
在这里插入图片描述
在这里插入图片描述

方法参数为什么不直接是:JButton,JLabel,JTextField,JTextArea呢?多态
在这里插入图片描述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqP6yGoh-1649210742187)(imgs/1640920087405.png)]

剩下两个,自己看。

通过刚才的API的回顾,我们发现了,JDK提供的API中处处体现了继承关系,实现关系,以及多态的应用。而这些内容只有我们学完了面向对象高级知识才能够看懂。当然,目前我们仅仅是从语法

层面对面向对象有了进一步的了解,而面向对象设计层面的知识,我们还需要再后续学习过程中,不断的去思考,去理解。特别是当我们后面做完一个实际开发的项目后,对面向对象我们可能才会

有一些比较深刻的体会。

好了,关于API的回顾我们就先讲到这里。

2:Lambda表达式

2.1 体验Lambda表达式(理解)

这个符号就叫做Lambda,它被称为函数式编程。
在这里插入图片描述
函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”。
面向对象思想:匿名内部类实现,重点是做什么?
函数式思想:Lambda表达式实现,重点是哪个对象去怎么做事情?

public interface Inter {
    void show();
}
/* 测试类 */
public class InterDemo {
    public static void main(String[] args) {
        //匿名内部类实现:强调怎么做?
        useInter(new Inter() {
            @Override
            public void show() {
                System.out.println("匿名内部类实现");
            }
        });
        //Lambda表达式实现:强调做什么?
        useInter(() -> {
            System.out.println("Lambda表达式实现");
        });
    }
    public static void useInter(Inter i) {
        i.show();
    }
}

2.2 Lambda表达式标准格式(理解)

Lambda表达式的使用前提:

  • 有一个接口
  • 接口中只能有一个抽象方法

Lambda表达式的三要素形式参数箭头代码块

Lambda表达式的格式:

  • 格式:(形式参数) -> {代码块}
  • 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可。
  • ->:由英文中划线和大于符号组成,固定写法,代表指向动作。
  • 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容。

总结起来就是一句话:拿着形式参数去做代码块中的事情

@FunctionalInterface  //检查当前的借口是否是一个 函数式接口:1.接口 2.只有一个抽象方法
public interface Swimming{
	public abstract void swim();
	//以下都不是抽象方法,上面有且仅有一个抽象方法,@FunctionalInterface 不报错
	public default void method(){
		System.out.println("我是一个默认方法");
	}
	private void method2(){
		System.out.println("我是一个私有方法");
	}
	static void method3(){
		System.out.println("我是一个静态方法");
	}
	
}

注意:
如果一个接口没有直接的父接口,name会将Object中的public方法在接口中隐式的声明一份,参数和返回值都一样。在接口中重写了父类Object类中任意一个public方法的方法并不算接口中的抽象方法。

@FunctionalInterface  //不会报错,确定为函数式借口
public interface Inter{
	public abstract boolean compare(inta,intb);
	@Override//不报错,确定为重写
	public abstract boolean equals(Object obj);//重写Obect中的equals方法,并不是Inter自己的方法
}

这个equals方法的具体实现来自于Object类,由此可以知道即使接口里面对equals方法进行了定义,实际上的实现还是Object方法中的,在Java语言规范中,如果一个接口没有父接口,那么就会将Object中的public方法在接口里隐含的申明一份,参数,返回值什么的都一样.
重写了父类Object类中任意一个public方法的方法并不算接口中的抽象方法。所以虽然Compare接口中有两个抽象方法compare和equals,但equals并不算接口中的抽象方法,所以Compare接口还是满足函数式接口的要求,Compare接口是一个函数式接口。


匿名内部类中重写show()方法的代码分析

  • 方法形式参数为空,说明调用方法时不需要传递参数
  • 方法返回值类型为void,说明方法执行没有结果返回
  • 方法体中的内容,是我们具体要做的事情
    在这里插入图片描述
    Lambda表达式的代码分析
  • ():里面没有内容,可以看成是方法形式参数为空
  • ->:用箭头指向后面要做的事情
  • { }:包含一段代码,我们称之为代码块,可以看成是方法体中的内容
    在这里插入图片描述

2.3 练习1(无参无返回值)(应用)

public interface Eatable {
    void eat();
}
/*
    Lambda表达式的格式:(形式参数) -> {代码块}

    练习1:
        1:定义一个接口(Eatable),里面定义一个抽象方法:void eat();
        2:定义一个测试类(EatableDemo),在测试类中提供两个方法
            一个方法是:useEatable(Eatable e)
            一个方法是主方法,在主方法中调用useEatable方法
 */
public class EatableDemo {
    public static void main(String[] args) {
        //在主方法中调用useEatable方法
        //匿名内部类
        useEatable(new Eatable() {
            @Override
            public void eat() {
                System.out.println("一天一苹果,医生远离我");
            }
        });

        //Lambda表达式
        useEatable(() -> {
            System.out.println("一天一苹果,医生远离我");
        });
    }

    private static void useEatable(Eatable e) {
        e.eat();
    }
}

2.4 练习2(带参无返回值)(应用)

public interface Flyable {
    void fly(String s);
}
/*
    Lambda表达式的格式:(形式参数) -> {代码块}

    练习2:
        1:定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);
        2:定义一个测试类(FlyableDemo),在测试类中提供两个方法
            一个方法是:useFlyable(Flyable f)
            一个方法是主方法,在主方法中调用useFlyable方法
 */
public class FlyableDemo {
    public static void main(String[] args) {
        //在主方法中调用useFlyable方法
        //匿名内部类
        useFlyable(new Flyable() {
            @Override
            public void fly(String s) {
                System.out.println(s);
                System.out.println("飞机自驾游");
            }
        });
        System.out.println("--------");

        //Lambda
        useFlyable((String s) -> {
            System.out.println(s);
            System.out.println("飞机自驾游");
        });

    }

    private static void useFlyable(Flyable f) {
        f.fly("风和日丽,晴空万里");
    }
}

2.5 练习3(带参带返回值)(应用)

public interface Addable {
    int add(int x,int y);
}
/*
    Lambda表达式的格式:(形式参数) -> {代码块}

    练习3:
        1:定义一个接口(Addable),里面定义一个抽象方法:int add(int x,int y);
        2:定义一个测试类(AddableDemo),在测试类中提供两个方法
            一个方法是:useAddable(Addable a)
            一个方法是主方法,在主方法中调用useAddable方法
 */
public class AddableDemo {
    public static void main(String[] args) {
        //在主方法中调用useAddable方法
        useAddable((int x,int y) -> {
            return x + y;
//            return  x - y;
        });
    }
    private static void useAddable(Addable a) {
        int sum = a.add(10, 20);
        System.out.println(sum);
    }
}

2.6 Lambda的省略模式(应用)

省略规则:

  • 参数类型可以省略。但是有多个参数的情况下,不能只省略一个
  • 如果参数有且仅有一个,那么小括号可以省略
  • 如果代码块的语句只有一条,可以省略大括号分号,甚至是return。注意:要么都不省略,要么3个都要省略。
public interface Addable {
    int add(int x, int y);
}
public interface Flyable {
    void fly(String s);
}
/*
    Lambda表达式的省略模式
 */
public class LambdaDemo {
    public static void main(String[] args) {
//        useAddable((int x,int y) -> {//原式
//            return x + y;
//        });
        
        useAddable((x, y) -> {//参数的类型可以省略
            return x + y;
        });
        
//        useAddable((x,int y) -> {//报错:但是有多个参数的情况下,不能只省略一个
//            return x + y;
//        });

//        useFlyable((String s) -> {//原式
//            System.out.println(s);
//        });

//        useFlyable((s) -> {//参数的类型可以省略
//            System.out.println(s);
//        });

        
//        useFlyable(s -> {//如果参数有且仅有一个,那么小括号可以省略
//            System.out.println(s);
//        });

        //如果代码块的语句只有一条,可以省略大括号和分号,必须都省掉
        useFlyable(s -> System.out.println(s));

        //如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉,即必须都省掉。
        useAddable((x, y) -> x + y);
    }
    private static void useFlyable(Flyable f) {
        f.fly("风和日丽,晴空万里");
    }
    private static void useAddable(Addable a) {
        int sum = a.add(10, 20);
        System.out.println(sum);
    }
}

2.7 Lambda和匿名内部类的区别(理解)

  • 所需类型不同
    • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
    • Lambda表达式:只能是接口
  • 使用限制不同
    • 如果接口中仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
    • 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
  • 实现原理不同
    • 匿名内部类:编译之后,产生一个单独的.class字节码文件
    • Lambda表达式:编译之后,你没有看到一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
public interface Inter {
    void show();
//    void show2();
}
public abstract class Animal {
    public abstract void method();
}
public class Student {
    public void study() {
        System.out.println("爱生活,爱Java");
    }
}
/*
    Lambda表达式和匿名内部类的区别
 */
public class LambdaDemo {
    public static void main(String[] args) {
        //匿名内部类
        useInter(new Inter() {
            @Override
            public void show() {
                System.out.println("接口");
            }
        });
        useAnimal(new Animal() {
            @Override
            public void method() {
                System.out.println("抽象类");
            }
        });
        useStudent(new Student(){
            @Override
            public void study() {
                System.out.println("具体类");
            }
        });

        //Lambda
//        useInter(() -> System.out.println("接口"));
//        useAnimal(() -> System.out.println("抽象类"));
//        useStudent(() -> System.out.println("具体类"));

//        useInter(() -> System.out.println("接口"));

//        useInter(new Inter() {
//            @Override
//            public void show() {
//                System.out.println("show");
//            }
//
//            @Override
//            public void show2() {
//                System.out.println("show2");
//            }
//        });

    }

    private static void useStudent(Student s) {
        s.study();
    }
    private static void useAnimal(Animal a) {
        a.method();
    }
    private static void useInter(Inter i) {
        i.show();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值