java入门之计算机基础知识

什么是计算机?计算机在生活中的应用举例 

  • 计算机(Computer)全称:电子计算机,俗称电脑。是一种能够按照程序运行,自动、高速处理海量数据的现代化智能电子设备。由硬件和软件所组成,没有安装任何软件的计算机称为裸机。常见的形式有台式计算机、笔记本计算机、大型计算机等。
  • 应用举例 
    • 1:科学计算
    • 2、数据处理
    • 3、自动控制
    • 4、计算机辅助设计
    • 5、人工智能
    • 6、多媒体应用
    • 7、计算机网络

什么是硬件?硬件举例

  • 计算机硬件(Computer Hardware)是指计算机系统中由电子,机械和光电元件等组成的各种物理装置的总称。这些物理装置按系统结构的要求构成一个有机整体为计算机软件运行提供物质基础。
  • 冯.诺依曼体系结构
  • 计算机的硬件分成5大组成部件:运算器、控制器、存储器、输入设备和输出设备。

    • 运算器和控制器是计算机的核心,合称中央处理单元(Central Processing Unit,CPU)或处理器。CPU的内部还有一些高速存储单元,被称为寄存器。其中运算器执行所有的算术和逻辑运算;控制器负责把指令逐条从存储器中取出,经译码后向计算机发出各种控制命令;而寄存器为处理单元提供操作所需要的数据。
    • 存储器是计算机的记忆部分,用来存放程序以及程序中涉及的数据。它分为内部存储器和外部存储器。内部存储器用于存放正在执行的程序和使用的数据,其成本高、容量小,但速度快。外部存储器可用于长期保存大量程序和数据,其成本低、容量大,但速度较慢。
    • 输入设备和输出设备统称为外部设备,简称外设或I/O设备,用来实现人机交互和机间通信。微型机中常用的输入设备有键盘、鼠标等,输出设备有显示器、打印机等。

什么是软件?软件分类及举例 

  • 计算机软件(Computer Software)是使用计算机过程中必不可少的东西,计算机软件可以使计算机按照事先预定好的顺序完成特定的功能
  • 计算机软件按照其功能划分为系统软件与应用软件 
    • 系统软件: DOS(Disk Operating System), Windows, Linux, Unix, Mac, Android, iOS
    • 应用软件:office QQ聊天 YY语言 扫雷

计算机基础知识(软件开发和计算机语言概述)

  • A:什么是软件 
    • 按照特定顺序组织的计算机数据和指令的集合
  • B:什么是开发 
    • 软件的制作过程
  • C:什么是软件开发 
    • 借助开发工具与计算机语言制作软件
  • D:什么是计算机语言 
    • 人与计算机之间进行信息交流沟通的一种特殊语言
  • E:计算机语言的分类 
    • 机器语言: 
      • 机器语言是直接用二进制代码指令表达的计算机语言,指令是用0和1组成的一串代码,它们有一定的位数,并分成若干段,各段的编码表示不同的含义。
    • 汇编语言: 
      • 汇编语言是使用一些特殊的符号来代替机器语言的二进制码,计算机不能直接识别,需要用一种软件将汇编语言翻译成机器语言。
    • 高级语言: 
      • 使用普通英语进行编写源代码,通过编译器将源代码翻译成计算机直接识别的机器语言,之后再由计算机执行。
      • 高级语言包括C,C++,C#,JAVA

计算机基础知识(常见的DOS命令讲解)

  • A:d: 回车 盘符切换
  • B:dir(directory):列出当前目录下的文件以及文件夹
  • C:cd (change directory)改变指定目录(进入指定目录)
  • D:cd.. : 退回到上一级目录
  • E:cd: 退回到根目录
  • F:cls : (clear screen)清屏
  • G:exit : 退出dos命令行(分割线上的需要掌握,下的了解)
  • /=========================================================
  • md (make directory) : 创建目录
  • rd (remove directory): 删除目录
  • del (delete): 删除文件,删除一堆后缀名一样的文件*.txt
  • notepad 创建文件
  • 删除带内容的文件夹 
    • rd + /s 文件夹名称(询问是否删除)
    • rd + /q + /s 文件夹名称(直接删除)

Java语言基础(Java语言概述)(了解)

  • A:Java语言发展史 
    • 詹姆斯·高斯林(James Gosling)1977年获得了加拿大卡尔加里大学计算机科学学士学位,1983年获得了美国卡内基梅隆大学计算机科学博士学位,毕业后到IBM工作,设计IBM第一代工作站NeWS系统,但不受重视。后来转至Sun公司,1990年,与Patrick,Naughton和Mike Sheridan等人合作“绿色计划”,后来发展一套语言叫做“Oak”,后改名为Java。
    • SUN(Stanford University Network,斯坦福大学网络公司)
  • B:Java语言版本 
    • JDK 1.1.4 Sparkler 宝石 1997-09-12
    • JDK 1.1.5 Pumpkin 南瓜 1997-12-13
    • JDK 1.1.6 Abigail 阿比盖尔–女子名 1998-04-24
    • JDK 1.1.7 Brutus 布鲁图–古罗马政治家和将军 1998-09-28
    • JDK 1.1.8 Chelsea 切尔西–城市名 1999-04-08
    • J2SE 1.2 Playground 运动场 1998-12-04
    • J2SE 1.2.1 none 无 1999-03-30
    • J2SE 1.2.2 Cricket 蟋蟀 1999-07-08
    • J2SE 1.3 Kestrel 美洲红隼(sǔn) 2000-05-08
    • J2SE 1.3.1 Ladybird 瓢虫 2001-05-17
    • J2SE 1.4.0 Merlin 灰背隼 2002-02-13
    • J2SE 1.4.1 grasshopper 蚱蜢 2002-09-16
    • J2SE 1.4.2 Mantis 螳螂 2003-06-26
    • JAVASE 5.0 (1.5.0) Tiger 老虎
    • JAVASE 5.1 (1.5.1) Dragonfly 蜻蜓
    • JAVASE 6.0 (1.6.0) Mustang 野马
    • JAVASE 7.0 (1.7.0) Dolphin 海豚
  • C:Java语言平台 
    • J2SE(Java 2 Platform Standard Edition)标准版 
      • 是为开发普通桌面和商务应用程序提供的解决方案,该技术体系是其他两者的基础,可以完成一些桌面应用程序的开发
    • J2ME(Java 2 Platform Micro Edition)小型版 
      • 是为开发电子消费产品和嵌入式设备提供的解决方案
    • J2EE(Java 2 Platform Enterprise Edition)企业版 
      • 是为开发企业环境下的应用程序提供的一套解决方案,该技术体系中包含的技术如 Servlet、Jsp等,主要针对于Web应用程序开发
  • D:Java语言特点 
    • 简单性
    • 解释性
    • 面向对象
    • 高性能
    • 分布式处理
    • 多线程
    • 健壮性
    • 动态
    • 结构中立
    • 安全性
    • 开源
    • 跨平台

Java语言基础(Java语言跨平台原理)(掌握)

  • A:什么是跨平台性
  • B:Java语言跨平台原理 
    • 只要在需要运行java应用程序的操作系统上,先安装一个Java虚拟机(JVM Java Virtual Machine)即可。由JVM来负责Java程序在该系统中的运行。
  • C:Java语言跨平台图解 
    • write once ,run anywhere!(一处编译,到处运行)

Java语言基础(JRE和JDK的概述)(掌握)

  • A:什么是JRE 
    • 包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。
    • JRE:JVM+类库。
  • B:什么是JDK 
    • JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。
    • 其中的开发工具:编译工具(javac.exe) 打包工具(jar.exe)等
    • JDK:JRE+JAVA的开发工具。
  • C:为什么JDK中包含一个JRE 
    • 为什么JDK中包含一个JRE呢? 
      • 开发完的程序,需要运行一下看看效果。
  • D:JDK,JRE,JVM的作用和关系

Java语言基础(JDK的下载和安装过程图解)(了解)

  • A:JDK的下载 
  • B:JDK的安装 
    • a:傻瓜式安装 
      • 双击安装程序,然后一路next即可(但是不建议)
    • b:安装的推荐方式 
      • 安装路径不要有中文或者特殊符号如空格等。
      • 所有和开发相关的软件最好安装目录统一。 
        • 举例:我的JDK安装路径 
          • D:\xuexi\JDK
      • 当提示安装JRE时,可以选择不安装。建议还是安装上。
    • c:演示安装流程 
      • 可以先在d盘建立一个文件夹(develop)
      • 然后演示安装过程
  • C:验证安装是否成功 
    • a:通过DOS命令,切换到JDK安装的bin目录下。 
      • D:\xuexi\JDK\bin
    • b:然后分别输入javac和java,如果正常显示一些内容,说明安装成功

Java语言基础(JDK安装路径下的目录解释)

  • a:bin目录:该目录用于存放一些可执行程序。 
    • 如javac.exe(java编译器)、java.exe(java运行工具),jar.exe(打包工具)和* javadoc.exe(文档生成工具)等。
  • b:db目录:db目录是一个小型的数据库。 
    • 从JDK 6.0开始,Java中引用了一个新的成员JavaDB,这是一个纯Java实现、开源的数据库管理系统。这个数据库不仅轻便,而且支持JDBC 4.0所有的规范,在学习JDBC 时,不再需要额外地安装一个数据库软件,选择直接使用JavaDB即可。
  • c:jre目录:”jre”是 Java Runtime Environment 的缩写,意为Java程序运行时环境。此目录是Java运行时环境的根目录,它包括Java虚拟机,运行时的类包,Java应用启动器以及一个bin目录,但不包含开发环境中的开发工具。
  • d:include目录:由于JDK是通过C和C++实现的,因此在启动时需要引入一些C语言的头文件,该目录就是用于存放这些头文件的。
  • e:lib目录:lib是library的缩写,意为 Java 类库或库文件,是开发工具使用的归档包文件。
  • f:src.zip文件:src.zip为src文件夹的压缩文件,src中放置的是JDK核心类的源代码,通过该文件可以查看Java基础类的源代码。

ava语言基础(Java开发工具介绍)

  • A:notepad(微软操作系统自带)
  • B:Editplus/Notepad++
  • C:Eclipse
  • D:MyEclipse
  • E:idea

Java概述

基本组成

  1. JDK:Java Development Kit,java的开发和运行环境,java的开发工具和 jre。
  2. JRE:Java Runtime Environment,java 程序的运行环境,java 运行的所需的类库+JVM。
  3. JVM:Java Virtual Machine,是一个虚构出来的计算机,能够屏蔽了与具体平台相关的信息,编译生成在Java虚拟机上运行的目标代码(字节码)。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。
  4. 配置环境变量:使jdk\bin目录下的工具,可以在任意目录下允许,原因是,将所在目录告诉了系统,当使用该工具时,由系统帮我们去找指定的目录

    新建系统变量JAVA_HOME 和CLASSPATH

    变量名:JAVA_HOME

    变量值:C:\Program Files\Java\jdk1.7.0

    变量名:CLASSPATH

    变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

    变量名:Path

    变量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

CLASSPATH

         javac编译器的一个环境变量。它的作用与 import、package关键字有关。编译器面对 import关键字时,就知道要引入 package中的类;但是首先得告诉编译器这个package的所在位置;如何告诉它呢?就是设置 CLASSPATH 啦 :) 如果 java.util 这个 package 在 c:/jdk/ 目录下,你得把 c:/jdk/这个路径设置到 CLASSPATH中去!当编译器面对 importjava.util.*这个语句时,它先会查找 CLASSPATH所指定的目录,并检视子目录 java/util是否存在,然后找出名称吻合的已编译文件(.class 文件)。如果没有找到就会报错!

PATH环境变量

       PATH环境变量。作用是指定命令搜索路径,在命令行下面执行命令如 javac编译 java程序时,它会到 PATH变量所指定的路径中查找看是否能找到相应的命令程序。我们需要把 jdk安装目录下的 bin 目录增加到现有的PATH 变 量中 , bin 目录 中包 含经常要用到的可执行文件 javac/java/javadoc等待,设置好 PATH变量后,就可以在任何目录下执行 javac/java等工具了。

javac命令和 java命令

       要知道 java是分两部分的:一个是编译,一个是运行。

         javac:负责的是编译的部分,当执行 javac 时,会启动 java 的编译器程序。对指定扩展名的.java文件进行编译。 生成了 jvm可以识别的字节码文件。也就是 class文件,也就是 java的运行程序。

          java:负责运行的部分.会启动 jvm.加载运行时所需的类库,并对 class文件进行执行.一个文件要被执行,必须要有一个执行的起始点,这个起始点就是 main函数.

Java基本语法

变量

变量命名

  1. 首字母:字母、下划线“_”、“$”
  2. 其余部分:数字、字母、字母、下划线“_”、“$”
  3. 命名规则:见文知义、驼峰命名法

Java语言基础(关键字的概述和使用)

  • A:什么是关键字 
    • 被Java语言赋予特定含义的单词
  • B:关键字的特点 
    • 组成关键字的字母全部小写
  • C:常见关键字 
    • public static void class等
  • D:关键字的注意事项 
    • goto和const作为保留字存在,目前并不使用,类似Editplus这样的高级记事本,针对关键字有特殊的颜色标记,非常直观

Java语言基础(标识符的概述和组成规则)

  • A:什么是标识符 
    • 就是给类,接口,方法,变量等起名字时使用的字符序列
  • B:标识符的组成规则 
    • 英文大小写字母
    • 数字字符
    • $和_
  • C:标识符注意事项 
    • 1,不能使用关键字
    • 2,不能数字开头

Java语言基础(标识符中常见的命名规则)

  • 见名知意
  • A:包 
    • 最好是域名倒过来,要求所有的字母小写
  • B:类或者接口 
    • 如果是一个单词首字母大写
    • 如果是多个单词每个单词首字母大写(驼峰标识)
  • C:方法或者变量 
    • 如果是一个单词全部小写
    • 如果是多个单词,从第二个单词首字母大写
  • D:常量 
    • 如果是一个单词,所有字母大写
    • 如果是多个单词,所有的单词大写,用下划线区分每个单词

变量的作用域及生命周期

  1. 变量的作用域:

作用域从变量定义的位置开始,到该变量所在的那对大括号结束;

     2. 生命周期:

变量从定义的位置开始就在内存中活了;

变量到达它所在的作用域的时候就在内存中消失了。

Java 内存管理

概述

       对于 Java程序员来说,在虚拟机的自动内存管理机制的帮助下,不再需要为每一个 new操作去写配对的 delete/free代码,而且不容易出现内存泄漏和内存溢出问题,看起来由虚拟机管理内存一切都很美好。不过,也正是因为 Java程序员把内存控制的权力交给了 Java虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那排查错误将会成为一项异常艰难的工作。

运行时数据区域

       Java虚拟机在执行 Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。Java虚拟机所管理的内存将会包括以下几个运行时数据区域

程序计数器

       程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。 由于 Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。 如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Natvie 方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。

Java虚拟机栈

       与程序计数器一样,Java 虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是 Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(StackFrame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。经常有人把 Java 内存区分为堆内存(Heap)和栈内存(Stack),与对象内存分配关系最密切的内存区域是这两块。所指的“栈”就是现在讲的虚拟机栈,或者说是虚拟机栈中的局部变量表部分。局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型),它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置。其中 64 位长度的 long 和 double 类型的数据会占用 2 个局部变量空间(Slot),其余的数据类型只占用 1 个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。 在 Java 虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常;如果虚拟机栈可以动态扩展(当前大部分的 Java 虚拟机都可动态扩展,只不过 Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛OutOfMemoryError 异常。

本地方法栈

       本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的 Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如 Sun HotSpot 虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

Java堆

        对于大多数应用来说,Java 堆(Java Heap)是 Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在 Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配,所有的对象都分配在堆上也渐渐变得不是那么“绝对”了。java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”(Garbage Collected Heap)。存储的是对象实例,,Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出 OutOfMemoryError 异常。

方法区

       方法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。

       Java 虚拟机规范对这个区域的限制非常宽松,除了和 Java 堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。当方法区无法满足内存分配需求时,将抛出 OutOfMemoryError 异常。

运行时常量池

       运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。 Java 虚拟机对 Class 文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。但对于运行时常量池,Java 虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。不过,一般来说,除了保存 Class 文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。 运行时常量池相对于 Class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只能在编译期产生,也就是并非预置入 Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是 String 类的 intern()方法。 既然运行时常量池是方法区的一部分,自然会受到方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。

对象访问

       介绍完 Java 虚拟机的运行时数据区之后,我们就可以来探讨一个问题:在 Java 语言中,对象访问是如何进行的?对象访问在 Java 语言中无处不在,是最普通的程序行为,但即使是最简单的访问,也会却涉及 Java栈、Java 堆、方法区这三个最重要内存区域之间的关联关系,如下面的这句代码:

Object obj = new Object();

       假设这句代码出现在方法体中,那“Object obj”这部分的语义将会反映到 Java 栈的本地变量表中,作为一个reference 类型数据出现。而“new Object()”这部分的语义将会反映到 Java 堆中,形成一块存储了 Object类型所有实例数据值(Instance Data,对象中各个实例字段的数据)的结构化内存,根据具体类型以及虚拟机实现的对象内存布局(Object Memory Layout)的不同,这块内存的长度是不固定的。另外,在 Java 堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法等)的地址信息,这些类型数据则存储在方法区中。由于 reference类型在 Java虚拟机规范里面只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到 Java 堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接指针。 如果使用句柄访问方式,Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息如果使用的是直接指针访问方式,Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference 这两种对象的访问方式各有优势,使用句柄访问方式的最大好处就是 reference 中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而 reference本身不需要被修改。使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在 Java 中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。就本书讨论的主要虚拟机 Sun HotSpot 而言,它是使用第二种方式进行对象访问的,但从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也十分常见。

参考博客:https://blog.csdn.net/echo_1994/article/details/78666868

猜你喜欢

转载自blog.csdn.net/gaofengyan/article/details/84770161