Panda白话 - G1垃圾收集器

are you ready~~
知识点太多,肝一篇长文~,let us go ~~

先来看张图:

在这里插入图片描述

上图可以看到随着java版本的迭代,不断有新的垃圾收集器面世,新的GC Collector也日渐强大~~

JDK 1.3 发布串行Serial GC、ParNew(多线程的Serial)-> JDK 1.4 发布 并行Parallel Scavenge -> JDK 1.5 发布并发CMS -> JDK 1.6 发布Parallel Old ->JDK 1.7 发布G1 -> JDK 9 默认G1,标记CMS过时 - >JDK 10 增强G1->JDK 11 引入Epsilon、ZGC->JDK 12 发布 增强G1,Shenandoah GC ->JDK 13 发布 增强ZGC -> JDK 14 删除CMS,拓展ZCC

先来简单说下jdk已经提供的几种垃圾收集、如下图:

在这里插入图片描述

Young Generation - 年轻代:

  • Serial-串行 :
    • 单线程 - 只有一个GC线程在做GC工作
    • 串行 - STW(stop the world)-暂停所有用户线程
    • 复制算法
  • ParNew - 并行:
    • Serial 的多线程版本 - 多个GC线程并行做GC工作,缩短了GC时间
    • 其它和Serial一毛一样
  • Parallel Scavenge -并行
    • 多线程
    • STW
    • 复制算法
    • 目标是提升吞吐量(吞吐量 = t用户/(t用户 + tGC))
  • G1 - 并行 +并发

Tenured Generation - 老年代:

  • CMS-Concurrent Mark Sweep
    • 并发收集 - 用户线程与GC线程交替工作 - 可能产生浮动垃圾
    • 标记-清除算法 - 会产生内存碎片
  • Serial Old
    • Serial 的老年代版
    • 标记-整理算法
    • STW
  • Parallel Old
    • Parallel Scavange 的老年代版
    • 标记-整理算法
  • G1

note:

并行 - parallelism: 只是说多个GC线程并行进行垃圾收集动作,还是要STW,暂停所有用户线程的,如下图
在这里插入图片描述

  • Parallel 和ParNew 都是并行GC Collector,都会STW

  • Parallel 和ParNew 都是都是标记-整理算法,Parallel 更关注高Throughput-吞吐量,高效利用CPU,也称吞吐量优先收集器
    吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)

  • Parallel Scavenge 提供了两个参数控制吞吐量:

-XX:MaxGCPauseMillis  - GC最大暂停时间(毫秒)、JVM没有指定默认值
-XX:GCTimeRatio =99 - GC时间占比  , 只能取0到100的整数,默认99,即  1/(1+99)  =  1%
  • Parallel Scavenge 还提供了1个参数 - 很牛:
-XX:+UseAdaptiveSizePolicy  - 启动GC自适应的调节策略、jdk8默认启用
-XX:-UseAdaptiveSizePolicy - 关闭GC自适应的调节策略

自适应嘛,顾名思义,JVM自己动态调整来提供最合适的停顿时间或最大的吞吐量,
启动之后,以下参数不用自己配啦,根据运行情况动态调整。

-Xmn: - 年轻代大小、一般为1/4 (-Xmx - 最大堆内存大小)
-XX:NewRatio:2(默认)- 新生代与老年代的比例,即Young = 1/3 (Heap)、Old = 2/3 (Heap)
-XX:SurvivorRatio:8(默认) - 新生代中Eden:Survivor0:Survivor1 = 8:1:1
  • 既然Parallel Scavenge 这么厉害还要ParNew干啥呢?ParNew也很重要,它可以和CMS搭配使用,Parallel Scavenge不可以和CMS搭配使用,因为HotSpot VM 有一个分布式GC框架,Serial、Serial Old、ParNew、CMS都在这个框架内,共享了很多代码,可以任意搭配,“mix-and-match”,Parallel Scavenge 和G1采用了新框架,不兼容原本分布式GC框架。,所以ParNew+CMS 一度非常受欢迎

并发 - concurrency: GC线程可以和用户线程交替获得CPU时间片

  • CMS是G1之前真正实现并发GC的Collector,GC的同时,用户线程也在并发进行,用户无感知的情况下就完成了GC(当然它也有STW的阶段,G!的mixed GC 同CMS类似,后面详细介绍)
    宏观上来看就是这样的、如下图:在这里插入图片描述

  • CMS使用的是Mark-Sweep (标记-清除)算法,会产生很多内存碎片、如下图
    在这里插入图片描述
    7种垃圾收集器详解 - 知识补充请找这位老哥 - 传送门

CMS使老年代垃圾收集器前进了一大步,缺点也很明显,HotSpot VM 团队历时6年,终于在jdk 7 发布时、G1垃圾收集器强势来袭,赋予了取代CMS的使命

G1 - Garbage First 垃圾收集器

G1- Garbage First,见名思议,垃圾优先,先回收垃圾多的region

G1 特性 - 牛在哪里:

  • 可预测的停顿时间模型 - soft real-time (软实时) - 短暂停时间且可控
  • 高吞吐量
  • 并发+并行
  • 引入Region-分区思想 - GC以Region为单位、设计了基于部分内存回收的Young GC和Mixed GC
  • 引入Concurrence Refinement Thread - 并发优化线程

我们都知道java的 一大NB之处是它的自动内存管理,即GC,GC虽然叫Garbage Collection - 垃圾收集,它有两个职能,第一是内存的分配管理JVM-Java Virtual Machine,java虚拟机,是运行在操作系统上的虚拟计算机,只能跟OS打交道,对内存的管理也是先通过OS的系统调用申请一块内存,然后通过不同的GC算法进行管理),第二是垃圾回收,每种垃圾回收策略都和内存分配策略息息相关。

G1之前内存划分 - 分代 - 如下图 -

  • 内存划分为年轻代和老年代
  • 年轻代和老年代内存空间物理连续
  • Permanent - 永久代 在jdk 8 被干掉了
  • 年轻代收集器都采用复制算法,通过s0、s1空间复制实现
    在这里插入图片描述
    G1将内存重新划分,引入了Region(分区)的概念、先上图:

在这里插入图片描述

  • G1将heap划分为2048个大小相等的Region

  • 每个Region逻辑连续,物理不连续

  • GC是以Region为单位进行的

  • Region有5种类型

    • Eden - 伊甸园,新生代的eden区
    • Survivor - 存活区,新生的s0、s1区
    • Old - 老年代
    • Humongous - 巨无霸对象区,简单说一下吧,就是一个对象大小>1/2 eden,那它就是巨大对象,直接放到H区,H区可能占几个连续的Region
    • free - 空闲分区
  • 每个Region类型不是固定的,一个Region被GC释放后就是free分区,下次被分配为Eden、Survivor、Old Region,any type is possible ~

我们逐个来看一下,大牛们是怎么想的~~
Region 类型 - 分区类型在这定义的 - heapRegionType.hpp

  // 0000 0 [ 0] Free
  //
  // 0001 0      Young Mask
  // 0001 0 [ 2] Eden
  // 0001 1 [ 3] Survivor
  //
  // 0010 0      Humongous Mask
  // 0010 0 [ 4] Humongous Starts
  // 0010 1 [ 5] Humongous Continues
  //
  // 01000 [ 8] Old
  typedef enum {
    FreeTag       = 0, //空闲分区

    YoungMask     = 2, //年轻代
    EdenTag       = YoungMask, //年轻代中Eden-伊甸园 区
    SurvTag       = YoungMask + 1,//年轻代中Survivor - 存活 区

    HumMask       = 4, //巨无霸对象、占一片连续Region
    HumStartsTag  = HumMask, //巨无霸对象起始位置
    HumContTag    = HumMask + 1, //巨无霸对象连续Region

    OldTag        = 8 //老年代
  } Tag;
  

还提供了一些判断方法:

public:
  // Queries

  bool is_free() const { return get() == FreeTag; }

  bool is_young()    const { return (get() & YoungMask) != 0; }
  bool is_eden()     const { return get() == EdenTag;  }
  bool is_survivor() const { return get() == SurvTag;  }

  bool is_humongous()           const { return (get() & HumMask) != 0; }
  bool is_starts_humongous()    const { return get() == HumStartsTag;  }
  bool is_continues_humongous() const { return get() == HumContTag;    }

  bool is_old() const { return get() == OldTag; }

Region大小上限、下限 - heapRegionBounds.hpp

HR(Heap Region)的大小影响分配和回收的效率,HR太大回收时间长,HR太小Eden频繁占满、频繁进行分配,开销大,也不合理,所以JVM设置了上限和下限,源码如下:
panda保留了关键注释,进行了蹩脚翻译~ ,毕竟咱也六级选手呢,<{=....(嘎嘎~)

private:
  // Minimum region size; we won't go lower than that.
  //最小堆大小,我们不会再小了~
  static const size_t MIN_REGION_SIZE = 1024 * 1024; //Region最小1MB

  // reason for having an upper bound. We don't want regions to get too
  // large, otherwise cleanup's effectiveness would decrease as there
  //设置上限的原因是,我们不想把Region设置太大,因为回收效率会因此降低
  static const size_t MAX_REGION_SIZE = 32 * 1024 * 1024;// Region 最大 32MB

  // The automatic region size calculation will try to have around this
  //自动region大小计算会调整这个值 ,就是可变、不固定
  static const size_t TARGET_REGION_NUMBER = 2048; //默认2048个Region

Region大小设置 - HEAPREGION.CPP
JVM 给了Region大小范围,我们可以通过-XX:G1HeapRegionSize参数来设置每个Region的大小,如果你没设置怎么办呢,JVM根据实际情况动态决定,关键源码如下:

void HeapRegion::setup_heap_region_size(size_t initial_heap_size, size_t max_heap_size) {
  uintx region_size = G1HeapRegionSize;
  if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
    size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;
    region_size = MAX2(average_heap_size / HeapRegionBounds::target_number(),
                       (uintx) HeapRegionBounds::min_size());
  }

  int region_size_log = log2_long((jlong) region_size);
  // Recalculate the region size to make sure it's a power of
  // 2. This means that region_size is the largest power of 2 that's
  // <= what we've calculated so far.
  region_size = ((uintx)1 << region_size_log);

  // Now make sure that we don't go over or under our limits.
  if (region_size < HeapRegionBounds::min_size()) {
    region_size = HeapRegionBounds::min_size();
  } else if (region_size > HeapRegionBounds::max_size()) {
    region_size = HeapRegionBounds::max_size();
  }

  // And recalculate the log.
  region_size_log = log2_long((jlong) region_size);
}

不要慌,我们逐步来看,
类名 - HeapRegion
俩参数 :

  • initial_heap_size - 初始堆大小,就是我们熟悉的Xms 设置的最小堆内存 ,我们假设给个之值2048 (2MB)
  • max_heap_size - 最大堆大小,是Xmx 设置的值,我们假设给个之值6144(大概6MB)

方法体:

  1. uintx region_size = G1HeapRegionSize; 将我们通过参数-XX:G1HeapRegionSize设置的值作为HR size
  2. 在这里插入图片描述
 if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
    size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;
    region_size = MAX2(average_heap_size / HeapRegionBounds::target_number(),
                       (uintx) HeapRegionBounds::min_size());  
  }

这步是重点,标星,嘎嘎~~,我们再来拆解一下

  • if (FLAG_IS_DEFAULT(G1HeapRegionSize))是否是默认标志,就是没设置嘛
  • size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;//取我们传的这俩参数的平均值,就是说你不是设置了堆内存范围吗【2048,6144】(panda
    给的示例值啊,不是jvm的默认值,嘎嘎~),那我就当你设置了(2048+6144)/ 2 = 4096(4MB)
    这么大,既然你说随便,那我给你个平均值呗,无功无过的,嘎嘎~
  • region_size = MAX2(average_heap_size / HeapRegionBounds::target_number(), (uintx) HeapRegionBounds::min_size()); }
    MAX 就是要取最大值嘛,取谁和谁的最大值呢,
    (uintx) HeapRegionBounds::min_size()这个上面说了,jvm给的HR界限里的最小值1MB,
    average_heap_size / HeapRegionBounds::target_number()这个就是刚才算完堆大小用平均值 average_heap_size除以Region目标个数2048就是每个Region的大小啦,
    计算的大小与最小1MB取最大值,因为不能低于1MB呀~
  • 这就算完啦~~~
  1. 后面几步就是判断是否是2的次幂、是否在界限范围内

先理解到这个维度吧,逐步递进:

G1的内存分配策略就让人哇塞~~,大内存就是任性啊~,

G1 就是把堆内存给切豆腐了,不同的Region不同的策略,分而治之,一块一块的管理,

G1把内存分配策略搞介个样子,是出于GC效率考虑的,其它收集器进行GC都要整堆扫描,硬件发展这么迅速,内存已经很大了,JVM可以申请的内存也很大了,还整堆扫描,STW的时间太长了,用户忍不了啊,所以就有问题解决问题啊,切豆腐~
分区管理,每次GC部分收集(当然只有老年代是部分收集,年轻代还是all Young Region
收集的,嘎嘎~~),提高收集效率,响应用户也快,内存管理也高效,double win ~~

总体还是分代思想,分为新生代和老年代,

GC分为Young GC 和 Mixed GC ,

也是以Serial Old 的Full GC 做担保机制

行话~

先来储备几个行话~~ 行走江湖不会说几句黑化怎么行~~嘎嘎~

STW - stop the world :世界静止了。。JVM停止一切用户线程

safepoint - 安全点: JVM并不能为所欲为地STW,设计安全点,当用户线程到达安全点时,主动停止

Mutator : Java应用线程,即用户线程

RSet - Remember Set : 记忆集,记录代际间引用关系,不用头大,先混个脸熟吧,嘎嘎~
Panda 白话 - G1垃圾收集器 之 RSet(Remembed Set)源码解读 - 传送门-灰常通俗白话

Refine - 优化 : 处理RSet的优化线程
Panda白话 - G1垃圾收集器 之 Refine线程 - 传送门

Evac-Evacuation - 转移:将存活对象复制到Survivor Region或Old Region过程

Reclaim - 回收 : Region中存活对象已经完成Evac,分区可以释放了

GC Root: GC的根节点,这不用说了,GC算法可达性分析法的可达就是GC Root可达

Root Set: 根集合

FGC - Fu’ll GC : 整堆回收,串行,STW,G1用Serial Old做担保机制做Full GC

Remark - 再标记

TLAB - Thread Local Allocation Buffer:线程本地分配缓冲区

我们来认真看一下TLAB,见名思议,每个线程一个本地缓冲区,这个解释听君一席话如听一席话,嘎嘎~
情况是这样的:
JVM中堆内存是线程共享的(这都不了解的话你就完犊了~~)
从堆内存分配对象需锁整堆,为不受其它线程中断和影响
那这肯定不行啊,创建个对象堆就被锁住了,创建个对象堆就被锁住了,其它线程还怎么干活了。。
所以JVM团队就设计了TLAB,
每个线程分配一块内存(Eden区的内存),每个线程创建的对象都在自己的内存分配,且不用上锁
所有TLAB内存对所有线程都是可见的,因为堆是共享的嘛,划分几块给各个线程,那它还是共享的啊,线程共享TLAB还怎么各管各的,还无锁分配对象呢?
每个线程有个数据结构,存放TLAB可用内存的start和end地址,新对象只能在这段区间分配,就做到了无锁分配,快速分配、看图说话:
T1线程用完两块TLAB,分配第三块TLAB了,第三块用完一半了,还是top 到end那么点空间可分配
T2和T4线程同理
一个Region可以有多个TLAB,一个TLAB不能占多个Region
可以通过参数-XX:TLABWasteTargetPercent: 1 设置TLAB占Eden空间百分比,默认1%
在这里插入图片描述
堆分配TLAB空间时还是要上锁的(G1使用CAS并行分配),同理分配对象,堆说我管你是谁呢,我是共享的,从我这分配空间就得上锁,得保证并发情况数据一致性啊

G1 - 参数设置 :

-XX:+UseG1GC - 开启G1垃圾收集器 、JDK9之后默认开启

-XX:G1HeapRegionSize   -  指定每个region的大小 ,2的n次幂,1MB - 32MB  (1MB、2MB、4MB、8MB、16MB、32MB)

-XX:G1NewSizePercent - 新生代占总堆最小百分比、默认值5%

-XX:G1MaxNewSizePercent - 新生代占总堆最大百分比、默认值60%

-XX:MaxGCPauseMillis - GC暂停时间,默认200ms
-XX:GCTimeRatio - GC与应用耗费时间比,G1默认是9,即GC占10%,CMS默认是99,即GC耗时占1%,

-XX:NewRatio - 年轻代占比,默认值 2,即1/3 年轻代,2/3 老年代

-XX:NewRatio 参数 和 -XX:G1NewSizePercent、-XX:G1MaxNewSizePercent 两个参数我们来说下吧,都是设置年轻代占比,那搞这么多干啥,当然各有各的用啦,

  • -XX:NewRatio 是固定了年轻代大小,值为2,则年轻代占总堆的1/3
  • -XX:G1NewSizePercent、-XX:G1MaxNewSizePercent 是不固定年轻代大小,指定了范围,年轻代在总堆大小的5% 到 60% 动态调整
  • 我们可以通过参数-XX:MaxGCPauseMillis设置希望GC停顿最大时间,JVM会根据停顿预测模型来动态调整新生代大小,如果只设置了-XX:NewRatio就会将动态调整大小false,可能就不能满足停顿预期时间了
  • 如何同时设置了-XX:NewRatio 参数 和 -XX:G1NewSizePercent、-XX:G1MaxNewSizePercent 两个参数,JVM则自动忽略-XX:NewRatio ,源码如下:
  if (FLAG_IS_CMDLINE(NewRatio)) {
    if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) {
      warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio");
    } else {
      _sizer_kind = SizerNewRatio;
      _adaptive_size = false;
      return;
    }
  }

Young GC - 年轻代垃圾收集

  • 触发时机:

    • 新的对象创建会放入Eden区
    • Eden区满、G1会根据停顿预测模型-计算当前Eden区GC大概耗时多久
    • 如果回收时间远 < -XX:MaxGCPauseMills,则分配空闲分区加入Eden 区存放新创建的o,
    • 如果回收时间接近-XX:MaxGCPauseMills,则触发一次Young GC
    • 年轻代初始占总堆5%,随着空闲分区加入而增加,最多不超过60%
  • Young GC 会回收all新生代分区 - Eden区和Survivor 区

  • Young GC 会STW(stop the world),暂停所有用户线程

  • GC后重新调整新生代Region数目,每次GC回收Region数目不固定

  • 回收过程:

    • phase one - 扫描根
    • phase two - 更新RSet
    • phase three - 处理RSet
    • phase four - 复制对象
    • phase five - 处理引用
  • 图解:

画图太慢了,借用大佬几张图这可能是最清晰易懂的 G1 GC 资料

-在这里插入图片描述

  • 初始状态: D -> B 、 C -> F 、 E -> C

    • 年轻代 - Region A - 存放了对象 : A、 B、C
    • 年轻代 - Region B - 存放了对象 :E
    • 年轻代 - Region C - 存放了对象 F
    • 老年代 - Region D - 存放了对象 :D
  • 可以看到E->C, C -> F ,E、C、F都在新生代分区中,RSet不会记录他们的引用关系

  • D -> B ,老年代引用新生代,所以在B所在的Region A的RSet中会记录这个代间引用关系

  • 第一步:选择CSet(收集集合)- YGC收集所有新生代分区,根据停顿预测模型选择最大新生代分区数

  • 第二步: GCRoot Scan(根集合扫描)

    • 从GCRoot出发能直达的对象都是存活对象
    • 存活对象复制到新的Survivor分区
    • 存活对象的field入栈,留着后面深度递归用 panda.kongfu = new Kongfu(),konfu属性就是panda对象的field,引用了对象Kongfu,通过kongfu存放的值可以找到Kongfu对象所在堆内存地址
      在这里插入图片描述
  • 示例图分析:

    • 根可达的对象有A、D、E,D对象在老年代,不在YGC范围,所以将A、E存活对象复制到新的空闲Survivor分区Region M
    • E->C ->F ,所以E的field c,C的field f 入栈
    • 对象A、E复制到了新Region M,原Region中的对象A、E的对象头有点变化
      • 对象头里面的指针指向新的对象(引用对象可以根据指针找到新对象)
      • 对象头中锁标志位会被设置为 11 - 即可以GC
  • 步骤三 : RSet Scan(扫描RSet):

    • 更新RSet,即上面讲的Refine线程处理DCQS中DCQ记录的引用关系更新RSet,使RSet为最新完整信息
    • 将RSet 作为GC Root进行根扫描,同步骤二

    在这里插入图片描述

    • 示例图分析: Region A 中RSet记录了对象D到对象B的引用,B为直接可达对象复制到Region M,因为D在老年代,不处理,所以D的field 不入栈
  • 步骤四: Evacuation(复制):

    • 将上面步骤放入栈中的field(存放的是引用对象的地址),将引用对象复制到Region M
      在这里插入图片描述
    • 示例图解:
    • 栈中c、f指向的对象C、F复制到Region M
    • 原对象C、F的对象头修改
  • 步骤五:重构RSet、释放空间

    • 更新RSet (Rset 记录引用对象地址和卡表信息,对象都重新分配了,它的地址,卡表肯定变了) Panda 白话 - G1垃圾收集器 之 RSet(Remembed Set)源码解读
    • 清理卡表 - 释放空间
      在这里插入图片描述
    • 示例图解:
      • CSet中Region A、B、D被回收了
      • 回收后的Region作为Free Region ,下次被分配为哪种Region使用不确定

Mixed GC - 混合垃圾收集

未完待续。。。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立件、传感、光电件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机人、激光、工控、无人机)、食品药品、医疗械、农业等。邮箱:market@qyresearch.com
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装 8-2 对象包装 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值