分析设备模型、设备模型与驱动关联的过程

  本文的大多数内容参考了:对于网络上设备与驱动关联的全过程分析(I2C方式)一文。在此特别感谢这位作者前辈的无私奉献。 本人只是添加了一些个人理解和补充。

  在Linux操纵系统中,驱动程序的加载分为两种:内核启动时自动加载和用户手动加载;硬件设备也可以采用两种方式添加到系统中:在系统启动前及系统运行时的热插拨。下面,我们以arm体系结构下的at91处理器中的I2C控制器为例,先容一下硬件设备及相关的驱动程序是如何绑定及松绑的。

分析设备模型、设备模型与驱动关联的过程


  1. 平台驱动注册过程

  具体的目录如下:

   关于设备模型、设备与驱动关联的全过程分析。.. 电力模型. 1

  1.1 at91_i2c_init()函数... 1

  1.2 platform_driver_register()函数... 2

  1.3 driver_register()函数... 4

  1.4 bus_add_driver()函数... 5

  1.5 dd.c文件driver_attach()函数... 7

   1.1 at91_i2c_init()函数

  在文件drivers/i2c/busses/i2c-at91.c中,定义了结构体struct platform_driver并进行了初始化,通过使用module_init()宏进行声明,当模块被加载到内核时会调用 at91_i2c_init()函数。在此函数中,调用了platform_driver_register()函数来完成注册。

  static struct platform_driver at91_i2c_driver = {

  .probe= at91_i2c_probe,

  .remove = __devexit_p(at91_i2c_remove),

  .suspend= at91_i2c_suspend,

  .resume= at91_i2c_resume,

  .driver= {

  .name

  = "at91_i2c",

  .owner

  = THIS_MODULE,

  },

  };

  static int __init at91_i2c_init(void)

  {

  return platform_driver_register(&at91_i2c_driver);

  }

   1.2 platform_driver_register()函数

  在文件drivers/base/platform.c中,实现并导出了platform_driver_register()函数,以便使其他模块中的函数可以调用此函数。它在完成简单的包装后,调用了driver_register()函数,完成了从平台实现到Linux内核实现的过渡。

  int platform_driver_register(struct platform_driver *drv) 

  { 

  /*设置成platform_bus_type这个很重要,由于driver和device是通过bus联系在一起的,具体在本例中是通过 platform_bus_type中注册的回调例程和属性来是实现的, driver与device的匹配就是通过 platform_bus_type注册的回到例程platform_match ()来完成的。*/

  drv->driver.bus = &platform_bus_type; 

  //在really_probe函数中,回调了platform_drv_probe函数

  if (drv->probe) 

  drv->driver.probe = platform_drv_probe; 

  if (drv->remove) 

  drv->driver.remove = platform_drv_remove; 

模型公司  if (drv->shutdown) 

  drv->driver.shutdown = platform_drv_shutdown; 

  if (drv->suspend) 

  drv->driver.suspend = platform_drv_suspend; 

  if (drv->resume) 

  drv->driver.resume = platform_drv_resume; 

  return driver_register(&drv->driver); 

  } 

   EXPORT_SYMBOL_GPL(platform_driver_register); 

  在platform_driver_register()函数中,对总线附值使用了如下语句,给总线类型和相关操纵函数赋值。drv->driver.bus = &platform_bus_type; 

  struct bus_type platform_bus_type = {

  .name = "platform",

  .dev_attrs = platform_dev_attrs,

  .match =  platform_match,

  .uevent = platform_uevent,

  .suspend = platform_suspend,

  .suspend_late = platform_suspend_late,

  .resume_early = platform_resume_early,

  .resume = platform_resume,

  };

   EXPORT_SYMBOL_GPL(platform_bus_type);

  总线bus是联系driver和device的中间关键。Device通过所属的bus找到driver.

  struct bus_type {

  const char * name;

  struct subsystem subsys;

  struct kset drivers; // drivers-〉list链表包含了所有注册到该bus的driver.

  struct kset devices; // devices ->list链表包含了所有注册到该bus的devices.

  struct klist klist_devices; //

  struct klist klist_drivers;

  struct blocking_notifier_head bus_notifier;

  struct bus_attribute * bus_attrs;

  struct device_attribute * dev_attrs;

  struct driver_attribute * drv_attrs;

  int (*match)(struct device * dev, struct device_driver * drv);

  int (*uevent)(struct device *dev, char **envp,

  int num_envp, char *buffer, int buff 锅炉模型er_size);

  int (*probe)(struct device * dev);

  int (*remove)(struct device * dev);

  void (*shutdown)(struct device * dev);

  int (*suspend)(struct device * dev, pm_message_t state);

  int (*suspend_late)(struct device * dev, pm_message_t state);

  int (*resume_early)(struct device * dev);

  int (*resume)(struct device * dev);

  };

  在此,我们需要关注一下platform_match()和platform_drv_probe()函数。platform_match() 函数确定驱动与设备的关联,而platform_drv_probe()函数会在随后先容的函数中被调用。

  //比较驱动信息中的name与设备信息中的name两者是否一致

  static int platform_match(struct device * dev, struct device_driver * drv)

  {

  struct platform_device *pdev = container_of(dev, struct platform_device, dev);

  //通过device找到他所属的platform_device

  return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) = = 0);

  } 

   linux kernel源码中有一个神奇的container_of宏,可以根据一个结构体中成员的地址计算出结构体自身的地址。

   完全可以这样理解container_of宏:

   #define container_of(ptr, type, member) (type *)((char *)ptr - offset_of(type,member)) 

    

   对于实现匹配关系的设备和驱动应有如下关系:

  platform_device -〉device :该device通过链表连接到BUS上.

  platform_driver-〉driver(device_driver类型的结构体):该device通过链表连接到BUS上.

  platform_device -〉device->device_driver(指针),该指针指向了platform_driver-〉driver。

  这样platform_device、platform_driver 就通过platform_device -〉device联系在一起了。

  因此我们可以通过platform_device -〉device 找到对应的platform_device和platform_driver。

  这样就很轻易理解下面的platform_drv_probe函数了:

  static int platform_drv_probe(struct device *_dev)

  {

  struct platform_driver *drv = to_platform_driver(_dev->driver);

  struct platform_device *dev = to_platform_device(_dev);

  return drv->probe(dev);//转往执行platform_driver中定义的probe函数。

  }。

  对于挂到总线上的设备、驱动是通过:kset、kobject建立各个层次之间的联系。对于kset、kobject。可以参考DDR3设备治理的章节。

  至此对设备(device)、总线(bus)、驱动(device_driver)的关系有了一个大概的了解。

  对于2.6内核中更上面一层的封装:platform_device、platform_driver也有了大概的了解。

  1.3  driver_register()函数

  在文件drivers/base/driver.c中,实现了driver_register()函数。在此函数中,初始化结构体struct device_driver中的klist_device和unloaded字段,通过klist_device字段,可以保存此驱动支持的设备链表,通过“完成”接口机制,完成线程间的同步。链表和“完成”接口的具体信息可以参考文献[1]。返回bus_add_driver()函数的运行结果。

  /** *driver_register - register driver with bus *

  @drv:driver to register *

  We pass off most of the work to the bus_add_driver() call, *

  since most of the things we have to do deal with the bus structures. 

水利模型>  *The one interesting aspect is that we setup drv->unloaded *

  as a completion that gets complete when the driver reference count reaches 0. */ 

  int driver_register(struct device_driver * drv) 

  { 

   //假如总线的方法和设备自己的方法同时存在,将打印告警信息

  if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown))

  { 

  printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); 

  } 

  klist_init(&drv->klist_devices, NULL, NULL); //将driver驱动上的设备链表清空

  init_completion(&drv->unloaded); 

  return bus_add_driver(drv); //将本driver驱动注册登记到drv->bus所在的总线上。

  在内核中以driver成员变量kobject,表示driver.

  所谓的注册即是: driver中的内核成员对象kobject的链表(kobj->entry),加进到bus总线的bus_type ->kset->list 链表中。这样就可以通过总线,找到所有定义在该总线下的kobject(driver).

  } 

   1.4 bus_add_driver()函数

  在文件drivers/base/bus.c中实现了bus_add_driver()函数,它通过语句klist_add_tail(&drv->knode_bus, &bus->klist_drivers); 将驱动信息保存到总线结构中,在设备注册过程中,我们就可以明白此语句的作用了。在此语句之前,调用了driver_attach()函数。

  /** *bus_add_driver - Add a driver to the bus 锅炉模型. *@drv:driver. * */ 

  int bus_add_driver(struct device_driver *drv) 

  { 

  struct bus_type * bus = get_bus(drv->bus); //获取总线内容,即前面定义的

  platform_bus_type

  int error = 0; 

  if (!bus) 

  return 0; 

  pr_debug("bus %s: add driver %s\n", bus->name, drv->name); 

  /*kobject_set_name :设置kboj->name[KOBJ_NAME_LEN]数组内容,假如KOBJ_NAME_LEN长度不够,会调用kmalloc申请之后kobj->k_name指针或者指向kboj->name或者指向kmalloc返回地址*/

  error = kobject_set_name(&drv->kobj, "%s", drv->name); 

  //设置kboj->name成员= drv->name

  if (error) 

  goto out_put_bus;  //开释总线

  drv->kobj.kset = &bus->drivers; //设置device_driver结构体的kobj.kset成员变量(是一个kset指针变量)。 很重要,它指向总线(bus)的kset成员,bus->drivers成员drivers为kset类型。在platform_driver_register ()函数中有如下总线赋值语句:drv->driver.bus = &platform_bus_type; 

  platform_bus_type为内核定义的一类总线(bus)。此处的drv->kobj.kset指针指向了总线(bus) 的kset成员。总线的kset成员是kobject的顶层容器,包含了定义在该总线下面所有的kobject。

  /******************************************************************/

  /* kobject_register()理解:把drv的kobj登记到治理它的bus->kset集合上往。同时再根据层级关系创建相应的目录文件 。

  注册登记该kobj,假如该kobj属于某个kset,那么将自己的entry节点(list_head)挂接到该kset的list链表上,以示自己需要该kset的滋润,同时kobj->parent=&kset->ko 智能模型bj,parent指向kset用来治理自己的kobj

  假如该kobj的parent已经定义,那么简单 化工模型的将parent的引用计数加1(假如该kobj不属于kset,而属于parent,那么简单的将parent的引用计数加1.)

  对于kobj属于某个kset的情况,可以实现kset向下查找kobj,也可以实现kobj向上查找kset。

  对于kobj属于某个parent的情况,查找只能是单向的,只能kobj找到parent,parent不能查找该parent挂接的kobj们。parent是用来明显建立亲子关系图的标志性变量,当然在kset也能若隐若现的显露出这种关系,但总不如parent正宗和高效。之后调用create_dir()创建该kobj在sysfs中的目录文件

  最后调用kobject_uevent()将KOBJ_ADD事件通知到用户空间的守护进程*/

  if ((error = kobject_register(&drv->kobj)))  //将driver挂到bus总线上。

  
goto out_put_bus; 

  error = driver_attach(drv); //查找所有注册在该bus上的device,当有device的name和driver->name一样时。即找到了该driver对应的设备。在里面调用的really_probe()函数中,实现了设备与驱动的绑定。语句如下:dev->driver = drv;和ret = drv->probe(dev)

  if (error) 

  goto out_unregister; 

  klist_add_tail(&drv->knode_bus, &bus->klist_drivers); 

  module_add_driver(drv->owner, drv); 

  /*所以一个驱动需要维持住1个klist链条和一个kobj层次结构--驱动drv->kobj对象,内核一方面使用该kobj在sysfs中建立同一的与该kobj对应的目录对象供用户空间访问,另一方面使用该kobj的引用计数来获悉该kobj设备的繁忙与空闲情况,

  //当本kobj对象的引用计数到达0时,只要其他条件答应,那么说明集本钱kobj的结构体对象不再使用,内核得知这个情况很重要,由于这对内核进行进一步的决策提供了具体的证据资料,进而对物理设备进行细致的电源治理成了可能,//如:当hub1上的所有端口设备都被拔掉之后,hub1就可以安全的进进省电模式了,而这个功能在2.4内核中是找不到的.

  error = driver_add_attrs(bus, drv); 

  if (error) { 

  /* How the hell do we get out of this pickle? Give up */ 

  printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", 

  __FUNCTION__, drv->name); 

  } 

  error = add_bind_files(drv); 

  if (error) { 

  /* Ditto */ 

  printk(KERN_ERR "%s: add_bind_files(%s) failed\n", 

  __FUNCTION__, drv->name); 

  } 

  return error; 

  out_unregister: 

  kobject_unregister(&drv->kobj); 

  out_put_bus: 

  put_bus(bus); 

  return error; 

  } 

   下面说明设备驱动是如何知道总线对应设备的

   1.5 dd.c文件driver_attach()函数

  在文件drivers/base/dd.c中,实现了设备与驱动交互的核心函数。

  1.5.1 driver_attach()函数

  函数driver_attach()返回bus_for_each_dev()函数的运行结果。bus_for_each_dev()函数的原型如下:

  int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, 

  int (*fn) (struct device *, void *));

  该函数迭代了在总线上的每个设备,将相关的device结构传递给fn,同时传递data值。假如start是NULL,将从总线上的第一个设备开始迭代;否则将从start后的第一个设备开始迭代。假如fn返回一个非零值,将停止迭代,而这个值也会从该函数返回(摘自<<Linux设备驱动程序>>第三版)。

  该函数是如何知道总线上的每个设备的呢?在设备注册过程中,我会具体先容。

  /* *drivers/base/dd.c - The core device/driver interactions. * * This file contains the (sometimes tricky) code that controls the *interactions between devices and drivers, which primarily includes *driver binding and unbinding. *//** *driver_attach - try to bind driver to devices. *@drv:driver. * *Walk the list of devices that the bus has on it and try to *match the driver with each one.If driver_probe_device() *

  returns 0 and the @dev->driver is set, we've found a *compatible pair. */ 

  int driver_attach(struct device_driver * drv) 

  { 

  return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); 

  } 

  1.5.2 __driver_attach()函数

  函数__driver_attach()在调用driver_probe_device()函数前,需要进行线程间的互斥处理。

  static int __drive 智能模型r_attach(struct device * dev, void * data) 

  { 

  struct device_driver * drv = data; 

  /* * Lock device and try to bind to it. We drop the error * here and always return 0, because we need to keep trying * to bind to devices and some drivers will return an error* simply if it didn't support the device. * * driver_probe_device() will spit a warning if there * is an error. */ 

  if (dev->parent)

  down(&dev->parent->sem); 

  down(&dev->sem); 

  if (!dev->driver) 

  driver_probe_device(drv, dev); 

  up(&dev->sem); 

  if (dev->parent) 

  up(&dev->parent->sem); 

  return 0; 

  } 

  1.5.3 driver_probe_device()函数

  在driver_probe_device()函数中,调用了match函数platform_match(),假如它返回0,表示驱动与设备不一致,函数返回;否则,调用really_probe()函数。

  /** * driver_probe_device - attempt to bind device & driver together 

  * @drv: driver to bind a device to * @dev: device to try to bind to the driver * * First, we call the bus's match function, if one present, which should * compare the device IDs the driver supports with the device IDs of the * device. Note we don't do this ourselves because we don't know the * format of the ID structures, nor what is to be considered a match and * what is not. * * This function returns 1 if a match is found, an error if one occurs *(that is not -ENODEV or -ENXIO), and 0 otherwise. * * This function must be called with @dev->sem held. When called for a * USB inte***ce, @dev->parent->sem must be held as well. */ 

  int  driver_probe_device(struct device_driver * drv, struct device * dev) 

  { 

  struct stupid_thread_structure *data; 

  struct task_struct *probe_task; 

  int ret = 0; 

  if (!device_is_registered(dev)) 

  return -ENODEV; 

  if (drv->bus->match && !drv->bus->match(dev, drv)) 

  goto done; 

  pr_debug("%s: Matched Device %s with Driver %s\n", 

  drv->bus->name, dev->bus_id, drv->name); 

  data = kmalloc(sizeof(*data), GFP_KERNEL); 

  if (!data) 

  return -ENOMEM; 

  data->drv = drv; 

  data->dev = dev; 

  if (drv->multithread_probe) { 

  probe_task = kthread_run(really_probe, data, 

  "probe-%s", dev->bus_id); 

  if (IS_ERR(probe_task)) 

  ret = really_probe(data); 

  } else 

  ret =  really_probe(data)

  done: 

  return ret; 

  }

   struct stupid_thread_structure 

  struct device_driver *drv; 

  struct device *dev; 

  }; 

  1.5.4 really_probe()函数

   在really_probe()函数中,实现了设备与驱动的绑定。语句如下:dev->driver = drv;和

  ret = drv->probe(dev); probe()函数的实现如下:

  include/linux/platform_device.h

  #define to_platform_device(x) container_of((x), struct platform_device, dev)

  drivers/base/platform.c

  #define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver))

  static int platform_drv_probe(struct device *_dev) 

  { 

  struct platform_driver *drv = to_platform_driver(_dev->driver); 

  struct platform_device *dev = to_platform_device(_dev); 

  return drv->probe(dev); 

  } 

  在此函数中,回调了我们在i2c-at91.c文件中实现的探测函数at91_i2c_probe(),至此,平台驱动的注册过程结束。

  static atomic_t probe_count = ATOMIC_INIT(0); 

  static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); 

  static int really_probe(void *void_data) 

  { 

  struct stupid_thread_structure *data = void_data; 

  struct device_driver *drv = data->drv; 

  struct device *dev = data->dev; 

  int ret = 0; 

  atomic_inc(&probe_count); 

  pr_debug("%s: Probing driver %s with device %s\n", 

  drv->bus->name, drv->name, dev->bus_id); 

  WARN_ON(!list_empty(&dev->devres_head)); 

  dev->driver = drv; 

  if (driver_sysfs_add(dev)) { 

  printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", 

  __FUNCTION__, dev->bus_id); 

  goto probe_failed; 

  } 

  if (dev->bus->probe) { 

  ret = dev->bus->probe(dev); 

  if (ret) 

  goto probe_failed; 

  } else if (drv->probe) { 

  ret = drv->probe(dev) 科普模型

  if (ret) 

  goto probe_failed; 

  } 

  //设备与驱动绑定后,对系统中已注册的组件进行事件通知。

  driver_bound(dev); 

  ret = 1; 

  pr_debug("%s: Bound Device %s to Driver %s\n", 

  drv->bus->name, dev->bus_id, drv->name); 

  goto done; 

  probe_failed: 

  devres_release_all(dev); 

  driver_sysfs_remove(dev); 

  dev->driver = NULL; 

  if (ret != -ENODEV && ret != -ENXIO) { 

  /* driver matched but the probe failed */ 

  printk(KERN_WARNING 

  "%s: probe of %s failed with error %d\n", 

  drv->name, dev->bus_id, ret); 

  } 

  /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ 

  ret = 0; 

  done: 

  kfree(data); 

  atomic_dec(&probe_count); 

  wake_up(&probe_waitqueue); 

  return ret; 

  }

  摘自:http://www.360doc.com/content/10/0831/15/_.shtml
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版: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 。。。
完整版: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 。。。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值