【学习日记2023.3.28】之 内部类_lambda表达式_API(Math_System_Runtime_BigDecima)

1. 内部类

在类的内部定义的类

public class Outer{ // 外部类
    class Inner{ // Inner称为Outer这个类的内部类
    
    }
}

1.1 分类

  • 成员内部类(了解)
  • 静态内部类(了解)
  • 局部内部类(了解)
  • 匿名内部类(重点)

1.2 成员内部类

  • 定义格式
public class 外部类{
    private int num;
    
    // 和其他成员平级
    修饰符 class 内部类{
        
    }
    public void show(){}
    
}
  • 使用格式
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
Outer.Inner oi = new Outer().new Inner();

内部类笔试题

  • 内部类成员访问特点: 就近原则
  • 外部类成员: 外部类名.this.成员
  • 外部类的父类成员: 外部类名.super.成员
public class Outer extends Fu{
    private int num = 30; // 外部类的成员变量
    /*
         成员内部类: 定义在类中成员位置
         内部类中成员的访问特点: 就近原则
            外部类成员  外部类名.this.成员
            外部类父类成员 外部类名.super.成员
     */

    public class Inner{
        public int num = 20; // 内部类中的成员变量
        public void test(){
            int num = 10; // 局部变量
            System.out.println(num); // 10
            System.out.println(this.num); // 20
            System.out.println(Outer.this.num); // 30
            System.out.println(Outer.super.num);// 40
        }
    }

    public void show(){

    }
}

public class Fu {
    public int num = 40;
}

1.3 静态内部类

  • staitc修饰的成员内部类
  • 静态内部类的定义
public class Outer {
    
    // 静态内部类: static修饰的成员内部类
    public static class Inner{
        public void show(){
            System.out.println("我是内部类中的show方法");
        }
    }
    
}
  • 静态内部类的使用
  • 外部类名.内部类名 变量名 = new 外部类名.内部类名();
public class Demo {
    public static void main(String[] args) {
        // 静态内部类使用格式: 外部类名.内部类名 变量名 = new 外部类名.内部类名();
        Outer.Inner i = new Outer.Inner();
        i.show();
    }
}

1.4 局部内部类

  • 定义在方法中
  • 只能在方法中创建对象
public class Outer {

    // 局部内部类: 定义在方法中
    public void show(){


        class Inner{
            public void test(){
                System.out.println("我是局部内部类中的show方法");
            }
        }

        // 局部内部类 只能在方法中创建对象
        Inner i = new Inner();
        i.test();


    }
}

1.5 小结

  • 开发中很少使用
  • 看JDK源代码可能会遇到,能看懂
  • 笔试题: 内部类,成员变量的访问特点

1.6 匿名内部类(重点)

前提

  • 要先有一个类或者接口

格式

new 类名或者接口名(){
    // 重写方法
}

public interface Inter{
    void show();
}

new Inter(){
    public void show(){
        
    }
}

匿名内部类格式的本质

  • 是一个继承了该类的子类【对象】,或者是一个实现了该接口的实现类【对象
  • 在idea中选中模块 -> 右键 -> Open in -> Exporer -> 找到out文件夹 -> 可以找到匿名内部类产生的字节码文件
/*
    1.定义了一个子类或者实现类(没有java文件,但是会产生字节码文件)
    2.重写了方法
    3.创建了一个子类或者实现类的对象
*/
new Inter() {
    @Override
    public void show() {
        System.out.println("匿名内部类");
    }
};

代码

public interface Inter {
    void show();
}
public class Demo {
    public static void main(String[] args) {
      // Inter 是一个接口
      // i 记录了实现类的对象
       Inter i = new Inter() {
           @Override
           public void show() {
               System.out.println("匿名内部类");
           }
       };
        // 调用方法
        i.show();
    }
}

1.7 匿名内部类好处

  • 不需要手动定义很多java文件
  • 更好的支持多态
// 接口
public interface Animal {
    void eat();
}
public class Demo {
    public static void main(String[] args) {
//        Animal a = new Animal() {
//            @Override
//            public void eat() {
//                System.out.println("狗吃肉");
//            }
//        };
//        show(a);
        
        
        show(new Animal() {
            @Override
            public void eat() {
                System.out.println("狗吃肉");
            }
        });
    }

    // 看看动物吃什么
    public static void show(Animal a){
        a.eat();
    }
}

1.8 匿名内部类使用场景

  • 通常作为一个参数传给方法
  • 调用方法,并给参数传值,重点看参数变量的数据类型
  • 如何看参数变量的类型,点进方法的源码,点进参数类型的源码
public class Test {
    public static void main(String[] args) {
        // 参数找我们要一个Runnable接口 ,传递Runnable接口的实现类对象
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println();
            }
        });

        // 集合
        ArrayList<String> list = new ArrayList<>();
        // 参数 找我们要一个Predicate接口,传递Predicate接口的实现类对象
        list.removeIf(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return false;
            }
        });
    }
}

1.9 内部类的字节码文件(知道)

  • 成员(静态)内部类: Outer$Inner.class
  • 局部内部类: Outer$1Inner.class
  • 匿名内部类: Test$1.class

1.10 总结

请添加图片描述

2. Lambda表达式

2.1 体验lambda表达式

lambda

  • 这个λ符号希腊字母,发音为lambda。
  • java中的lambda表达式, 是JDK8开始出现的语法
  • 使用lambda表达式语法进行编程,也被称为函数式编程(Functional Programming)
    请添加图片描述

代码

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();
    }
}

作用

  • 对匿名内部类格式的简化
  • 官网:https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
    请添加图片描述

lambda前提和格式

  • 前提
    • 有一个接口,且接口中只有一个抽象方法
  • 基本格式
    • (形式参数) -> {代码}
      • (形式参数): 和接口中抽象方法中的参数保持一致
      • -> : 固定格式
      • {} : 重写方法的内容

2.2 练习1(无参数无返回值)

接口中的抽象方法,无参数无返回值

步骤

  • 定义一个接口(Eatable),里面定义一个抽象方法:void eat();
  • 定义一个测试类(EatableDemo),在测试类中提供两个方法
    • 一个方法是:useEatable(Eatable e)
    • 一个方法是主方法,在主方法中调用useEatable方法

代码

public interface Eatable {
    void eat();
}
public class EatableDemo {
    public static void main(String[] args) {
        //匿名内部类
        useEatable(new Eatable() {
            @Override
            public void eat() {
                System.out.println("一天一苹果,医生远离我");
            }
        });

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

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

2.3 练习2(带参无返回值)

接口中的抽象方法,带参数无返回值

步骤

  • 定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);
  • 定义一个测试类(FlyableDemo),在测试类中提供两个方法
    • 一个方法是:useFlyable(Flyable f)
    • 一个方法是主方法,在主方法中调用useFlyable方法

代码

public interface Flyable {
    void fly(String s);
}
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("--------");

        //Lambda
        useFlyable((String s) -> {
            System.out.println(s + "在飞");
        });

    }

    public static void useFlyable(Flyable f) {
        f.fly("猪");
    }
}

2.4 练习3(带参带返回值)

接口中的抽象方法,带参数带返回值

步骤

  • 定义一个接口(Addable),里面定义一个抽象方法:int add(int x,int y);
  • 定义一个测试类(AddableDemo),在测试类中提供两个方法
  • 一个方法是:useAddable(Addable a)
  • 一个方法是主方法,在主方法中调用useAddable方法

代码

public interface Addable {
    int add(int x,int y);
}
public class AddableDemo {
    public static void main(String[] args) {
       
        useAddable(new Addable() {
            @Override
            public void add(int x,int y) {
                return x + y;
            }
        });
        
        useAddable((int x,int y) -> {
            return x + y;
        });

    }

    public static void useAddable(Addable a) {
        int sum = a.add(10, 20);
        System.out.println(sum);
    }
}

2.5 lambda省略格式

  • 省略规则
    • 基本格式: (参数) -> {}
  • 参数
    • 没有参数: 小括号不能省略
      • () -> {System.out.println(“黑马程序员”);}
    • 有一个参数: 小括号和数据类型都可以省略
      • (String s) -> {System.out.println(s);}
      • s -> {System.out.println(s);}
    • 多个参数: 数据类型可以省略,参数类型要么都省略要么都留着
      • (int a,int b) -> {return a + b;}
      • (a,b) -> {return a + b;}
  • 语句体{}
    • 如果{} 中只有一条语句,可以省略大括号,分号,return
      • (int a,int b) -> {return a + b;}
      • (a,b) -> a + b

2.6 lambda和内部类区别

所需类型不同

  • 匿名内部类: 可以是接口, 可以是抽象类,可以是普通的类
  • Lambda: 只能是接口,且接口中有一个抽象方法
    • 函数式接口: 只有一个抽象方法的接口被称为函数式接口
    • @FunctionalInterface: 验证一个接口是否为函数式接口
    • 函数式接口可以使用lambda表达式

实现原理不同

  • 匿名内部类:编译之后,产生一个单独的.class字节码文件
  • Lambda表达式:编译之后,没有.class字节码文件。对应的字节码会在运行的时候动态生成(不在硬盘上,直接进入方法区)

2.7 lambda练习过程

  • 先使用匿名内部类格式,再写lambda基本格式。熟练后再按照下面的方式
  • 打开接口源码,照着抽象方法写(主要看参数和返回值)lambda基本格式。熟练后再按照下面的方式
  • 打开接口源码,照着抽象方法,直接写lambda省略格式

2.8 总结

请添加图片描述

3. API

  • API(Application Programming Interface) : 应用程序编程接口
  • 目前理解: 别人提供给我们使用的类和方法

3.1 如何学习

  • 搜索引擎: baidu等
    • 比如: 搜索判断是否以某个字符串开头
  • 查看API帮助文档
    • 各种JDK版本的API官方帮助文档,看不懂就翻译
  • idea中查看源码,翻译文档注释
    • 点两下Shift键 => 在提示框中搜索类名
    • Alt+7 => 显示类的成员
    • Ctrl+F12 => 显示类的成员

翻译插件安装步骤

  1. File => setting
    请添加图片描述

  2. 重启idea
    请添加图片描述

  3. idea右下角设置翻译软件
    请添加图片描述

  4. 进入某个类的源码
    请添加图片描述

3.2 Math

  • Math工具类,提供执行基本数字运算的方法
方法名说明
public static int abs(int a)返回参数的绝对值
public static double ceil(double a)向上取整
public static double floor(double a)向下取整
public static int round(float a)按照四舍五入返回最接近参数的int
public static int max(int a,int b)返回两个int值中的较大值
public static int min(int a,int b)返回两个int值中的较小值
public static double pow (double a,double b)返回a的b次幂的值
public static double random()返回值为double的正值,[0.0,1.0) 左包含,右不包含

3.3 System

  • System工具类,提供和系统相关的方法
方法名说明
public static void exit(int status)终止当前运行的Java虚拟机,非零表示异常终止
public static long currentTimeMillis()返回当前操作系统的时间(以毫秒为单位)
public static Properties getProperties()获取所有属性
public static String getProperty(String key)获取指定名称的属性值
public static String getenv(String name)获取指定环境变量
static arraycopy(源数组,源数组起始索引,目的地数组,目的地数组起始索引,拷贝个数)数组copy
public static double pow (double a,double b)返回a的b次幂的值
public static double random()返回值为double的正值,[0.0,1.0) 左包含,右不包含

3.4 Runtime

  • Runtime:代表程序运行环境
  • Runtime是一个单例类
方法名说明
public static Runtime getRuntime()返回与当前Java应用程序关联的运行时对象
public void exit(int status)终止当前运行的java虚拟机
public native int availableProcessors()获取当前系统能够使用的处理器数
public native long totalMemory()返回Java虚拟机中的内存总量
public native long freeMemory()返回Java虚拟机中的可用内存量
public Process exec(String command)启动某个程序,并返回代表该程序的对象

3.5 BigDecimal (重点)

  • BigDecimal: 用于精确运算
  • 问题: 使用double运算结果不准确
public static void main(String[] args){
    System.out.println(0.1 + 0.2);    
    System.out.println(0.1 - 0.32);    
    System.out.println(1.015 * 100);    
    System.out.println(1.301 / 100);    
}

获取BigDecimal对象

方法名说明
public BigDecimal(double val)禁用参数为double
public BigDecimal(String val)参数为String
public static BigDecimal valueOf(double val)推荐静态方法,类名调用

常用方法

注意: 下列方法会将计算结果返回一个新的对象

方法名说明
public BigDecimal add(另一个BigDecimal对象)加法
public BigDecimal subtract (另一个BigDecimal对象)减法
public BigDecimal divide (另一个BigDecimal对象)除法
public BigDecimal multiply (另一个BigDecimal对象)乘法
public BigDecimal divide (另一个BigDecimal对象)除法
public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式)除法(如果除不尽会报错)参数二: 精确到小数点后几位参数三: 舍入模式向上取整: RoundingMode.UP向下取整: RoundingMode.DOWN四舍五入: RoundingMode.HALF_UP
public double doubleValue()返回double类型结果

练习

  • 需求: double[] arr = {0.1,0.2,0.3}; 求和
public class Demo {
    public static void main(String[] args) {
        double[] arr = {0.1,0.2,0.3};
        // 求和
        // 1.定义求和变量
        BigDecimal sum = BigDecimal.ZERO;
        // 2.遍历数组
        for (int i = 0; i < arr.length; i++) { // i 0 1 2
            // 累加求和
            // 第1轮   0 和 0.1   结果赋值给了sum(0.1)
            // 第2轮   0.1 和 0.2 结果赋值给了sum(0.3)
            // 第3轮   0.3 和 0.3 结果赋值给了sum(0.6)
            sum = sum.add(BigDecimal.valueOf(arr[i]));
        }
        System.out.println(sum);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值