当前课程知识点:“做中学”Java程序设计 >  第4章使用面向对象高级语法 >  4.4使用抽象类 >  Video

返回《“做中学”Java程序设计》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《“做中学”Java程序设计》慕课在线视频列表

Video课程教案、知识点、字幕

在讨论今天的主题时我们先来看一个在设计Java类的时候经常会碰到的一个现实问题

了解了类和对象以后

在讨论今天的主题时我们先来看一个在设计Java类的时候经常会碰到的一个现实问题

今天我们来一起学习一下

今天我们来一起学习一下

如何在JAVA当中创建一个自定义的类

比如要描述所有人都会讲话

以及如何和像类当中添加相关的属性

以及如何和像类当中添加相关的属性

但是美国人讲的是美式英语

首先我们一起来看看类是如何定义的

首先我们一起来看看类是如何定义的

而中国人讲的是汉语

这里给出 了JAVA类的标准定义语法

这里给出 了JAVA类的标准定义语法

先简要的介绍一下他们的基本含义

你可能会这样设计

先简要的介绍一下他们的基本含义

父类person当中包含两个子类American和Chinese

父类person当中包含两个子类American和Chinese

类的声明主要有Class关键字

类名

类体部分和修饰符部分构成

类体部分和修饰符部分构成

而 Person都有speak()行为

而 Person都有speak()行为

作为父类Person它是无法确知这个方法的具体实现的

包含关键字Class的这一行

我们称之为类的声明

我们称之为类的声明

只有具体的子类 American他才知道自己讲是美式英语

称之为类体

只有具体的子类 American他才知道自己讲是美式英语

类的声明使用关键字Class

类的声明使用关键字Class

同样Chinese也知道自己应该讲汉语

同样Chinese也知道自己应该讲汉语

后面紧跟一个类名

同样Chinese也知道自己应该讲汉语

这里的类名必须是合法的标志符

这里的类名必须是合法的标志符

JAVA当中允许你将父类当中

这里的类名必须是合法的标志符

这个无法实现的特殊方法打上一个abstract标签

这个无法实现的特殊方法打上一个abstract标签

方括号括起来的关键字

是类的可选关键字

我们将这样的方法称之为抽象方法

我们将这样的方法称之为抽象方法

我们将这样的方法称之为抽象方法

这些关键字我们称之为类的修饰符

而将这个方法的具体实现

而将这个方法的具体实现

这些关键字我们称之为类的修饰符

交给继承这个类的子类来完成

他们具有一些特定含义

交给继承这个类的子类来完成

我们可以先了解一下

我们可以先了解一下

随着学习的深入

例如你要将类Person定义为抽象类

你会对这些关键字

你会对这些关键字

只需要在Class的标识符前面

有更深刻的认识

只需要在Class的标识符前面

加上abstract关键字就可以了

Public

Private

加上abstract关键字就可以了

Protect和Default

Protect和Default

现在我们来总结一下抽象类的应用场景

现在我们来总结一下抽象类的应用场景

是JAVA当中

是JAVA当中

访问权限的相关关键字

正如前面所示例的

访问权限的相关关键字

当某个类知道其子类应该具有某个方法

这里的Public关键字就描述了该类的访问权限是公开的共有的

这里的Public关键字就描述了该类的访问权限是公开的共有的

但是无需具体了解这些子类的方法实现的时候

共有的

但是无需具体了解这些子类的方法实现的时候

就目前而言你需要记住的一点是

就目前而言你需要记住的一点是

我们就可以使用抽象方法

凡是声明为Pulic的类

凡是声明为Pulic的类

必须保存在与它名字相同的源文件当中

你也可以从多个具有相同特性的类当中来抽象出一个抽象类

你也可以从多个具有相同特性的类当中来抽象出一个抽象类

更具体一点的来讲

更具体一点的来讲

以这个抽象类作为子类的模板

以这个抽象类作为子类的模板

在一个JAVA源代码文件当中

在一个JAVA源代码文件当中

从而避免子类设计的随意性

你可以包含多个类的定义

你可以包含多个类的定义

就刚才的例子来讲

但是只能有且只有一个

但是只能有且只有一个

我们如果要增加一个新的Japanese日本人

可以声明为Public的

我们如果要增加一个新的Japanese日本人

因为它的名字必须要和

因为它的名字必须要和

那么同样他只要继承我们的Person类

那么同样他只要继承我们的Person类

这个源文件的文件名保持一致

这个源文件的文件名保持一致

凡是继承Person类

凡是继承Person类

可选的修饰符还包括abstract

可选的修饰符还包括abstract

那么他这个类那就具有speak()功能

那么他这个类那就具有speak()功能

它是一个抽象修饰符

它是一个抽象修饰符

从而规范了所有继承自Person类的子类行为

声明为抽象的类

将不能被实例化

将不能被实例化

在使用抽象类的时候我们还需要特别注意它的使用规则

在使用抽象类的时候我们还需要特别注意它的使用规则

final

这是一个最终的修饰符

这是一个最终的修饰符

表明这个类不能被继承

除了抽象类在定义时必须使用abstract关键字进行修饰之外

除了抽象类在定义时必须使用abstract关键字进行修饰之外

无法对它进行扩展

无法对它进行扩展

抽象方法也必须使用abstract关键字进行修饰

extends

抽象方法也必须使用abstract关键字进行修饰

它是用来声明类的继承关系

它是用来声明类的继承关系

那么这里 大家需要特别注意在定义抽象方法的时候我们不需要给出方法体

那么这里 大家需要特别注意在定义抽象方法的时候我们不需要给出方法体

关键字implements

那么这里 大家需要特别注意在定义抽象方法的时候我们不需要给出方法体

表明该类是现在相关的接口

表明该类是现在相关的接口

只需要保留方法的签名就可以了

只需要保留方法的签名就可以了

那么各个接口之间

那么各个接口之间

要记住 凡是具有抽象方法的类这个类必须定义成一个抽象类

使用逗号进行分隔

要记住 凡是具有抽象方法的类这个类必须定义成一个抽象类

了解了这些知识以后呢

要记住 凡是具有抽象方法的类这个类必须定义成一个抽象类

下面我们要实现如图所示的时间应用程序项目

如果你只添加了抽象方法

下面我们要实现如图所示的时间应用程序项目

而忘了给类添加的abstract关键字的话

而忘了给类添加的abstract关键字的话

在这个项目当中

我们可以根据用户设定的时

我们可以根据用户设定的时

那么将产生一个编译错误

分秒的时间信息

分秒的时间信息

作为抽象类你无法使用它进行对象的实例化

作为抽象类你无法使用它进行对象的实例化

来设定一个时间对象

作为抽象类你无法使用它进行对象的实例化

并且以均用格式和标准格式

并且以均用格式和标准格式

所以直接new Person是一个常见的语法错误

两种不同的显示方式来显示这个时间对象

两种不同的显示方式来显示这个时间对象

但是抽象类可以作为一种数据类型

但是抽象类可以作为一种数据类型

这里就让我们从定义时间类来开始

这里就让我们从定义时间类来开始

你可以用它来定义一个引用变量

时间类是对时间对象的一个共同抽象

时间类是对时间对象的一个共同抽象

比如你可以这样写Person p=new Chinese();

比如你可以这样写Person p=new Chinese();

那么我们有哪些时间对象呢

你可以找出很多

你可以找出很多

这样你就可以用它来引用一个子类的实际对象

这样你就可以用它来引用一个子类的实际对象

比如

你早上上课的时间是八点十五分

这样你就可以用它来引用一个子类的实际对象

早操的时间是九点钟

早操的时间是九点钟

刚才我们提到

早操的时间是九点钟

如果一个方法是抽象方法

如果一个方法是抽象方法

晚上熄灯的时间是二十二点

晚上熄灯的时间是二十二点

那么他所在的类 必然是一个抽象类

那么他所在的类 必然是一个抽象类

观察一下这些时间对象

它们有哪些共同的属性呢

它们有哪些共同的属性呢

但是反过来

它们有哪些共同的属性呢

抽象类并不一定必须要有抽象方法的

我们在学习当中对每个对象

在内存当中持有的数据

在内存当中持有的数据

你可以在一个抽象类当中仅仅只包含 普通方法而没有抽象方法

称之为类的属性

它们在类的定义当中

对应的就是我们类的实例变量

对应的就是我们类的实例变量

有了这些基本概念以后呢我们就可以引入面向对象的第三大特性

在每个创建的对象当中

都存在一套这样的实例变量

多态性

都存在一套这样的实例变量

多态和继承有时候密不可分

针对我们现在的时钟应用程序

针对我们现在的时钟应用程序

它是指同一个操作

首先我们要确定它的类名

首先我们要确定它的类名

作用于不同的对象

然后是它的实例变量

然后是它的实例变量

具有不同的显示从而产生不同的执行结果

具有不同的显示从而产生不同的执行结果

同时还要考虑这些实例变量的类型又是什么

同时还要考虑这些实例变量的类型又是什么

在继承关系当中我们曾经讲过你可以借助is-a来判断两个类是否具有有继承关系

在继承关系当中我们曾经讲过你可以借助is-a来判断两个类是否具有有继承关系

最后呢我们还要注意到

他们有各自不同的取值范围

在继承关系当中我们曾经讲过你可以借助is-a来判断两个类是否具有有继承关系

根据见名知意的原则

根据见名知意的原则

在我们的学生信息管理系统当中

我们可以又使用Time作为我们的类名

我们可以又使用Time作为我们的类名

学生是其中的一个用户

学生是其中的一个用户

它准确的表达了我们这个类的用途以及它的含义

它准确的表达了我们这个类的用途以及它的含义

所以学生是用户是符合逻辑的

它准确的表达了我们这个类的用途以及它的含义

教师也是我们的一类用户

同时

教师也是我们的一类用户

我们可以使用hour,mimute

我们可以使用hour,mimute

所以教师是用户也是符合逻辑的

second

分别表示它的属性

分别表示它的属性

因此将用户作为父类

对应的就是我们的时、分、秒

对应的就是我们的时、分、秒

将学生和教师作为它的子类

三个数据

将学生和教师作为它的子类

至于这些属性

至于这些属性

是符合继承关系的

至于这些属性

但是这种关系的倒过来就不合逻辑了比如用户是教师 用户是学生

它的类型

但是这种关系的倒过来就不合逻辑了比如用户是教师 用户是学生

我想大家一定会选择

int作为它的数据类型

int作为它的数据类型

明显是不符合逻辑的

因为这些值都是一个整型数的表达

因为这些值都是一个整型数的表达

也正是这种逻辑关系

也正是这种逻辑关系

我们推而广之

好了

我们推而广之

接下去我们就开始动手写出这个类吧

著名的里氏替换原则就讲到

接下去我们就开始动手写出这个类吧

任何基类对象出现的地方

我们可以通过类的新建向导

创建一个类

创建一个类

继承于他的子类也一定可以出现

继承于他的子类也一定可以出现

取名为time

继承于他的子类也一定可以出现

eclipse已经为我们搭建好了time类的框架

eclipse已经为我们搭建好了time类的框架

你可以这样理解

eclipse已经为我们搭建好了time类的框架

所有引用父类的地方

所有引用父类的地方

接下去我们在类当中

接下去我们在类当中

我们都可以透明的把它替换成子类的对象

定义三个实例变量

分别取名为hour、minute、second

分别取名为hour、minute、second

就我们的学生信息管理系统当中

它们的数据类型都是整型

它们的数据类型都是整型

所有的用户对象

所有的用户对象

他都能够登录和退出系统

好了

这样三个属性就添加完成了

这样三个属性就添加完成了

那么作为他的子类 学生和教师

要在外界引用这些属性,需要通过对象成员的访问方式

要在外界引用这些属性,需要通过对象成员的访问方式

也同样就应该具有 登录和退出系统的功能

来完成

也同样就应该具有 登录和退出系统的功能

我们先来新建一个测试类

我们先来新建一个测试类

这是符合逻辑的

取名为App

取名为App

并勾选main方法

自动生成可运行的程序入口main的框架

这里的代码的第9行

这里的代码的第9行

在这个方法当中

在这个方法当中

我们声明了一个user类型的引用变量

我们来测试下time类的使用

我们来测试下time类的使用

原则上他应该指向一个user对象

原则上他应该指向一个user对象

这里我们就要需要补充两个重要的语法

这里我们就要需要补充两个重要的语法

但这里的我们将一个子类student赋值给他

但这里的我们将一个子类student赋值给他

创建实例的语法

但这里的我们将一个子类student赋值给他

和属性引用的语法

和属性引用的语法

因为父类的引用变量可以保持任何继承他的子类对象

因为父类的引用变量可以保持任何继承他的子类对象

要创建一个实例

需要通过new这个关键字

这是符合里氏替换原则的

这是符合里氏替换原则的

并且调用相应的构造方法

并且调用相应的构造方法

但是种功能也会带来负面的作用

比如

你这里要创建一个time实例

你这里要创建一个time实例

有时候你无法确定

有时候你无法确定

你就可以new time 来完成

你就可以new time 来完成

这父类引用变量当中保持了你要使用的哪一个特定的类型对象呢

这父类引用变量当中保持了你要使用的哪一个特定的类型对象呢

Time

这父类引用变量当中保持了你要使用的哪一个特定的类型对象呢

圆括号是一个默认的构造方法

圆括号是一个默认的构造方法

这时候你就可以使用了

这时候你就可以使用了

我们用它来创建一个时间对象t当中

我们用它来创建一个时间对象t当中

instance of语法来进行类型的检查

instance of语法来进行类型的检查

并保存在我们的引用变量

并保存在我们的引用变量

从而判断某个对象是不是某个特定的类型的子类

从而判断某个对象是不是某个特定的类型的子类

有了这个对象

我们就可以通过对象引用的方法

我们就可以通过对象引用的方法

比如代码的第14号 这里的t 保持的是代码第8行中的教师对象

比如代码的第14号 这里的t 保持的是代码第8行中的教师对象

也称之为原点访问法

比如代码的第14号 这里的t 保持的是代码第8行中的教师对象

来获取对象当中的属性

比如代码的第14号 这里的t 保持的是代码第8行中的教师对象

虽然不是user对象 但instance of 判断是基于里氏替换原则的 它将返回的是一个Ture

比如我们要获取小时就可以用t.hour

虽然不是user对象 但instance of 判断是基于里氏替换原则的 它将返回的是一个Ture

要获取分钟

虽然不是user对象 但instance of 判断是基于里氏替换原则的 它将返回的是一个Ture

就可以用t.minutes

就可以用t.minutes

同样的代码的第15行第16行返回了Ture

要获取秒钟

同样的代码的第15行第16行返回了Ture

只需要用t.second就可以了

只需要用t.second就可以了

代码第17行 引用变量u当中

来运行下我们的程序

你可以看到,在控制台当中

你可以看到,在控制台当中

实际保持的是代码第九行的学生对象

它们的输出的结果都是零

它们的输出的结果都是零

学生对象不是这Teacher类型的实例

学生对象不是这Teacher类型的实例

接下去我们用

接下去我们用

因此他返回的是一个false

原点访问法去修改这些属性

原点访问法去修改这些属性

这些设计 使得我们的多态的实现成为了可能

这些设计 使得我们的多态的实现成为了可能

再次打印你将会发现这些t的值发生了相应的变化

下面我们一起来完成下面的任务

再次打印你将会发现这些t的值发生了相应的变化

体会多态的奥秘

再次打印你将会发现这些t的值发生了相应的变化

用类似的方式

你可以试一试在你的程序当中

在这个任务当中 学生信息管理系统当中需要我们实现user和teacher-student三者的继承关系

创建一个早操的时间

在这个任务当中 学生信息管理系统当中需要我们实现user和teacher-student三者的继承关系

和晚上熄灯的时间

在这个任务当中 学生信息管理系统当中需要我们实现user和teacher-student三者的继承关系

今天的课就到这里

今天的课就到这里

其中所有用户都具有登录

其中所有用户都具有登录

好了

其中所有用户都具有登录

总结一下今天的内容

总结一下今天的内容

login和退出logout方法

login和退出logout方法

在今天的课程当中

在今天的课程当中

但父类user无法对具体的登录和退出进行实现

你学习了如何使用JAVA程序

编写一个自定义的类

但父类user无法对具体的登录和退出进行实现

以及如何使用类

所以我们可以将它们定义为抽象方法

所以我们可以将它们定义为抽象方法

声明自己的属性

声明自己的属性

作为子类Teacher在登陆时

在代码当中

作为子类Teacher在登陆时

创建类的实例变量

创建类的实例变量

将显示相应的登录信息并切换到教师的操作视图

将显示相应的登录信息并切换到教师的操作视图

通过原点的访问方式

将显示相应的登录信息并切换到教师的操作视图

来引用对象的相应属性

来引用对象的相应属性

学生在登陆以后 除了同样显示登陆信息之外 将切换到学生的操作视图

学生在登陆以后 除了同样显示登陆信息之外 将切换到学生的操作视图

这些知识呢非常重要

学生在登陆以后 除了同样显示登陆信息之外 将切换到学生的操作视图

学会他们

学生在登陆以后 除了同样显示登陆信息之外 将切换到学生的操作视图

你就可以像上帝一样

你就可以像上帝一样

创造计算机世界当中的一切事物了

我们可以在 proj03的包当中找到我们前面设计好的student类 并在其中添加我们的Login和Logout方法

我们可以在 proj03的包当中找到我们前面设计好的student类 并在其中添加我们的Login和Logout方法

根据前面说明 学生作为具体子类 他知道如何 登录和退出系统

这里那我们就用一个输出语句来作为一个登陆和退出的示例

接下去我们创建一个新的类user

要在eclipse当中定义抽象类是非常方便的

你只需要在创建类的时候那打上这个abstract复选框即可了

单击完成

我们可以看到 eclipse自动为我们生成了抽象类的框架代码

接着 要让 Student 继承 User类

只需要在Student类当中修改类的声明部分添加extends继承关系

将它指定为User

我们可以将子类当中的共同的方法抽取到父类当中去

这里介绍一个小技巧

Eclipse提供了pull-up重构功能

单击右键

我们选择Refactor菜单

在子菜单当中我们可以找到Pull up功能

他可以将我们的子类当中的相关变量和方法提取到我们的父类当中来

在打开的Pull up对话框当中

确保你的目标类型是我们的父类user

选择要抽象的共同的属性 id name 和共同的方法 login和logout

单击finish完成

然后我们打开user类

子类的相应变量和方法已经提取到了父类当中

那么我们 接下去修改这些 变量的访问权限为protected

由于父类无法确定我们的login和logout 具体行为

因此这两个方法的我们将它定义为abstract抽象方法

一旦你声明了抽象方法以后呢 这个方法体你就可以去掉了

我们只要保留这个方法的签名就可以了

保存所有的文件以后你会发现学生类开始报错

将鼠标移动到类名当中

显示子类的Student必须实现父类User自定义的抽象方法

单击这个链接

系统将为你自动添加尚未实现的那些方法框架

我们只需要在这个方法框架里面

填写具体的方法实现即可

好保存一下

没有任何的错误

下面我们来创建一个代码测试

名字的取名为SMSApp

在这里的我们勾选main方法让它自动生成主方法

在main方法当中我们添加一个User类型数组

并使用初始化列表的方式

添加一个学生对象

这里出现的波浪线告诉我们尚未定义带有两个参数的构造方法

单击快速修改方案的这个链接 可以帮助我们快速地创建相应的构造方法

将方法的参数名字调整为id 和name

由于此类Student已经将id name的实例变量提取到了父类

所以我们可以 调用super方法

将创建对象的工作哪 交给父类的相应的方法去完成

那么这时候的super下波浪线

告诉我们 父类还需要提供带两个参数的构造方法

所以我们继续单击这个链接

创建一个带两个参数的构造方法的框架

切换到user 修改相应的参数名

这里呢 我们可以轻松地将用户传入的参数

保存到我们实例变量当中去了

使用this.id==id这样的形式将右侧的参数id保存到左侧实例变量id当中

对name也是如此操作

在Student类当中

我们以前写的26到37行的相关测试代码

我们先把它注释掉

回到SMSApp的测试程序当中

如果你想向数组当中添加教师对象

这时候我们就需要定义教师类

在创建教师类型的时候

你可以直接指定他的父类 为我们的user

这时候呢代码就自动识别出来

user这里面定义两个抽象方法

作为子类 你必须实现这两个抽象方法

相应的代码框架已经给你写好 你只要对他进行相应的实现就可以了

接下去我们还需要为这个Teacher的添加带两个参数的构造方法

同样我们可以使用 super 交给我们的父类去保存相应的id和name

现在我们已经可以在 数组当中添加任意的学生对象和教师对象了

利用前面学过的for each语法

我们可以用一条语句让数组的容器当中的每个user对象来登录系统

代码如此简单

简单到有点像变一个小魔术

这背后的奥秘这是我们前面讲过的里氏替换原则

user数组保持的都是User类型的引用

由于父类出现的地方都可以用Teacher对象来替代

这也就为我们的第7行第8行代码实现提供了相关的理论依据

此外父类的设计当中定义了抽象方法login

这就意味着第11行代码调用的是合法

这些代码及符合逻辑也符合语法规则

现在我们来运行下看看实际的运行效果

当第1次循环时 循环变量user实际引用的是一个学生对象 这将调用学生对象的login方法

而在第2次循环时 循环变量user实际引用的是一个教师对象 这将调用教室对象的login方法

这一切系统都会借助Java的动态绑定机制

自动的在后台替我们完成所有的工作而不需要我们的程序员手动的进行类型的转换

这个示例就是多态的一个典型示例

对照我们前面多态的定义

这里的共同行为就是我们的登录行为Login

对于这一个同一个操作它

作用于学生对象 和作用于教师对象

会呈现出不同的执行结果

通过这个例子 相信你应该明白了 多态的用法

在今天的课程当中

我们学习了Java多态的特性 以及他的代码实现

多态作为面向对象的主要特性

可以帮我们简化程序的设计和实现

这一切需要取决于你对他是否有一个全面而正确的理解

“做中学”Java程序设计课程列表:

第1章初始Java

-1.1Java简介

--01Java简介

-1.2搭建Java开发环境

--Video

-1.3使用记事本编写Java程序

--Video

-1.4使用Eclipse开发Java程序

--Video

-1.5导入/导出Java项目

--Video

-1.6管理组织代码

--Video

-第1章初始Java--测试题

第2章使用Java基本语法(1)

-2.1认识标识符

--Video

-2.2变量和变量类型

--Video

-2.3数据类型和类型转换

--Video

-2.4使用常量

--Video

-2.5使用注释

--Video

-2.6使用运算符进行算术运算

--Video

-第2章使用Java基本语法(1)--测试题

第2章使用Java基本语法(2)

-2.7使用运算符进行逻辑处理

--Video

-2.8使用if进行流程控制

--Video

-2.9使用switch进行流程控制

--使用switch进行流程控制

-2.10使用循环

--Video

-2.11循环的跳出和继续

--Video

-2.12多重循环

--Video

-第2章使用Java基本语法(2)--测试题

第3章使用面向对象基础语法

-3.1认识类和对象

--Video

-3.2为类添加属性

--Video

-3.3为类添加方法

--Video

-3.4为类添加静态方法

--Video

-3.5递归方法

--递归方法

-3.6构造方法

--Video

-3.7重载方法

--Video

-第3章使用面向对象基础语法--测试题

第4章使用面向对象高级语法

-4.1使用继承语法

--Video

-4.2使用数组

--Video

-4.3使用数组类操作数组

--Video

-4.4使用抽象类

--Video

-4.5使用接口

--Video

-第4章使用面向对象高级语法--测试题

第5章捕获并处理异常

-5.1异常处理机制

--Video

-5.2捕获异常

--Video

-5.3创建自定义异常

--Video

-第5章捕获并处理异常--测试题

第6章使用SWT设计界面

-6.1SWT图形界面

--Video

-6.2使用SWT布局管理-FillLayout

--使用SWT布局管理-FillLayout

-6.3使用SWT布局管理-RowLayout

--使用SWT布局管理-RowLayout

-6.4SWT中的事件模型

--Video

-6.5常见事件处理写法

--Video

-第6章使用SWT设计界面--测试题

第7章微波炉模拟程序

-7.1微波炉模拟程序的界面制作

--Video

-7.2微波炉模拟程序的代码重构

--Video

-7.3微波炉模拟程序的事件监听

--Video

-7.4微波炉模拟程序的数字键盘

--Video

-7.6微波炉模拟程序CookTimer

--Video

-7.7微波炉模拟程序添加图像

--Video

-7.8微波炉模拟程序添加声音

--Video

-7.9微波炉模拟程序安装包制作

--Video

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。