JavaSE进阶

Posted by WZhong on Sunday, October 18, 2020

TOC

Ⅰ. 反射

  1. 对反射的理解

    • Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性
    • 这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制
  2. 反射的示例

    public class Robot {
    
        private String name;
    
        static {
            System.out.println("this is in static block");
        }
    
        public void sayHi(String s) {
            System.out.println(s + " - " + name);
        }
    
        private String throwHello(String tag) {
            return "hello " + tag;
        }
    
    }
    
    public static void main(String[] args) throws
            ClassNotFoundException,
            NoSuchMethodException,
            IllegalAccessException,
            InstantiationException, InvocationTargetException, NoSuchFieldException {
        Class robotClass = Class.forName("com.wnzhong.bjavaseadvance.areflect.Robot");
        System.out.println("robotClass.getName() - " + robotClass.getName());
    
        Method throwHello = robotClass.getDeclaredMethod("throwHello", String.class);
        throwHello.setAccessible(true);
    
        Robot robot = (Robot) robotClass.newInstance();
    
        Object obj = throwHello.invoke(robot, "bob");
        System.out.println(obj);
    
        Method sayHi = robotClass.getMethod("sayHi", String.class);
        sayHi.invoke(robot, "welcome");
    
        Field name = robotClass.getDeclaredField("name");
        name.setAccessible(true);
        name.set(robot, "alice");
        sayHi.invoke(robot, "welcome");
    }
    
  3. 反射的应用

    • JDBC 的数据库连接

      • 通过 Class.forName() 加载数据库的驱动程序
      • 通过 DriverManager 类进行数据库的连接,连接时要输入数据库的连接地址、用户名、密码
      • 通过 Connection 接口接收连接
    • Spring 框架的通过 xml 配置模式装载 bean

      • 将程序内所有 xml 或 properties 配置文件载入内存
      • 解析配置文件内容,得到对应实体类的字节码字符串及相关属性信息
      • 使用反射机制,根据字符串获取某个类的 Class 实例
      • 动态配置实例的属性

Ⅱ. 动态代理

  1. 写一个 ArrayList 的动态代理类

  2. 动态代理 和 静态代理的区别及使用场景

    • 静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类

    • 静态代理事先知道要代理的是什么,而动态代理不知道要代理什么,只有运行时才知道

    • 动态代理是实现 JDK 里的 InvocationHandler 接口的 invoke 方法,但注意的是代理的是接口,也就是业务类必须要实现接口,通过 Proxy 里的 newProxyInstance 得到代理对象

    • 还有一种动态代理 CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的

    • AOP 编程就是基于动态代理实现的,比如著名的 Spring 框架、 Hibernate 框架等等都是动态代理的使用例子。

Ⅲ. 设计模式

  1. 你知道哪些设计模式(23种)

    • 创建型

      • 工厂方法
      • 抽象工厂
      • 单例
      • 建造者
      • 原型
    • 结构型

      • 适配器
      • 装饰器
      • 代理
      • 外观
      • 桥接
      • 组合
      • 享元
    • 行为型

      • 策略
      • 模版方法
      • 观察者
      • 迭代
      • 责任链
      • 命令
      • 备忘录
      • 状态
      • 访问者
      • 中介
      • 解释器
  2. 单例模式

  3. 工厂模式

  4. 建造者模式

  5. 适配器模式

  6. 装饰模式

  7. 策略模式

  8. 观察者模式

Ⅳ. 回收机制

  1. JVM 垃圾回收机制和常见算法

  2. JVM 的内存结构和内存分配

  3. Java 中的引用类型有哪些

  4. heap 和 stack 的区别

  5. 解释内存中的 栈、堆、方法区 的用法

Ⅴ. 类加载器

  1. Java 的类加载器的种类有哪些

  2. 类什么时候被初始化

  3. ClassLoader 的双亲委托机制

  4. 描述一下 JVM 加载 class

  5. 获得一个类对象有哪些方式

Ⅵ. JVM

  1. 既然有了 GC 机制,为什么还会有内存泄漏情况

Ⅶ. GC

  1. Java 为什么会有 GC 机制

  2. 哪些内存需要回收

  3. 什么时候回收垃圾

Ⅷ. Java8 新特性

  1. lambda 表达式

    • 实现 Runnable
    • 进行事件处理
    • 对列表进行迭代
    • 函数式接口 Predicate
    • map
    • reduce
    • filter
    • 对列表每个元素应用函数
    • distinct
    • 最大值、最小值、总和、平均值
  2. lambda 表达式要点

    • lambda 表达式的使用位置

      • 预定义使用了 @FunctionalInterface 注释的函数式接口,自带一个抽象函数的方法。这些称为 lambda 表达式的目标类型,可以用作返回类型,或 lambda 目标代码的参数。
      • 例如,若一个方法接收 Runnable、 Comparable 或者 Callable 接口,都有单个抽象方法,可以传入 lambda 表达式。
      • 类似的,如果一个方法接受声明于 java.util.function 包内的接口,例如 Predicate、 Function、 Consumer 或 Supplier,那么可以向其传 lambda 表达式。
    • lambda 和方法引用

      • lambda 表达式内可以使用方法引用,仅当该方法不修改 lambda 表达式提供的参数。
      list.forEach(n -> System.out.println(n));
      list.forEach(System.out::println);
      
    • lambda 内部引用资源

      • lambda 内部可以使用静态、非静态和局部变量,这称为 lambda 内的变量捕获。
    • lambda 表达式也称闭包

      • Lambda 表达式在 Java 中又称为闭包或匿名函数
    • lambda 表达式的编译方式

      • Lambda 方法在编译器内部被翻译成私有方法,并派发 invokedynamic 字节码指令来进行调用。
      • 可使用 JDK中的 javap 工具来反编译 class 文件。使用 javap -p 或 javap -c -v 命令来看一看 lambda 表达式生成的字节码
    • lambda 表达式的限制

      • 只能引用 final 或 final 局部变量,这就是说不能在 lambda 内部修改定义在域外的变量
      • 只是访问它而不作修改是可以的
  3. Optional 类

    • 描述:

      • 这是一个可以为 null 的容器对象。如果值存在则 isPresent()方法会返回 true,调用 get()方法会返回该对象
    • 方法:

      • Optional.of()
      • Optional.ofNullable()
      • Optional.isPresent()
      • Optional.get()
      • Optional.ifPresent()
      • Optional.orElse()
      • Optional.orElseGet()
      • Optional.orElseThrow()
      • Optional.map()
      • Optional.flatMap()
      • Optional.filter()

Ⅸ. 内存溢出

  1. 常见原因

    • 内存中加载的数据量过于庞大,如一次从数据库取出过多数据
    • 集合类中有对对象的引用,使用完后未清空,使得 JVM 不能回收
    • 代码中存在死循环,或循环产生过多重复的对象实体
    • 启动参数内存值设定过小
  2. 如何解决

    • 修改 JVM 启动参数,直接增加内存(-Xms,-Xmx 参数要添加)
    • 检查错误日志,查看 OutOfMemory 错误前是否有其他异常或错误
    • 对代码进行走查和分析,找出可能发生内存溢出的位置。重点排查如下:
      • 检查数据库查询中是否有一次获取全部数据的查询:十万条记录就可能引起内存溢出;尽量采用分页查询方式
      • 检查代码中是否有死循环或递归调用
      • 检查是否有大循环重复产生新对象实体
      • 检查 List、Map 等集合对象是否有使用完后未清除的问题。List、Map 等集合对象会始终存有对对象的引用,使得这些对象不能被 GC 回收
    • 使用内存查看工具动态查看内存使用情况

「真诚赞赏,手留余香」

WZhong

真诚赞赏,手留余香

使用微信扫描二维码完成支付