Java的特点(面向对象、平台无关、编译解释并存、自动垃圾回收、类加载机制、丰富的类库)

1. Java是一种面向对象的语言,具有封装、继承、多态特性。

  1. 封装:保护成员属性,隐藏方法细节,不让外部类直接访问和修改而是提供GET/SET方法。
  2. 继承:实现代码重用,多个类存在重复属性和方法时,抽象出一个父类,然后子类使用extend继承父类来拥有父类的属性和方法。
  3. 多态:一个引用类型在不同情况下呈现不同状态,可以理解为指向父类的引用来调用不同子类的方法。

2. Java有平台无关性,可以一次编译,到处运行。Java程序从源代码到运行有三个阶段,编码–>编译–>运行–>调试。

  1. Java第一次编译后,形成.class的字节码文件,.class文件就是可以到处运行的文件。
  2. 因为有JVM的存在,不同平台上的JVM将.class解释为目标机器代码。

3. Java是编译执行和解释执行并存的。

  1. 编译执行:源代码通过Javac先编译成.class字节码,然后JVM虚拟机解释器将字节码转换为机器码。(编译时一次性翻译,一旦程序被编译,不再需要源代码。静态语言通过编译执行,如C、Java)
  2. 解释执行:JIT编译器在运行时将热点代码编译成机器码。(在每次程序运行时都需要解释器和源代码。脚本语言采用解释执行,如JS、Python)

4. Java提供了垃圾收集器回收分配内存,程序员不需要自己操心内存分配和回收。

  1. 判断对象是否可以被回收
    判断一个对象已经死亡需要两次标记,第一次标记是通过引用计数/可达性分析算法后,判断出对象是可回收的,如果对象没有覆盖finalize()方法,则直接判定死亡。如果对象需要执行finalize()方法,则将对象加入一个队列中,垃圾收集器执行finalize()方法,如果对象在执行方法后有了引用,则不会标记为死亡。

    1. 引用计数算法:堆中每个对象都有一个引用计数,一个对象被创建时计数为1,当这个对象赋给其他对象时,计数器+1,当对象的引用被设置为其他值或者超过了声明周期时,计数器-1,当计数器为0时,就可以被收集,当被收集后,它引用的任何对象计数器-1。(无法检测循环引用)
    2. 可达性分析算法:以GC ROOT节点开始,寻找对应的引用节点,找到节点后,继续寻找这个节点的引用节点,当所有节点寻找完毕后,剩余的节点则被认为时没有被应用到的节点,即无用节点,可以被回收。
  2. Java中引用类型

    1. 强引用:常用的普通对象的引用,当JVM内存不足时会抛出OutOfMemoryError错误使程序停止,也不会去回收强引用的对象。被赋值为null后可以被垃圾收集器回收。
    2. 软引用:通过SoftReference类实现,当JVM内存不足时,才会去回收软引用的对象,以防止出现OutOfMemoryError错误,可以调用ReferenceQueue的poll()方法来检查指定对象是否被回收,软引用可以用于内存不足的缓存中。
    3. 弱引用:通过WeakReference类实现,当垃圾收集器发现了弱引用的对象,不管当前内存空间是否足够,都会回收对象,因为垃圾回收器是一个优先级很低的线程,因此弱引用可能会存活很长一段时间,弱引用被回收时,会把弱引用假如到与之关联的引用队列ReferenceQueue中。
    4. 虚引用:通过PhantomReference类实现,我们无法通过虚引用访问对象,垃圾收集器随时可以回收它。当垃圾回收器准备回收一个对象时,如 果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。可以通过判断是否加入了引用对象来判断对象是否被回收。
  3. 垃圾收集算法

    1. 标记-清除算法:标记-清除算法采用可达性分析算法从GC Roots根节点进行扫描,对存活对象进行标记,扫描完毕后,再扫描整个空间中未被标记的对象,进行回收。如图所示,标记清理不需要移动对象,只需要对不存活的对象进行处理,再存活对象较多的情况下,比较高效,但是会造成内存琐碎的现象。
      在这里插入图片描述
    2. 复制算法:复制算法解决了内存琐碎的问题,它开始把内存分成一个对象块和空白块。对象面用于存储对象,当对象面满了之后,采用可达性分析算法从GC Roots根节点进行扫描,并将存活的对象复制到空闲块中,然后把对象块清理掉。
      在这里插入图片描述
    3. 标记-整理算法:标记整理算法解决了内存琐碎的问题。解决采用标记清除算法一样的方式进行标记,但是在清除时,在回收不存活的对象占用的空间后,会将所有存活的对象往左端空闲空间移动,并更新对应指针。
      在这里插入图片描述
    4. 分代收集算法:当前大部分JVM垃圾收集器采用的算法,它根据对象存活周期划分为若干个不同的区域。一般分为老年代、新生代和永久代。老年代特点是每次垃圾收集时只有少量对象被回收,所以适合采用标记整理算法新生代特点是每次垃圾回收时都有大量的对象需要被回收,所以适合采用复制算法,每次只需要复制少量存活对象。所以可以根据不同代采用不同收集算法,提高了垃圾回收效率。
  4. 垃圾收集器

    1. 新生代收集器:串行(Serial)、ParNew、并行(Parallel Scavenge)
    2. 老年代收集器:CMS、Serial Old、Parallel Old
    3. 整堆收集器:G1
      G1收集器:工作范围是整个Java堆。并行与并发的方式 收集。收集后不会产生内存碎片。它在后台唯一了一个优先列表,在指定时间内优先收集价值最大的Region(G1收集器将内存划分为许多个Region,新生代、老年代都许多个Region组成的集合)。回收对象过程:第一步先直接标记GC Roots能直接到的对象,第二部使用可达性分析,找出存活对象,此过程时间比较长,但是可以并发标记。第三步将并发标记期间对象的变化记录在日志中,然后将日志的变化整合到集合中。最后对各个Region回收价值和成本进行排序,根据用户期望GC停顿时间来指定回收计划。
  5. GC什么时候触发

    1. young GC:当新生代中的eden区内存满时会触发young GC,GC过后新生代一部分存活对象可能会升级到老年代中,导致老年代占用量上升。
    2. full GC:每次触发young GC时会判断GC后升级到老年代的对象占用内存是否大于老年代剩余的内存,如果大于,那么就不触发young GC转而触发full GC。如果老年代或者持久代被写满时也会触发full GC。调用System.gc()方法时也会触发full GC(一般GC由虚拟机决定,不会手动调用,即使调用了也不一定会触发)。
  6. JVM内存模型

    1. 程序计数器:一块较小的内存空间,可以看作是当前线程所执行的行号指示器。字节码解释器通过改变计数器的值来选取下一条需要执行的字节码指令,如分支、循环、跳转、异常处理等。且每个线程都必须有一个独立的程序计数器,各个线程间计数器互不影响,独立存储。程序计数器是线程私有的。
    2. 虚拟机栈:Java方法执行的内存模型,每次方法调用的数据通过栈传递。虚拟机栈由一个个的栈帧组成,每个栈帧包括局部变量表、操作数栈、动态链接、方法出口信息。局部变量表存放方法内的局部变量。操作数栈:用来执行操作。动态链接:用来处理多态的引用。返回地址:用来处理返回值。虚拟机栈是线程私有的。
    3. 本地方法栈:与虚拟机栈类似,但是它是用于处理native本地方法。本地方法栈式线程私有的。
    4. 堆:JVM管理内存中最大的块,也是垃圾收集器管理的主要区域。用于存放对象的实例。以分代垃圾回收算法来划分可以将堆分为新生代和老年代。新生代细致划分为Eden空间、From Survivor、To Survivor。老年代划分为tentired。堆是线程共享的。
    5. 方法区/本地内存的元空间:用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译后的代码等数据。方法区也称为永久代。JDK1.8后使用直接内存的元空间代替了永久代。因为存储在直接内存中,内存大小可以按照需求动态调整。-XX:MetaspaceSize 。
    6. 运行时常量池:用于 存放class文件中的字面量(文本字符串、被final修饰的常量、基本数据类型值等)和符号引用(字段、方法描述符)。JDK1.7之后JVM将常量池从方法区中移除,放入堆中。

5.Java类加载的双亲委派机制

  1. 类加载过程:加载–>验证–>准备–>解析–>初始化
    1. 加载:第一步通过全类名获取定义此类的二进制字节流。第二步将字节流所代表的静态存储结构转换为方法区的数据结构。第二部在内存中生成一个代表该类的Class对象,作为方法区这些数据访问的入口。加载阶段需要用到类加载器。
    2. 验证:校验一下.class文件是否正确,比如文件格式、语义方面、符号方面等。
    3. 准备:主要为类变量分配内存并设置初始值(数据类型的默认值而不是被赋与的默认值)。类变量主要是在方法区中操作。其中类变量会分配内存,而实例变量不会,实例变量随着对象实例化分配到堆内存中。
    4. 解析:将常量池中符号引用转化为直接引用。主要正对类、接口、字段、方法、方法类型等的引用。
    5. 初始化:主要为类的静态变量赋值,可以通过类变量指定初始值或者静态代码块指定初始值。(类的初始化触发条件:new一个类/调用类的静态变量或方法/反射/初始化类的子类)。
  2. 类加载器:Java有三个自带类加载器
    1. BootStrap ClassLoader:最顶层加载器,主要加载核心类库。
    2. Extention ClassLoader:扩展的类加载器,加载扩展包的类库。
    3. App classLoader:加载当前应用的根目录下所有类。
    4. 自定义类加载器,继承ClassLoader。
  3. 双亲委派原则
    1. 概念:当一个类收到类加载任务时,会先交给父类加载器执行,所以最后都会让顶层类加载器,也就是BootStrap ClassLoader来加载。父类处理不了的再让子类进行处理。
    2. 好处:可以避免重复加载,当父类已经加载后,子类就不需要再次加载。可以避免用户随意定义加载器加载核心api带来的安全问题。
      java.lang.ClassLoader 的 loadClass() 中的类加载器代码:
private final ClassLoader parent; 
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先,检查请求的类是否已经被加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {//父加载器不为空,调用父加载器loadClass()方法处理
                        c = parent.loadClass(name, false);
                    } else {//父加载器为空,使用启动类加载器 BootstrapClassLoader 加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                   //抛出异常说明父类加载器无法完成加载请求
                }

                if (c == null) {
                    long t1 = System.nanoTime();
                    //自己尝试加载
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

6.Java丰富的类库(集合、并发等)

HashMap源码解析:https://blog.csdn.net/tc979907461/article/details/105371196

LinkedList源码解析:https://blog.csdn.net/tc979907461/article/details/105339742

ArrayList源码解析:https://blog.csdn.net/tc979907461/article/details/105322599

多线程学习总结:https://blog.csdn.net/tc979907461/article/details/105188940

原创文章 49 获赞 55 访问量 8390

猜你喜欢

转载自blog.csdn.net/tc979907461/article/details/105796769