2019版尚硅谷Java入门视频教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1Kb411W75N?p=5
一、Java概述Java基础是学习JavaEE、大数据、Android开发的基石。
1.1 软件开发介绍软件开发
软件,即一系列按照特定顺序组织的计算机数据和指令的集合。有系统软件和应用软件之分。
人机交互方式
图形化界面:GUI(Graphical User Interface):这种方式简单直观,使用者易于接受,容易上手 *** 作。
命令行方式:CLI(Command Line Interface ):需要有一个控制台,输入特定的指令,让计算机完成一些 *** 作。较为麻烦,需要记住一些命令。
常用的DOS命令 dir : 列出当前目录下的文件以及文件夹
md : 创建目录
rd: 删除目录
cd: 进入指定目录
cd… : 退回到上一级目录
cd: 退回到根目录
del: 删除文件
exit : 退出 dos 命令行
1-2 计算机编程语言介绍 计算机语言:人与计算机交流的方式。如果人要与计算机交流,那么就要学习计算机语言。计算机语言有很多种。如:C ,C++ ,Java ,PHP , Kotlin,Python,Scala等。
l 第一代语言
Ø 机器语言。指令以二进制代码形式存在。
l 第二代语言
Ø 汇编语言。使用助记符表示一条机器指令。
l 第三代语言:高级语言
Ø C、Pascal、Fortran面向过程的语言
Ø C++面向过程/面向对象
Ø Java跨平台的纯面向对象的语言
Ø .NET跨语言的平台
Ø Python、Scala…
1-3 Java语言概述l 是SUN(Stanford University Network,斯坦福大学网络公司 ) 1995年推出的一门高级编程语言。
l 是一种面向Internet的编程语言。Java一开始富有吸引力是因为Java程序可以在Web浏览器中运行。这些Java程序被称为Java小程序(applet)。applet使用现代的图形用户界面与Web用户进行交互。 applet内嵌在HTML代中。
l 随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。
l 后台开发:Java、PHP、Python、Go、Node.js
Java简史Ø 1991年 Green项目,开发语言最初命名为Oak (橡树)
Ø 1994年,开发组意识到Oak 非常适合于互联网
Ø 1996年,发布JDK 1.0,约8.3万个网页应用Java技术来制作
Ø 1997年,发布JDK 1.1,JavaOne会议召开,创当时全球同类会议规模之最
Ø 1998年,发布JDK 1.2,同年发布企业平台J2EE
Ø 1999年,Java分成J2SE、J2EE和J2ME,JSP/Servlet技术诞生
Ø 2004年,发布里程碑式版本:JDK 1.5,为突出此版本的重要性,更名为JDK 5.0
Ø 2005年,J2SE -> JavaSE,J2EE -> JavaEE,J2ME -> JavaME
Ø 2009年,Oracle公司收购SUN,交易价格74亿美元
Ø 2011年,发布JDK 7.0
Ø 2014年,发布JDK 8.0,是继JDK 5.0以来变化最大的版本
Ø 2017年,发布JDK 9.0,最大限度实现模块化
Ø 2018年3月,发布JDK 10.0,版本号也称为18.3
Ø 2018年9月,发布JDK 11.0,版本号也称为18.9
Ø 之后每隔半年发布一次
Java技术体系平台 Java在各领域的应用从Java的应用领域来分,Java语言的应用方向主要表现在以下几个方面:
• 企业级应用:主要指复杂的大企业的软件系统、各种类型的网站。Java的安全机制以及它的跨平台的优势,使它在分布式系统领域开发中有广泛应用。应用领域包括金融、电信、交通、电子商务等。
• Android平台应用:Android应用程序使用Java语言编写。Android开发水平的高低很大程度上取决于Java语言核心能力是否扎实。
• 大数据平台开发:各类框架有Hadoop,spark,storm,flink等,就这类技术生态圈来讲,还有各种中间件如flume,kafka,sqoop等等 ,这些框架以及工具大多数是用Java编写而成,但提供诸如Java,scala,Python,R等各种语言API供编程。
• 移动领域应用:主要表现在消费和嵌入式领域,是指在各种小型设备上的应用,包括手机、PDA、机顶盒、汽车通信设备等。
Java主要特性 • Java语言是易学的。Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用Java。
• Java语言是强制面向对象的。Java语言提供类、接口和继承等原语,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为implements)。
• Java语言是分布式的。Java语言支持Internet应用的开发,在基本的Java应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、ServerSocket等。Java的RMI(远程方法激活)机制也是开发分布式应用的重要手段。
•Java语言是健壮的。Java的强类型机制、异常处理、垃圾的自动收集等是Java程序健壮性的重要保证。对指针的丢弃是Java的明智选择。
• Java语言是安全的。Java通常被用在网络环境中,为此,Java提供了一个安全机制以防恶意代码的攻击。如:安全防范机制(类ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查。
• Java语言是体系结构中立的。Java程序(后缀为java的文件)在Java平台上被编译为体系结构中立的字节码格式(后缀为class的文件),然后可以在实现这个Java平台的任何系统中运行。
•Java语言是解释型的。如前所述,Java程序在Java平台上被编译为字节码格式,然后可以在实现这个Java平台的任何系统的解释器中运行。
• Java是性能略高的。与那些解释型的高级脚本语言相比,Java的性能还是较优的。
• Java语言是原生支持多线程的。在Java语言中,线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建。
1-4 Java程序运行机制及运行过程 Java语言的特点特点1.面向对象性:
两个基本概念:类、对象;
三大特性:封装、继承、多态
特点2.健壮性:
吸收了C/C++语言的优点,但去掉了其影响程序健壮性的部分(如指针、内存的申请与释放等),提供了一个相对安全的内存管理和访问机制
Java确实是从C语言和C++语言继承了许多成份,甚至可以将Java看成是类C语言发展和衍生的产物。比如Java语言的变量声明, *** 作符形式,参数传递,流程控制等方面和C语言、C++语言完全相同。但同时,Java是一个纯粹的面向对象的程序设计语言,它继承了C++语言面向对象技术的核心。Java舍弃了C语言中容易引起错误的指针(以引用取代)、运算符重载(operator overloading)、多重继承(以接口取代)等特性,增加了垃圾回收器功能用于回收不再被引用的对象所占据的内存空间。
JDK1.5又引入了泛型编程(GenericProgramming)、类型安全的枚举、不定长参数和自动装/拆箱
特点3.跨平台性:
跨平台性:通过Java语言编写的应用程序在不同的系统平台上都可以运行,Write once , Run Anywhere
原理:只要在需要运行 java 应用程序的 *** 作系统上,先安装一个Java虚拟机 (JVM Java Virtual Machine) 即可。由JVM来负责Java程序在该系统中的运行。
Java两种核心机制 1.Java虚拟机(Java Virtal Machine) JVM是运行在 *** 作系统之上的,它与硬件没有直接的交互。
JVM是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指令,管理数据、内存、寄存器。
只有某平台提供了对应的java虚拟机,java程序才可在此平台运行
对于不同的平台,有不同的虚拟机。
Java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行”。
JVM体系结构概览 类装载器ClassLoader 负责加载class文件,class文件在文件开头有特定的文件标示,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine(执行引擎)决定 ,Execution Engine执行引擎负责解释命令,提交 *** 作系统执行。
虚拟机自带的加载器:
启动类加载器(Bootstrap) C++
扩展类加载器(Extension) Java
应用程序类加载器(App) Java,也叫系统类加载器,加载当前应用的classpath的所有类
用户自定义加载器:
Java.lang.ClassLoader的子类,用户可以定制类的加载方式
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
Native Interface本地方法接口 Java语言本身不能对 *** 作系统底层进行访问和 *** 作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
本地接口的作用是融合不同的编程语言为Java所用,它的初衷是融合 C/C++程序,Java诞生的时候是C/C++横行的时候,要想立足,必须有调用C/C++程序,于是就在内存中专门开辟了一块区域处理标记为Native的代码,它的具体做法是Native Method Stack中登记Native方法,在Execution Engine 执行时加载Native libraries。
目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印机或者Java系统管理生产设备,在企业级应用中已经比较少见。因为现在的异构领域间的通信很发达,比如可以使用Socket通信,也可以使用WebService等等,不多做介绍。
Native Method Stack(本地方法栈) 它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载本地方法库。
PC寄存器 每个线程都有一个程序计数器,是线程私有的就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。
栈 栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就Over,生命周期和线程一致,是线程私有的。基本类型的变量、实例方法、引用类型变量都是在函数的栈内存中分配。
方法区1:方法区是线程共享的,通常用来保存装载的类的元结构信息。比如:运行时常量池+静态变量+常量+字段+方法字节码+在类/实例/接口初始化用到的特殊方法等。
2:通常和永久区关联在一起(Java7之前),但具体的跟JVM的实现和版本有关。
Heap堆(Java7之前) 一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行。
堆内存逻辑上分为三部分:新生+养老+永久
新生区
新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。
新生区又分为两部分: 伊甸区(Eden space)和幸存者区(Survivor pace),所有的类都是在伊甸区被new出来的。
幸存区有两个:0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存0区,若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。那如果1区也满了呢?再移动到养老区。
养老区
若养老区也满了,那么这个时候将产生MajorGC(FullGC),进行养老区的内存清理。若养老区执行了Full GC之后发现依然无法进行对象的保存,就会产生OOM异常OutOfMemoryError。
如果出现java.lang.OutOfMemoryError: Java heap space异常,说明Java虚拟机的堆内存不够。原因有二:
(1)Java虚拟机的堆内存设置不够,可以通过参数-Xms、-Xmx来调整。
(2)代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)。
Java7:
java8(JDK 1.8)之后将最初的永久代取消了,由元空间取代。
2.垃圾收集机制(Garbage Collection)不再使用的内存空间应回收—— 垃圾回收:
在C/C++等语言中,由程序员负责回收无用内存。
Java 语言消除了程序员回收无用内存空间的责任:它提供一种系统级线程跟踪存储空间的分配情况。并在JVM空闲时,检查并释放那些可被释放的存储空间。
垃圾回收在Java程序运行过程中自动进行,程序员无法精确控制和干预。
Java程序还会出现内存泄漏和内存溢出问题吗?Yes!
GC是什么? 为什么要有GC?
GC是垃圾收集的意思(Garbage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃
Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示 *** 作方法。
垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。
可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
Java的内存管理之垃圾回收(了解)
分配:由JVM自动为其分配相应的内存空间
释放:由JVM提供垃圾回收机制自动的释放内存空间
垃圾回收机制(GC:Garbage Collection):将垃圾对象所占用的堆内存进行回收。Java的垃圾回收机制是JVM提供的能力,由单独的系统级垃圾回收线程在空闲时间以不定时的方式动态回收。
垃圾对象:不再被任何引用指向的对象。
问:在程序中是否可以通知垃圾回收机制过来回收垃圾?
能,通过调用System.gc();或Runtime.getRuntime().gc();
再问:调用了System.gc();或Runtime.getRuntime().gc();后是立刻执行垃圾回收吗?
不是,该调用并不会立刻启动垃圾回收机制开始回收,但会加快垃圾回收机制的运行。
public class TestGC{ public static void main(String[] args)throws Exception{ for(int i=0; i<10; i++){ //这里本次循环完,本次创建的对象就成为垃圾了 MyClass m = new MyClass(); System.out.println("创建第" + (i+1) + "的对象:" + m); } //通知垃圾回收机制来收集垃圾 System.gc(); //为了延缓程序结束 for(int i=0; i<10; i++){ Thread.sleep(1); System.out.println("程序在继续...."); } } } class MyClass{ public void finalize(){ System.out.println("轻轻的我走了....."); } }
垃圾回收机制关键点
1.垃圾回收机制只回收JVM堆内存里的对象空间。
2.对其他物理连接,比如数据库连接、输入流输出流、Socket连接无能为力
3.现在的JVM有多种垃圾回收实现算法,表现各异。
4.垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。
5.可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。
6.程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否进行垃圾回收依然不确定。
7.垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)。
8.永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。
1-5 Java语言的环境搭建 1.JDK与JRE的理解jdk(Java Development Kit ,Java开发工具包)
JDK是提供给Java开发人员使用的,其中包含了java的开发工具(编译工具(javac.exe) 打包工具(jar.exe)等),也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。
jre(Java Runtime Environment,Java运行环境)
包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。简单而言,使用JDK的开发工具完成的java程序,交给JRE去运行。
2.JDK、JRE、JVM关系 3.下载并安装JDKl 官方网址:
Øwww.oracle.com
Øjava.sun.com
l 安装JDK
Ø傻瓜式安装,下一步即可。
Ø建议:安装路径不要有中文或者空格等特殊符号。
Ø如果 *** 作系统是64位的,软件尽量选择支持64位的(除非软件本身不区分)。
Ø当提示安装 JRE 时,正常在JDK安装时已经装过了,但是为了后续使用Eclipse等开发工具不报错,建议也根据提示安装JRE。
4.配置环境变量 path每次执行 java 的工具都要进入到bin目录下,是非常麻烦的。可不可以在任何目录下都可以执行java的工具呢?
根据windows系统在查找可执行程序的原理,可以将java工具所在路径定义到path 环境变量中,让系统帮我们去找运行执行的程序。windows系统执行命令时要搜寻的路径。目的是为了在控制台的任何文件路径下,都可以调用jdk指定目录下的所有指令。
配置方法:
Ø我的电脑–属性–高级系统设置–环境变量
Ø编辑 path 环境变量,在变量值开始处加上java工具所在目录,后面用 ;和其他值分隔开即可。
Ø打开DOS命令行,任意目录下敲入javac。如果出现javac 的参数信息,配置成功。
5.classpath java 在编译和运行时要找的 class 所在的路径
如果计算机安装过一些商业化的Java开发产品或带有Java技术的一些产品,安装这些产品后,classpath的值可能会被修改了。如果希望使用最新的Java运行环境,就重新设置 classpath的值。
1-6 开发Java程序— HelloWorld Java程序的基本组成要素Java程序的基本组成要素:运算符和表达式
运算符是一种特殊的符号,用以表示数据的运算,赋值和比较。不同的运算符用来完成不同的运算。
java语言使用运算符将一个或者多个 *** 作数连缀成执行性语句,形成表达式,表达式是由运算符和 *** 作数按一定语法规则组成的符号序列。以下是合法的表达式:
a + b 、 (a + b)*(a - b)
表达式经过运算后都会产生一个确定的值,一个常量或一个变量是最简单表达式。
java开发步骤 (1)编写源文件:扩展名必须是 .java。
(2)编译Java源程序:用Java编译器(javac.exe)编译源文件,得到字节码文件。 如果程序没有错误,没有任何提示,但在当前目录下会出现一个xxx.class文件,该文件称为字节码文件,也是可以执行的java的程序。
(3)运行Java程序:使用Java解释器(java.exe)来解释执行字节码文件。
注意事项Ø Java源文件以java为扩展名
Ø 源文件的基本组成部分(单元)是类(class)
Ø 一个源文件中最多只能有一个public类,其它类的个数不限,如果源文件包含一个public类,则文件名必须按该类名命名。
Ø Java语言严格区分大小写
Ø 一个程序的执行需要一个起始点或者入口,Java应用程序的执行入口是main()方法。它有固定的书写格式:public static void main(String[] args) {...}
Ø 对修改后的xxx.java源文件需要重新编译,生成新的class文件后,再进行执行。
Ø 发现没有编译失败,但也没有任何效果,因为并没有告诉JVM要帮我们做什么事情,也就是没有可以具体执行的语句。
Ø Java方法由一条条语句构成,每个语句以 ;结束。
Ø 大括号都是成对出现的,缺一不可。
Ø java反编译器(javap.exe):将字节码文件转换为源文件。
1-7 常见问题及解决方法 1-8 注释(Comment)用于注解说明解释程序的文字就是注释。
单行注释 格式: //注释文字
多行注释 格式:
注:
对于单行和多行注释,被注释的文字,不会被JVM(java虚拟机)解释执行。
多行注释里面不允许有多行注释嵌套。
文档注释(java特有) 格式:
注释内容可以被JDK提供的工具javadoc所解析,生成一套以网页文件形式体现的该程序的说明文档。
*** 作方式,如生成HelloWorld.java的说明文档:javadoc -d mydoc -author -version HelloWorld.java
1-9 Java API文档 API (Application Programming Interface,应用程序编程接口)是 Java 提供的基本编程接口。
Java语言提供了大量的基础类,因此 Oracle 也为这些基础类提供了相应的API文档,用于告诉开发者如何使用这些类,以及这些类里包含的方法。
1.10 良好的编程风格 1-11 常用的Java开发工具(Integrated Development Environment)文本编辑工具:
Ø 记事本 Ø UltraEdit Ø EditPlus Ø TextPad Ø NotePad
Java集成开发环境(IDE):
Ø JBuilder Ø NetBeans Ø Eclipse Ø MyEclipse Ø IntelliJ IDEA
二、java基本语法 2-1 关键字与保留字 关键字(keyword) Ø 定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词)
Ø 特点:关键字中所有字母都为小写
Ø官方地址: https://docs.oracle.com/javase/tutorial//nutsandbolts/_keywords.html
Ø 现有Java版本尚未使用,但以后版本可能会作为关键字使用。自己命名标记符时要避免使用这些保留字
Ø byValue、cast、future、 generic、 inner、 operator、 outer、 rest、 var 、 goto 、const
2-2 标识符(Identifier)Ø 凡是自己可以起名字的地方都叫标识符
Ø Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符
命名的规则:(一定要遵守,不遵守就会报编译的错误)
Ø 由26个英文字母大小写,0-9 ,_或 $组成
Ø 数字不可以开头。
Ø 不可以使用关键字和保留字,但能包含关键字和保留字。
Ø Java中严格区分大小写,长度无限制。
Ø 标识符不能包含空格。
Java中的名称命名规范:(不遵守,也不会出现编译的错误)
包名:多单词组成时所有字母都小写:xxxyyyzzz
类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz
变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz
常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ
l 注意1:在起名字时,为了提高阅读性,要尽量有意义,见名知意。
l 注意2:java采用unicode字符集,因此标识符也可以使用汉字声明,但是不建议使用。
2-3 变量变量的概念:
Ø 内存中的一个存储区域
Ø 该区域的数据可以在同一类型范围内不断变化
Ø 变量是程序中最基本的存储单元。包含变量类型、变量名和存储的值
Ø 该区域有自己的名称(变量名)和类型(数据类型)
Ø Java中每个变量必须先声明,后使用
变量的作用:
Ø 用于在内存中保存数据
使用变量注意:
Ø 初始化值
Ø Java中每个变量必须先声明,后使用
Ø 使用变量名来访问这块区域的数据
Ø 变量的作用域:其定义所在的一对{ }内
Ø 变量只有在其作用域内才有效
Ø 同一个作用域内,不能定义重名的变量
l声明变量
Ø 语法:<数据类型> <变量名称>
Ø 例如:int var;
l 变量的赋值
Ø 语法:<变量名称> = <值>
Ø 例如:var = 10;
l 声明和赋值变量
Ø 语法: <数据类型> <变量名> = <初始化值>
Ø 例如:int var = 10;
1.成员变量与局部变量变量的分类-按数据类型:
对于每一种数据都定义了明确的具体数据类型(强类型语言),在内存中分配了不同大小的内存空间。
变量的分类-按声明的位置的不同
l 在方法体外,类体内声明的变量称为成员变量。
l 在方法体内部声明的变量称为局部变量。
| 成员变量又分为实例成员变量(简称实例变量)和类变量(也称静态变量)
Ø 成员变量在定义时有默认值,局部变量没有,局部变量只在方法内有效
Ø 如果局部变量的名字与成员变量的名字相同,则成员变量被隐藏,即该成员变量在这个方法内暂时失效,如果想在该方法中使用被隐藏的成员变量,必须使用关键字this
| 成员变量:
成员变量定义在类中,在整个类中都可以被访问。
成员变量分为类变量和实例成员变量,实例成员变量存在于对象所在的堆内存中。
成员变量有默认初始化值。
成员变量的权限修饰符可以根据需要,选择任意一个
| 局部变量:
局部变量只定义在局部范围内,如:方法内,代码块内等。
局部变量存在于栈内存中。
作用的范围结束,变量空间会自动释放。
局部变量没有默认初始化值,每次必须显式初始化。
局部变量声明时不指定权限修饰符
相同点:1.遵循变量声明的格式: 数据类型 变量名 = 初始化值
2.都有作用域
不同点:1.声明的位置的不同 :成员变量:声明在类里,方法外
局部变量:声明在方法内,方法的形参部分,代码块内
2.成员变量的修饰符有四个:public private protected 缺省(default)
3.局部变量没有修饰符,与所在的方法修饰符相同。
4.二者在内存中存放的位置不同:成员变量存在于堆空间中;局部变量:栈空间中
局部变量:局部变量除形参外,需显式初始化。(局部变量没有默认初始化值)
成员变量:如果在声明的时候,不显式的赋值,那么不同数据类型会有不同的默认初始化值。
总结:关于变量的分类:1)按照数据类型的不同:基本数据类型(8种) & 引用数据类型
2)按照声明的位置的不同:成员变量 & 局部变量
2.基本数据类型 1.整数类型:byte、short、int、long java各整数类型有固定的表数范围和字段长度,不受具体OS( *** 作系统)的影响,以保证java程序的可移植性。
java的整型常量默认为 int 型,声明long型常量须后加l 或 L
java程序中变量通常声明为int型,除非不足以表示较大的数,才使用long
byte:内存分配1个字节(byte),占8位(bit),最大存储数据量是255,存放的数据范围是 -128~127 之间,即(-2)^8 ~(2^8)-1。
short:2字节,占16位,最大数据存储量是65536,数据范围是-32768~32767之间。
int:4字节,占32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1
long:8字节,占64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。
2.浮点类型:float、doublel 与整数类型类似,Java 浮点类型也有固定的表数范围和字段长度,不受具体 *** 作系统的影响。
l 浮点型常量有两种表示形式:
Ø 十进制数形式:如:5.12 512.0f .512 (必须有小数点)
Ø 科学计数法形式:如:5.12e2 512E2 100E-2
l float:单精度,可以精确到8位有效数字。很多情况下,精度很难满足需求。
double:双精度,精度是float的两倍。通常采用此类型。
l Java 的浮点型常量默认为double型,声明float型常量,须后加 f 或 F。
float(单精度型):4字节,32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F,float变量在存储时保留8位有效数字。
double(双精度型):8字节,64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加,double变量在存储时保留16位有效数字。
3.字符类型:charl char:2字节,16位,存储Unicode码,用单引号赋值。char 型数据用来表示通常意义上字符
l 字符型变量的三种表现形式:
Ø 字符常量是用单引号(‘ ’)括起来的单个字符,涵盖世界上所有书面语的字符。例如:char c1 = 'a'; char c2 = '中'; char c3 = '9';
Ø Java中还允许使用转义字符‘’来将其后的字符转变为特殊字符型常量。例如:char c3 = ‘n’; 'n'表示换行符
Ø 直接使用 Unicode 值来表示字符型常量:‘uXXXX’。其中,XXXX代表一个十六进制整数。如:u000a 表示 n。
l char类型是可以进行运算的。因为它都对应有Unicode码。
转义字符b:退格符 n:换行符 r:回车符 t:制表符
\":双引号 \':单引号 \:反斜线
4.逻辑类型(布尔型):booleanboolean 类型用来判断逻辑条件,一般用于程序流程控制:
Ø if条件控制语句;
Ø while循环控制语句;
Ø do-while循环控制语句;
Ø for循环控制语句;
boolean类型数据只允许取值true和false,无null
Ø 不可以使用0或非 0 的整数替代false和true,这点和C语言不同。
Ø Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达所 *** 作的boolean值,在编译之后都使用java虚拟机中的int数据类型来代替:true用1表示,false用0表示。———《java虚拟机规范 8版》
5.数据基本类型精度从低到高 byte short char int long float double
注意:String是引用数据类型,不是基本数据类型,String有length()这个方法,而数组没有length()这个方法,同时数组有length的属性。
3.字符串类型:Stringl String不是基本数据类型,属于引用数据类型
l 使用方式与基本数据类型一致。例如:String str = “abcd”;
l 一个字符串可以串接另一个字符串,也可以直接串接其他类型的数据。例如:
str = str + “xyz” ; int n = 100; str = str + n;
值null可以赋值给任何引用类型(类、接口、数组)的变量,用以表示这个引用类型变量中保存的地址为空。而String类属于引用类型,可用null赋值。
String类是一个典型的不可变类,String对象创建出来就不可能被改变。创建出的字符串将存放在数据区,保证每个字符串常量只有一个,不会产生多个副本。
注意:string是字符串类型,而char是字符类型
4.string和char的区别一 char和string的区别: 1 char是表示的是字符,定义的时候用单引号,只能存储一个字符。例如; char='d'. 而String表示的是字符串,定义的时候用双引号,可以存储一个或者多个字符。 例如:String=“we are neuer”。 2 char是基本数据类型,而String是个类,属于引用数据类型。 String类可以调用方法,具有面向对象的特征。 二 char类型 char在Java中是16位(两字节)的,因为Java用的是Unicode。 三 String类型 1 java设计了两种不同的方法来生成字符串对象,一种是使用双引号,一种是调用String类的构造函数。 String str1 = "we are student"; String str2 = new String ("qau neu"); 注:Java为String类型提供了缓冲池机制,当使用双引号定义对象时,Java环境首先去字符串缓冲池 寻找内容相同的字符串,如果存在就拿出来使用,否则就创建一个新的字符串放在缓冲池中。 例如: String S=new String("abc''), 产生(或者创建)几个对象? 答案是:产生一个或者两个对象。如果常量池中原来没有“abc",就产两个对象,如果 字符串常量池中"abc",就产生一个对象。因此,这个问题如果换成 String str = new String("abc")涉及到几个String对象?合理的解释是2个。 1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。 在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。 在这里要永远记住一点:“String对象一旦被创建就是固定不变的了,对String对象的任何改变 都不影响到原对象,相关的任何change *** 作都会生成新的对象”。 2 字符串常量池 我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串 我们使用的非常多。 JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。 每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中, 那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。 由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串(这点对理解上面至关重要)。 Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。 所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量, 还包含类、方法的信息,占用class文件绝大部分空间。 而运行时常量池,则是jvm虚拟机在完成类装载 *** 作后,将class文件中的常量池载入到内存中, 并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。 更多详情请参考:https://blog.csdn.net/qauchangqingwei/article/details/808317975.基本数据类型的封装
Java提供了基本数据类型相关的类,实现了对基本数据类型的封装,Byte、Integer、Short、Long、Float、Double和Character类,这些类在java.lang包中。
1GB=1024MB=1024^2KB=1024^3Byte=1024^3*8bit, 1bit(比特) = 1b(位)
补充:宽带知识 补充:cpu速度CPU的速度一般体现为CPU的时钟频率,而CPU的时钟频率的单位一般是赫兹(hz),赫兹其实就是秒分之一,它是每秒中的周期性变动重复次数的计量
6.基本数据类型初始化值自动类型转换:容量小的类型自动转换为容量大的数据类型。数据类型按容量大小排序为:
有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算,注意:
1.byte,short,char之间不会相互转换,他们三者在计算时首先转换为int类型。
2.boolean类型不能与其它数据类型运算。
3.当把任何基本数据类型的值和字符串(String)进行连接运算时(+),基本数据类型的值将自动转化为字符串(String)类型。
①自动类型转换:容量小的数据类型自动转换为容量大的数据类型。
short s = 12;
int i = s + 2;
注意:byte short char之间做运算,结果为int型!
②强制类型转换:是①的逆过程。使用()实现强转。
隐式类型转换自动类型转换,也称隐式类型转换,是指不需要书写代码,由系统自动完成的类型转换。
转换规则为:从存储范围小的类型到存储范围大的类型。
具体规则为:
short(char、byte)→int→long→float→double
也就是说int类型的变量可以自动转换为long类型,示例代码:int b = 10; long l = b;
显示类型转换(强制类型转换) 自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符:(),但可能造成精度降低或溢出,格外要注意。例如:int x=(int)34.89;,结果x的值变为了34
通常,字符串不能直接转换为基本类型,但通过基本类型对应的包装类则可以实现把字符串转换成基本类型。
Ø 如:String a = “43”; int i = Integer.parseInt(a);
Ø boolean类型不可以转换为其它的数据类型。
8.堆与栈 9.进制所有数字在计算机底层都以二进制形式存在。
对于整数,有四种表示方式:
Ø二进制**(binary)**:0,1 ,满2进1,以0b或0B开头。计算机底层都是用二进制来存储、运算。
Ø八进制**(octal)**:0-7 ,满8进1,以数字0开头表示。
Ø十进制**(decimal)**:0-9 ,满10进1。
Ø十六进制**(hex)**:0-9及A-F,满16进1. 以0x或0X开头表示。此处的A-F不区分大小写。
如:0x21AF +1= 0x21B0
原码、反码、补码Java整数常量默认是int类型,当用二进制定义整数时,其第32位是符号位;当是long类型时,二进制默认占64位,第64位是符号位
二进制的整数有如下三种形式:
Ø原码:直接将一个数值换成二进制数。最高位是符号位
Ø负数的反码:是对原码按位取反,只是最高位(符号位)确定为1(1表示负数,0表示整数)。
Ø负数的补码:其反码加1。
计算机以二进制补码的形式保存所有的整数。
Ø正数的原码、反码、补码都相同
Ø负数的补码是其反码+1
原码:直接将一个数值换成二进制数。
反码:是对原码按位取反,只是最高位(符号位)确定为1。
计算机底层都以补码的方式来存储数据!
为什么要使用原码、反码、补码表示形式呢?
计算机辨别符号位显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0, 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了。
10.ASCII 码 在计算机内部,所有数据都使用二进制表示。每一个二进制位(bit)有 0 和 1 两种状态,因此 8 个二进制位就可以组合出 256 种状态,这被称为一个字节(byte)。一个字节一共可以用来表示 256 种不同的状态,每一个状态对应一个符号,就是 256 个符号,从 0000000到 11111111。
ASCII码:上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码。ASCII码一共规定了128个字符的编码,比如空格SPACE是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。
缺点:
不能表示所有字符。
相同的编码表示的字符不一样:比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג)
11.Unicode 编码Java语言使用Unicode标准字符集,最多可以识别65536个字符
乱码:世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。
Unicode:一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,使用 Unicode 没有乱码的问题。
Unicode 的缺点:Unicode 只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储:无法区别 Unicode 和 ASCII:计算机无法区分三个字节表示一个符号还是分别表示三个符号。另外,我们知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储空间来说是极大的浪费。
UTF-8UTF-8 是在互联网上使用最广的一种 Unicode 的实现方式。
UTF-8 是一种变长的编码方式。它可以使用 1-6 个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8的编码规则:
对于单字节的UTF-8编码,该字节的最高位为0,其余7位用来对字符进行编码(等同于ASCII码)。
对于多字节的UTF-8编码,如果编码包含 n 个字节,那么第一个字节的前 n 位为1,第一个字节的第 n+1 位为0,该字节的剩余各位用来对字符进行编码。在第一个字节之后的所有的字节,都是最高两位为"10",其余6位用来对字符进行编码。
2-4 运算符运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
分为算术运算符、赋值运算符、比较运算符(关系运算符)、逻辑运算符、位运算符、三元运算符
1.算术运算符:+ - * / % ++ –
算术运算符的注意问题 如果对负数取模,可以把模数负号忽略不记,如:5%-2=1。 但被模数是负数则不可忽略。此外,取模运算的结果不一定总是整数。
对于除号/,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。
例如:int x=3510;x=x/1000*1000; x的结果是3000
另外,+除了有字符串相加功能外,还能把非字符串转换成字符串.例如:System.out.println(“5+5=”+5+5); 打印结果是 5+5=55
2.赋值运算符:= += -= *= /= %= Ø当=两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理。
Ø支持连续赋值。
3.比较运算符(关系运算符):== !> > < >= <= instanceofØ比较运算符的结果都是boolean型,也就是要么是true,要么是false。
Ø比较运算符==不能误写成= 。
== 与 = 区别。 进行比较运算 *** 作以后,返回一个boolean类型的值
4>=3 表达的是4 > 3或者 4 = 3。结果是true。
if(i > 1 && i < 10){ } 不能写为:if(1 < i < 10){}
4.逻辑运算符(运算符的两端是boolean值):& && | || ^ !逻辑运算符用于连接布尔型表达式,在Java中不可以写成3
单&时,左边无论真假,右边都进行运算;
双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
|和||的区别同理,||表示:当左边为真,右边不参与运算。
逻辑异或( ^ )与逻辑或(| )的不同之处是:当左右都为true时,结果为false。理解:异或,追求的是异!
5.位运算符(两端是数值类型的数据):<< >> >>> & | ^ ~ 6.三元运算符(条件运算符or三目运算符) 单目运算符单目运算符是指运算所需变量为一个的运算符,又叫一元运算符,其中有
逻辑非运算符:!
按位取反运算符:~
自增自减运算符:++, –等
负号运算符:-
类型转换运算符:(类型)
指针运算符和取地址运算符:*和&
长度运算符:sizeof
双目运算符双目运算符就是对两个变量进行 *** 作
初等运算符: 下标运算符【[]】、分量运算符的指向结构体成员运算符【->】、结构体成员运算符【.】
算术运算符 : 乘法运算符【*】、除法运算符【/】、取余运算符【%】 、加法运算符【+】、减法运算符【-】
关系运算符 : 等于运算符【==】、不等于运算符【!=】 、关系运算符【< > <= >= 】
逻辑运算符 : 逻辑与运算符【&&】 、逻辑或运算符【||】、逻辑非运算符【!】
位运算符 : 按位与运算符【&】、按位异或运算符【^】 、按位或运算符【|】、左移动运算符【<<】、右移动运算符【>>】
赋值运算符 : 赋值运算符【= += -= *= /= %= >>= <<= &= |= ^=】
逗号运算符 : 逗号运算符【,】
7.运算符的优先级注意:只有单目运算符、三元运算符、赋值运算符是从右向左运算的。
2-5 程序流程控制• 流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。
其流程控制方式采用结构化程序设计中规定的三种基本流程结构,即:
Ø顺序结构:程序从上到下逐行地执行,中间没有任何判断和跳转。
Ø分支结构:Ø根据条件,选择性地执行某段代码。
Ø有if…else和switch-case两种分支语句。
Ø循环结构:Ø根据循环条件,重复性的执行某段代码。
Ø有while、do…while、for三种循环语句。
Ø注:JDK1.5提供了foreach循环,方便的遍历集合、数组元素。
1.顺序结构 2.分支结构 1.if语句三种格式(if-else结构)使用说明:
l 条件表达式必须是布尔表达式(关系表达式或逻辑表达式)、布尔变量
l 语句块只有一条执行语句时,一对{}可以省略,但建议保留
l if-else语句结构,根据需要可以嵌套使用
l 当if-else结构是多选一时,最后的else是可选的,根据需要可以省略
l 当多个条件是互斥关系时,条件判断语句及执行语句间顺序无所谓
l 当多个条件是包含关系时,小上大下 / 子上父下
2.switch-case结构switch语句有关规则
l switch(表达式)中表达式的值必须是下述几种类型之一:byte,short,char,int,枚举 (jdk 5.0),String (jdk 7.0);
l case子句中的值必须是常量,不能是变量名或不确定的表达式值,且所有case子句中的值应是不同的;
l 同一个switch语句,所有case子句中的常量值互不相同;
l break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到switch结尾
l default子句是可任选的。同时,位置也是灵活的。当没有匹配的case时,执行default
l break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到switch结尾
l case后只能填写变量的值,不能写范围。
l default是可以省略的。并且其位置也是灵活的,但是通常将其放在case语句之后。
l 一旦满足某个case语句,则进入执行其 *** 作。直至遇到break或者程序终止。
l 若要判断的语句的条件满足switch变量的数据类型,且值不多的情况下,建议选择switch-case。除此之外,选择if-else.
3.switch和if语句的对比Ø 如果判断的具体数值不多,而且符合byte、short 、char、int、String、枚举等几种类型。虽然两个语句都可以使用,建议使用swtich语句。因为效率稍高。
Ø 其他情况:对区间判断,对结果为boolean类型判断,使用if,if的使用范围更广。也就是说,使用switch-case的,都可以改写为if-else。反之不成立。
3.循环结构在某些条件满足的情况下,反复执行特定代码的功能
注:1.不同的循环结构之间可以相互转换
2.while和do-while的区别:do-while程序至少会执行一次
3.嵌套循环:循环结构还可以声明循环。让内层循环结构整体充当外层循环的循环体。若外层循环执行m次,内层循环执行n次,整个程序执行m*n次。
1.for循环 2.while循环 3.do-while循环
4.无限循环结构for(;;){ ... if( ){ break; } ... } 或者 while(true){ ... if( ){ break; } ... }
往往我们在无限循环结构内部提供循环的终止条件,使用break关键字。否则,此循环将无限制的执行下去,形成死循环!死循环是我们要避免的。
5.嵌套循环(多重循环) 6.特殊关键字的使用:break&continue7.特殊流程控制语句3:return
1.并非专门用于结束循环的,它的功能是结束一个方法。当一个方法执行到一个return语句时,这个方法将被结束。
2.与break和continue不同的是,return直接结束整个方法,不管这个return处于多少层循环之内
8.特殊流程控制语句说明 1.break只能用于switch语句和循环语句中。continue 只能用于循环语句中。二者功能类似,但continue是终止本次循环,break是终止本层循环。
2.break、continue之后不能有其他的语句,因为程序永远不会执行其后的语句。
3.标号语句必须紧接在循环的头部,标号语句不能用在非循环语句的前面。
4.很多语言都有goto语句,goto语句可以随意将控制转移到程序中的任意一条语句上,然后执行它。但使程序容易出错。Java中的break和continue是不同于goto的。
三、数组 3-1 数组的概述l 数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
l 数组的常见概念
Ø 数组名
Ø 下标(或索引)
Ø 元素
Ø 数组的长度
l 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。
l 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址。
l 数组的长度一旦确定,就不能修改。
l 数组属引用类型,数组型数据是对象(object),数组中的每个元素相当于该对象的成员变量。
l 创建数组后,系统会给数组的每个元素一个默认的值。
l 数组属于引用型变量,两个相同类型的数组如果具有相同的引用,它们就有完全相同的元素。
l 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
l 数组的分类:
Ø 按照维度:一维数组、二维数组、三维数组、…
Ø 按照元素的数据类型分:基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)
内存的基本结构内存划分的结构:
栈(stack):局部变量 、对象的引用名、数组的引用名
堆(heap):new 出来的“东西”(如:对象的实体,数组的实体),含成员变量
方法区:含字符串常量
静态域:声明为static的变量
3-2 一维数组的使用 1.声明 2.一维数组初始化 动态初始化数组声明且为数组元素分配空间与赋值的 *** 作分开进行
静态初始化在定义数组的同时就为数组元素分配空间并赋值。
3.数组元素的默认初始化值 4.数组元素的引用 3-3 多维数组的使用l Java 语言里提供了支持多维数组的语法。
l 对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组。
遍历二维数组for(int i = 0;i < arr.length;i++){ for(int j = 0;j < arr[i].length;j++){ System.out.print(arr[i][j] + "t"); } System.out.println(); }3-4 数组中涉及到的常见算法
1. 数组元素的赋值(杨辉三角、回形数等)
2. 求数值型数组中元素的最大值、最小值、平均数、总和等
3. 数组的复制、反转、查找(线性查找、二分法查找)
4. 数组元素的排序算法
排序算法分类 Ø 内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序 *** 作都在内存中完成。
Ø 外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成。
十大内部排序算法l 选择排序
Ø 直接选择排序、堆排序
l 交换排序
Ø 冒泡排序、快速排序
l 插入排序
Ø 直接插入排序、折半插入排序、Shell排序
l 归并排序
l 桶式排序
l 基数排序
算法的五大特征 3-5 Arrays工具类的使用java.util.Arrays类即为 *** 作数组的工具类,包含了用来 *** 作数组(比如排序和搜索)的各种方法。Arrays拥有一组static方法。
System.arraycopy():array的复制。
java.util.Arrays类的sort()方法提供了数组元素排序功能:
import java.util.Arrays; public class SortTest { public static void main(String[] args) { int [] numbers = {5,900,1,5,77,30,64,700}; Arrays.sort(numbers); for(int i = 0; i < numbers.length; i++){ System.out.println(numbers[i]); } } }3-6 数组使用中的常见异常 数组脚标越界异常(ArrayIndexOutOfBoundsException) 空指针异常(NullPointerException) 源码获取
至此,我们的Java的学习(上)就讲解完成了。中篇我们将介绍面向对象、异常处理、多线程、常用类、枚举类与注解,源码素材可以通过关注我的微信公众号 我爱学习呀嘻嘻 ,回复关键字Java的学习源码素材进行获取哦。
Java的学习(中):面向对象、异常处理、多线程、Java常用类、枚举类与注解
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)