导图社区 Java基础
Java基础知识点,内容包括:计算机基础知识、JAVA语言概述、Java中的常量及进制、运算符、键盘录入数据、流程控制语句等相关知识点。整理了好长一段时间,发布的第一个作品,希望大家喜欢!
编辑于2020-11-26 11:18:25Java基础
第一部分:计算机基础知识
1. 计算机概述(了解)
1.1. 计算机组成
计算机(Computer)全称:电子计算机,俗称电脑。计算机由硬件和软件所组成。 应用举例: l 科学计算 l 数据处理 l 自动控制 l 计算机辅助设计 l 人工智能 l 多媒体应用 计算机网络
1.2. 计算机硬件
计算机硬件(Computer Hardware)是指计算机系统中由电子,机械和光电元件等组成的各种物理装置的总称。 冯·诺依曼型体系结构的计算机硬件系统的五大部件: 1) 运算器 2) 控制器 3) 存储器 4) 输入设备 5) 输出设备 运算器和控制器是计算机的核心,合称中央处理单元(Central Processing Unit,CPU)或处理器。 输入设备(如键盘、鼠标)和输出设备(如显示器、打印机)统称为外部设备,简称外设或I/O设备,用来实现人机交互和机间通信。
1.3. 计算机软件
计算机软件(Computer Software)是使用计算机过程中必不可少的东西,计算机软件可以使计算机按照事先预定好的顺序完成特定的功能。 计算机软件按照其功能划分为: l 系统软件:DOS(Disk Operating System), Windows, Linux, Unix, Mac, Android, iOS等。 DOS系统是命令行方式操作的操作系统,为了便于用户操作,后来产生了图形化界面操作的操作系统,也就是Windows系统。 应用软件:office,QQ聊天,扫雷等 l 
2. 软件开发和计算机语言概述(了解)
2.1. 软件开发
l 软件:按照特定顺序组织的计算机数据和指令的集合。 备注: 1、数据就是指现实生活中的年龄、姓名等信息。 2、指令就是告诉计算机如何对数据进行处理。 l 开发:软件的制作过程。 l 软件开发:借助开发工具与计算机语言制作软件。
2.2. 计算机语言
2.2.1. 计算机语言概述
人与计算机之间进行信息交流沟通的一种特殊语言。
2.2.2. 计算机语言分类
2.2.2.1. 机器语言
机器语言是直接用二进制代码指令表达的计算机语言,指令是用0和1组成的一串代码,它们有一定的位数,并分成若干段,各段的编码表示不同的含义。 计算机能够直接识别的语言就是机器语言。
2.2.2.2. 汇编语言
汇编语言是使用一些特殊的符号来代替机器语言的二进制码,计算机不能直接识别,需要用一种软件将汇编语言翻译成机器语言。
2.2.2.3. 高级语言
使用普通英语进行编写源代码,通过编译器将源代码翻译成计算机直接识别的机器语言,之后再由计算机执行。 高级语言包括C,C++,C#,JAVA。 l 高级语言工作原理 
3. 人机交互(了解)
3.1. 图形化界面方式
图形化界面方式特点:简单直观,使用者易于接受,容易上手操作。
3.2. 命令行方式
命令行方式特点:需要有一个控制台,输入特定的指令,让计算机完成一些操作。较为麻烦,需要记录住一些命令
4. 键盘功能键和快捷键【掌握】
5. 如何打开DOS控制台【掌握】
以Win7为例,如何打开DOS控制台? l 方式1:开始菜单——点击所有程序——找到附件——命令提示符 l 方式2:开始菜单——搜索程序和文件——输入cmd——回车 l 方式3:windows键 + R ——输入cmd——回车 【推荐方式】
6. 常用DOS命令【掌握】
早期操作计算机用DOS命令操作,因为需要记住很多命令,不利于普及,后期发展成图形界面,通过鼠标点击界面的形式操作计算机,底层实际上运行的依然是DOS命令。 1) 盘符:回车 切换盘符,如d: 2) dir回车 列出当前目录下的文件以及文件夹(dir-->directory) 3) cd 文件夹名称回车 进入指定目录(cd-->change directory) 4) cd..回车 返回到上一级目录 5) cd\回车 返回到根目录 6) cls回车 清屏(clear screen) 7) exit回车 退出dos命令行 注:目录就是指文件夹。 -------------------------分割线上的需要掌握,下方的了解即可----------------------- md 文件夹名回车,创建文件夹(make directory) rd 文件夹名称回车,删除文件夹(remove directory),注意:空文件夹才能直接删除成功 del 文件名称.后缀名回车,删除指定文件;删除当前目录下的一类文件:del *.后缀名回车 notepad 创建文件 删除带内容的文件夹: rd + /s 文件夹名称(询问是否删除) rd + /q + /s 文件夹名称(直接删除) 【补充】: l Tab 书写补全功能 l help 查看DOS命令 l ↑↓上下键 可以切换之前执行过的DOS命令 l ipconfig 查看IP地址 l ipconfig -all 查看笔记本网卡物理地址即mac地址(公司需要绑定mac地址) l ping IP地址 测试IP地址的网络是否正常收发消息
第二部分:Java语言概述
1. Java语言概述(了解)
1.1. Java语言发展史
l 1991年,在SUN公司(StanfordUniversityNetwork,斯坦福大学网络公司),由詹姆斯·高斯林(James Gosling,Java之父)等人开发一套开发语言,并将其命名为“oak”; l 1994年,oak更名为java; l 2009年,sun公司被oracle公司收购。 于是现在为止Java产品属于oracle公司。
1.2. java语言版本
l JDK 1.1.4 Sparkler 宝石 l ...... l JAVASE 5.0 (1.5.0) Tiger 老虎 l JAVASE 6.0 (1.6.0) Mustang 野马 l JAVASE 7.0 (1.7.0) Dolphin 海豚 l JAVASE 8.0 (1.8.0) 目前的最新版本
1.3. Java语言平台
1.3.1. J2SE标准版(Java 2 Platform Standard Edition)
是为开发普通桌面和商务应用程序提供的解决方案。 该技术体系是其他两者的基础,可以完成一些桌面应用程序的开发,如java版的扫雷
1.3.2. J2ME小型版(Java 2 Platform Micro Edition)
是为开发电子消费产品和嵌入式设备提供的解决方案。 该技术体系主要应用于小型电子消费类产品,如手机中的应用程序等。
1.3.3. 企业版(Java 2 Platform Enterprise Edition)
是为开发企业环境下的应用程序提供的一套解决方案。 该技术体系中包含的技术如 Servlet、Jsp等,主要针对于Web应用程序开发。 注意: Java5.0版本后,三种技术平台分别更名为JAVASE、JAVAME、JAVAEE。 由于现在已经出现了Android、IOS、WindowsPhone等手机操作系统,所以J2ME架构基本上已经不用了。目前,流行的手机软件都是基于这些最新的手机操作系统进行开发的。
1.4. Java语言的特点
简单性 解释性 面向对象 高性能 分布式处理 多线程 健壮性 动态 结构中立 安全性 开源 跨平台 补充:java还有内存优化和垃圾回收机制。
1.4.1. 简单性
1.4.2. 解释性
1.4.3. 面向对象
1.4.4. 高性能
1.4.5. 分布式处理
1.4.6. 多线程
1.4.7. 健壮性
1.4.8. 动态
1.4.9. 结构中立
1.4.10. 安全性
1.4.11. 开源
1.4.12. 跨平台
1.4.13. java还有内存优化和垃圾回收机制
2. Java语言跨平台原理【掌握】
2.1. 什么是跨平台性
通过Java语言编写的应用程序在不同的操作系统平台中都可以运行。
2.2. Java语言跨平台原理
只要在需要运行java应用程序的操作系统上,先安装一个Java虚拟机(JVM Java Virtual Machine)即可。由JVM来负责Java程序在该系统中的运行。比如:Java程序需要在Linux操作系统上运行,需要在Linux操作系统上安装一个Linux版本的Java虚拟机,这样就可以运行Java程序了。不用修改源代码。 
2.3. Java语言跨平台图解
write once ,run anywhere!(一次编译,到处运行)。 因为有了JVM,所以同一个Java程序在不同的操作系统中都可以执行。这样就实现了Java程序的跨平台性。也称为Java具有良好的可移植性。 
2.4. 注意事项
l JVM是不跨平台的,对于不同的操作系统有不同版本的JVM。 l JVM的作用就是搭建了Java语言编写的程序与操作系统之间的桥梁。
3. JRE和JDK的概述【掌握】
3.1. JRE(Java运行环境)
JRE(JavaRuntimeEnvironment,Java运行环境): l 包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等。 如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。 l JRE:JVM + 类库。
3.2. JDK(Java开发工具包)
JDK(JavaDevelopmentKit,Java开发工具包): l JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。 所以安装了JDK,就不用在单独安装JRE了。 l 其中的开发工具:编译工具(javac.exe)、运行工具(java.exe)、打包工具(jar.exe)等 l 简单而言:使用JDK开发完成的java程序,交给JRE去运行。 l JDK:JRE + JAVA的开发工具。
3.2.1. JDK安装路径下的目录解释(了解)
l bin目录:该目录用于存放一些可执行程序。如javac.exe(java编译器)、java.exe(java运行工具),jar.exe(打包工具)和javadoc.exe(文档生成工具)等。 l db目录:db目录是一个小型的数据库。从JDK 6.0开始,Java中引用了一个新的成员JavaDB,这是一个纯Java实现、开源的数据库管理系统。这个数据库不仅轻便,而且支持JDBC 4.0所有的规范,在学习JDBC 时,不再需要额外地安装一个数据库软件,选择直接使用JavaDB即可。 l jre目录:"jre"是 Java Runtime Environment 的缩写,意为Java程序运行时环境。此目录是Java运行时环境的根目录,它包括Java虚拟机,运行时的类包,Java应用启动器以及一个bin目录,但不包含开发环境中的开发工具。 l include目录:由于JDK是通过C和C++实现的,因此在启动时需要引入一些C语言的头文件,该目录就是用于存放这些头文件的。 l lib目录:lib是library的缩写,意为 Java 类库或库文件,是开发工具使用的归档包文件。 l src.zip文件:src.zip为src文件夹的压缩文件,src中放置的是JDK核心类的源代码,通过该文件可以查看Java基础类的源代码。
3.2.2. JDK的下载和安装过程图解(了解)
第三部分:HelloWorld案例以及环境变量的配置
1. HelloWorld案例的编写和运行【掌握】
首先,JAVA_HOME/bin目录中创建文本文档,命名HelloWorld,扩展名java,编写代码: ① 定义类:class 类名{} ② 写main方法:public static void main(String [] args){ } ③ 写输出语句:System.out.println("hello world"); ④ 编译:DOS控制台javac编译java文件(带后缀名),产生class字节码文件 ⑤ 运行:DOS控制台java运行class字节码文件(不带后缀名),就在控制台上输出HelloWorld class HelloWorld { public static void main(String[] args) { System.out.println("HelloWorld"); } } 图解:  l 首先编写java源代码程序,扩展名.java l 在命令行模式中,输入javac命令对源代码进行编译,生成字节码文件 编译命令:javac 源文件名.java javac命令的作用是对java程序进行语法性检查,一旦出错,就会打印出错误信息。 l 编译完成后,如果没有报错信息,输入java命令对class字节码文件进行解释运行,执行时不需要添加.class扩展名 运行命令:java 类名 注意:一旦我们修改了.java文件内容,一定要再次编译该文件,再运行。否则运行的还是之前的。 在jdk安装目录下的bin目录,按住shift + 鼠标右键,在该目录下可以直接打开DOS控制台,控制台直接就在该目录下。  注意:文件名和类名可以不一样,编译后生成字节码文件是以类名来命名文件的,即类名.class,但当主方法所在类class前有修饰符public时,则文件名和类名必须一致。 建议:类名和文件名保持一致。这样在编译和运行时直接使用文件名即可。
2. HelloWorld案例常见问题【掌握】
3. Java语言的书写格式(约定俗成)【掌握】
① 大括号要对齐,并且成对写【特别注意】 ② 左大括号前面有空格 ③ 遇到左大括号要缩进,Tab ④ 方法和程序块之间加空行让程序看起来清晰 ⑤ 并排语句之间加空格,例如for语句 ⑥ 运算符两侧加空格 class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } public static void show() { System.out.println(1 + 3); } }
4. path环境变量的作用及配置方式【掌握】
4.1. path环境变量的作用
1) 在JDK的bin目录下开发程序容易产生的问题 l 如果文件过多,不方便管理; l 删除自己写过的不需要的文件,可能不小心把JDK自带的工具给删除了。 2) 如何解决问题呢 notepad这样的命令为什么在任何路径下都能够执行,原因是配置path环境变量。 path配置的是可执行的文件.exe,配置后可以在不同的盘符下访问path路径下的这些可执行文件。
4.2. Path环境变量的配置方式1
右键点击桌面计算机→选择属性→选择高级系统设置→选择高级选项卡→点击环境变量→下方系统变量中查找path→双击path→将jdk安装目录下的bin目录添加到最左边并添加分号。 注意:分号是英文半角符号。
4.3. Path环境变量的配置方式2【掌握*】
1) 先新建一个系统变量JAVA_HOME:复制Java安装路径(能看到bin文件夹) 2) 再修改path:在Path路径中,在最前边添加动态获取Java环境变量:%JAVA_HOME%\bin; 3) 最后说一下path中配置的路径是有先后顺序关系的,所以将java的路径放在前边,优先检索。 注意分号:英文输入法下分号
第四部分:注释、关键字、标识符
1. 注释概述及其分类【掌握】
1.1. 注释概述
用于解释程序的文字就是注释。 注释是给人看的。提高代码的阅读性。 注释是一个程序员必须要具有的良好编程习惯。 初学者编写程序可以养成习惯:先写注释再写代码。 将自己的思想通过注释先整理出来,再用代码去体现。 因为代码仅仅是思想的一种体现形式而已。
1.2. 注释分类
1.2.1. 单行注释
格式://注释内容 举例: 
1.2.2. 多行注释
格式: /* 注释内容 注释内容 注释内容 */ 举例: 
1.2.3. 文档注释
格式: /** 注释内容 注释内容 注释内容 */ java中特有注释,通过工具可将文档注释内容,生成html说明文档。 注: 1:对于单行和多行注释,被注释的文字,不会被JVM(java虚拟机)解释执行。 2:对于文档注释,是java特有的注释,其中注释内容可以被JDK提供的工具 javadoc 所解析, 生成一套以网页文件形式体现的该程序的说明文档。
1.3. 注释作用
l 注释解释说明程序代码含义; l 调试程序: 当程序运行报错时,将某些代码注释掉,然后重新编译,运行。 如果程序不再报错,那么说明注释掉的部分代码中包含错误代码。
1.4. 注释嵌套
l 单行注释可以嵌套单行注释。  l 多行注释不可以嵌套多行注释。  因为多行注释的开头会和被嵌套的多行注释的结尾配对,导致后面的注释失效。 多行注释中可以有单行注释。
1.5. Javadoc 使用详解
2. 关键字的概述和使用【掌握】
1.1 什么是关键字 被Java语言赋予特定含义的单词 。 1.2 关键字的特点 组成关键字的字母全部小写 。 1.3 常见关键字 对于关键字,会随着我们的学习逐渐掌握,不需要死记硬背。   1.4 关键字注意事项 l goto和const作为保留字存在,目前并不使用,在JDK的新版本中可能提升为关键字; l 类似Editplus这样的高级记事本,针对关键字有特殊的颜色标记,非常直观。 1.5 案例:判断下列哪些是关键字 class,HelloWorld,public,static,void,main,String,System? 答:class,public,static,void。
2.1. 用于定义数据类型的关键字
2.1.1. class
2.1.2. interface
2.1.3. byte
2.1.4. short
2.1.5. int
2.1.6. long
2.1.7. float
2.1.8. double
2.1.9. char
2.1.10. boolean
2.1.11. void
2.2. 用于定义数据类型值的关键字
2.2.1. true
2.2.2. false
2.2.3. null
2.3. 用于定义流程控制的关键字
2.3.1. if
2.3.2. else
2.3.3. switch
2.3.4. case
2.3.5. default
2.3.6. while
2.3.7. do
2.3.8. for
2.3.9. break
2.3.9.1. break的使用场景
a. 在选择结构switch语句中 b. 在循环语句中 c. 离开使用场景的存在是没有意义的
2.3.9.2. break作用
跳出循环,即退出当前循环。
2.3.9.3. 案例
class Demo1_Break { public static void main(String[] args) { //break;写在这报错,break只能用在循环和switch语句中 for (int x = 1;x <= 10 ;x++ ) { if (x == 4) { break; //跳出循环 } System.out.println("x = " + x); } } }
2.3.9.4. 控制跳转语句练习【掌握】
l 练习题: for(int x=1; x<=10; x++) { if(x%3==0) { //在此处填写代码 } System.out.println(“Java基础班”); } 我想在控制台输出2次:“Java基础班“ 我想在控制台输出7次:“Java基础班“ 我想在控制台输出13次:“Java基础班“ class Test1 { public static void main(String[] args) { for(int x=1; x<=10; x++) { if(x%3==0) { //break; //我想在控制台输出2次:“Java基础班“ //continue; //我想在控制台输出7次:“Java基础班“ System.out.println("Java基础班"); //我想在控制台输出13次:“Java基础班“ } System.out.println("Java基础班"); } } }
2.3.10. continue
2.3.10.1. continue的使用场景
只能在循环中
2.3.10.2. continue作用
退出本次循环,继续下次循环
2.3.10.3. 案例
class Demo2_Continue { public static void main(String[] args) { for (int x = 1;x <= 10 ;x++ ) { if (x == 4) { continue; //终止本次循环,继续下次循环 } System.out.println("x = " + x); } } }
2.3.10.4. 控制跳转语句练习【掌握】
l 练习题: for(int x=1; x<=10; x++) { if(x%3==0) { //在此处填写代码 } System.out.println(“Java基础班”); } 我想在控制台输出2次:“Java基础班“ 我想在控制台输出7次:“Java基础班“ 我想在控制台输出13次:“Java基础班“ class Test1 { public static void main(String[] args) { for(int x=1; x<=10; x++) { if(x%3==0) { //break; //我想在控制台输出2次:“Java基础班“ //continue; //我想在控制台输出7次:“Java基础班“ System.out.println("Java基础班"); //我想在控制台输出13次:“Java基础班“ } System.out.println("Java基础班"); } } }
2.3.11. return
2.3.11.1. return的作用
a. 返回的意思 b. 其实它的作用不是结束循环的,而是结束方法的。
2.3.11.2. 案例
return和break以及continue的区别? ① return是结束方法 ② break是跳出循环 ③ continue是终止本次循环继续下次循环 class Demo4_Return { public static void main(String[] args) { for (int i = 1;i <= 10 ;i++ ) { if (i == 4) { //break; //停止循环 return; //返回的意思,用来返回方法 } } System.out.println("循环结束了"); } }
2.4. 用于定义访问权限修饰符的关键字
2.4.1. private
2.4.1.1. private的含义
1. private是一个权限修饰符,代表最小权限。 2. 可以修饰成员变量和成员方法。 3. 被private修饰后的成员变量和成员方法,只在本类中才能访问。
2.4.1.2. private的使用格式
private 数据类型 变量名 ; 1. 使用 private 修饰成员变量,代码如下: public class Student { //成员变量 public String name; //姓名 public int age; //年龄 } 2. 提供 getXxx 方法 / setXxx 方法,可以访问成员变量,代码如下: public class Student { //成员变量 public String name; //姓名 public int age; //年龄 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
2.4.2. protected
2.4.3. public
2.4.4. default
2.4.5. 权限修饰符
2.4.5.1. 概述
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限, public:公共的。 protected:受保护的 default:默认的 private:私有的
2.4.5.2. 不同权限的访问能力
2.2 不同权限的访问能力 可见,public具有最大权限。private则是最小权限。 编写代码时,如果没有特殊的考虑,建议这样使用权限: 成员变量使用 private ,隐藏细节。 构造方法使用 public ,方便创建对象。 成员方法使用 public ,方便调用方法。 小贴士:不加权限修饰符,其访问能力与default修饰符相同 
2.5. 用于定义类,函数,变量修饰符的关键字
2.5.1. abstract
2.5.1.1. abstract使用格式
2.5.1.1.1. 抽象方法
使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。 定义格式: 修饰符 abstract 返回值类型 方法名 (参数列表); 代码举例: public abstract void run();
2.5.1.1.2. 抽象类
如果一个类包含抽象方法,那么该类必须是抽象类。 定义格式: abstract class 类名字 { } 代码举例: public abstract class Animal { public abstract void run(); }
2.5.1.1.3. 抽象的使用
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父 类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。 代码举例: public abstract class Animal { public abstract void run(); } public class Cat extends Animal { public void run (){ System.out.println("小猫在墙头走~~~"); } } public class CatTest { public static void main(String[] args) { // 创建子类对象 Cat c = new Cat(); // 调用run方法 c.run(); } } 输出结果: 小猫在墙头走~~~ 此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法。
2.5.2. final
2.5.2.1. 概述
学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承 API中提供的类,改写其内容呢?显然这是不合适的。为了避免这种随意改写的情况,Java提供了 final 关键字, 用于修饰不可改变内容。 fifinal: 不可改变。可以用于修饰类、方法和变量。 类:被修饰的类,不能被继承。 方法:被修饰的方法,不能被重写。 变量:被修饰的变量,不能被重新赋值。
2.5.2.2. 使用方式
2.5.2.2.1. 修饰类
格式如下: final class 类名 { } 查询API发现像 public final class String 、 public final class Math 、 public final class Scanner 等,很多我们学习过的类,都是被fifinal修饰的,目的就是供我们使用,而不让我们可以改变其内容。
2.5.2.2.2. 修饰方法
格式如下: 修饰符 final 返回值类型 方法名(参数列表){ //方法体 } 重写被 final 修饰的方法,编译时就会报错。
2.5.2.2.3. 修饰变量
2.5.2.2.3.1. 局部变量
2.5.2.2.3.1.1. 基本类型
基本类型的局部变量,被fifinal修饰后,只能赋值一次,不能再更改。代码如下: public class FinalDemo1 { public static void main(String[] args) { // 声明变量,使用final修饰 final int a; // 第一次赋值 a = 10; // 第二次赋值 a = 20; // 报错,不可重新赋值 // 声明变量,直接赋值,使用final修饰 final int b = 10; // 第二次赋值 b = 20; // 报错,不可重新赋值 } } 思考,如下两种写法,哪种可以通过编译? 写法1: final int c = 0; for (int i = 0; i < 10; i++) { c = i; System.out.println(c); } 写法2: for (int i = 0; i < 10; i++) { final int c = i; System.out.println(c); } 根据 final 的定义,写法1报错!写法2,为什么通过编译呢?因为每次循环,都是一次新的变量c。这也是大家 需要注意的地方。
2.5.2.2.3.1.2. 引用类型
引用类型的局部变量,被fifinal修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的 修改,代码如下: public class FinalDemo2 { public static void main(String[] args) { // 创建 User 对象 final User u = new User(); // 创建 另一个 User对象 u = new User(); // 报错,指向了新的对象,地址值改变。 // 调用setName方法 u.setName("张三"); // 可以修改 } }
2.5.2.2.3.2. 成员变量
成员变量涉及到初始化的问题,初始化方式有两种,只能二选一: 显示初始化; public class User { final String USERNAME = "张三"; private int age; } 构造方法初始化。 public class User { final String USERNAME ; private int age; public User(String username, int age) { this.USERNAME = username; this.age = age; } } 被fifinal修饰的常量名称,一般都有书写规范,所有字母都大写。
2.5.3. static
2.5.3.1. 概述
关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属 于某个对象的。也就是说,既然属于类,就可以不靠创建对象来调用了。
2.5.3.2. 定义和使用格式
2.5.3.2.1. 类变量
当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。 类变量:使用 static关键字修饰的成员变量。 定义格式: static 数据类型 变量名; 举例: static int numberID; 比如说,基础班新班开班,学员报到。现在想为每一位新来报到的同学编学号(sid),从第一名同学开始,sid为 1,以此类推。学号必须是唯一的,连续的,并且与班级的人数相符,这样以便知道,要分配给下一名新同学的学 号是多少。这样我们就需要一个变量,与单独的每一个学生对象无关,而是与整个班级同学数量有关。 所以,我们可以这样定义一个静态变量numberOfStudent,代码如下: public static class Student { private String name; private int age; // 学生的id private int sid; // 类变量,记录学生数量,分配学号 public static int numberOfStudent = 0; public Student(String name, int age) { this.name = name; this.age = age; // 通过 numberOfStudent 给学生分配学号 this.sid = ++numberOfStudent; } // 打印属性值 public void show() { System.out.println("Student : name=" + name + ", age=" + age + ", sid=" + sid); } } public static class StuDemo { public static void main(String[] args) { Student s1 = new Student("张三", 23); Student s2 = new Student("李四", 24); Student s3 = new Student("王五", 25); Student s4 = new Student("赵六", 26); s1.show(); // Student : name=张三, age=23, sid=1 s2.show(); // Student : name=李四, age=24, sid=2 s3.show(); // Student : name=王五, age=25, sid=3 s4.show(); // Student : name=赵六, age=26, sid=4 } }
2.5.3.2.2. 静态方法
当 static 修饰成员方法时,该方法称为类方法 。静态方法在声明中有 static ,建议使用类名来调用,而不需要 创建类的对象。调用方式非常简单。 类方法:使用 static关键字修饰的成员方法,习惯称为静态方法。 定义格式: 修饰符 static 返回值类型 方法名 (参数列表){ // 执行语句 } 举例:在Student类中定义静态方法 public static void showNum() { System.out.println("num:" + numberOfStudent); } 静态方法调用的注意事项: 静态方法可以直接访问类变量和静态方法。 静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。 静态方法中,不能使用this关键字。 小贴士:静态方法只能访问静态成员。
2.5.3.2.3. 调用格式
被static修饰的成员可以并且建议通过类名直接访问。虽然也可以通过对象名访问静态成员,原因即多个对象均属 于一个类,共享使用同一个静态成员,但是不建议,会出现警告信息。 格式: // 访问类变量 类名.类变量名; // 调用静态方法 类名.静态方法名(参数); 调用演示,代码如下: public static class StuDemo2 { public static void main(String[] args) { Student s1 = new Student("张三", 23); Student s2 = new Student("李四", 24); Student s3 = new Student("王五", 25); Student s4 = new Student("赵六", 26); // 访问类变量 System.out.println(Student.numberOfStudent); // 调用静态方法 Student.showNum(); } }
2.5.3.3. 静态原理图解
static 修饰的内容: l 是随着类的加载而加载的,且只加载一次。 l 存储于一块固定的内存区域(静态区),所以,可以直接被类名调用。 l 它优先于对象存在,所以,可以被所有对象共享。 
2.5.3.4. 静态代码块
静态代码块:定义在成员位置,使用static修饰的代码块{ }。 位置:类中方法外。 执行:随着类的加载而执行且执行一次,优先于main方法和构造方法的执行。 格式: public class ClassName{ static { // 执行语句 } } 作用:给类变量进行初始化赋值。用法演示,代码如下: public class Game { public static int number; public static ArrayList<String> list; static { // 给类变量赋值 number = 2; list = new ArrayList<String>(); // 添加元素到集合中 list.add("张三"); list.add("李四"); } } 小贴士: static 关键字,可以修饰变量、方法和代码块。在使用的过程中,其主要目的还是想在不创建对象的情况 下,去调用方法。下面将介绍两个工具类,来体现static 方法的便利。
2.5.4. synchronized
2.6. 用于定义类与类之间关系的关键字
2.6.1. extends
2.6.2. implements
2.7. 用于定义实例及引用实例,判断实例的关键字
2.7.1. new
2.7.2. this
2.7.2.1. 发现问题
我们发现 setXxx 方法中的形参名字并不符合见名知意的规定,那么如果修改与成员变量名一致,是否就见名知意 了呢?代码如下: public class Student { private String name; private int age; public void setName(String name) { name = name; } public void setAge(int age) { age = age; } } 经过修改和测试,我们发现新的问题,成员变量赋值失败了。也就是说,在修改了 setXxx() 的形参变量名后,方 法并没有给成员变量赋值!这是由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无 法访问到成员变量,从而赋值失败。所以,我们只能使用this关键字,来解决这个重名问题。
2.7.2.2. this的含义
this代表所在类的当前对象的引用(地址值),即对象自己的引用。 记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
2.7.2.3. this使用格式
this.成员变量名; 使用 this 修饰方法中的变量,解决成员变量被隐藏的问题,代码如下: public class Student { private String name; private int age; public void setName(String name) { //name = name; this.name = name; } public String getName() { return name; } public void setAge(int age) { //age = age; this.age = age; } public int getAge() { return age; } } 小贴士:方法中只有一个变量名时,默认也是使用 this 修饰,可以省略不写。
2.7.3. super
2.7.4. instanceof
2.8. 用于异常处理的关键字
2.8.1. try
2.8.2. catch
2.8.3. finally
2.8.4. throw
2.8.5. throws
2.9. 用于包的关键字
2.9.1. package
2.9.2. import
2.10. 其它修饰符关键字
2.10.1. native
2.10.2. strictfp
2.10.3. transient
2.10.4. volatile
2.10.5. assert
3. 标识符
3.1. 标识符的概述和组成规则【掌握】
1.1 什么是标识符 就是给类,接口,方法,变量等起名字时使用的字符序列。 1.2 标识符的组成规则 l 英文大小写字母(a-z,A-Z) l 数字字符(0-9) l 美元符号$和_ 1.3 标识符注意事项 l 不能使用关键字 l 不能数字开头:错误示例:4xxx l 严格区分大小写:A和a是两个不同的标识符 举例:  1.4 案例:下面哪些是合法标识符 HelloWorld,DataClass,_983,$bS5_c7,class,DataClass#,98.3,Hell World 答:HelloWorld,DataClass,_983,$bS5_c7。 DataClass# #不是组成规则符号 98.3 不能以数字开头,点.也不是组成规则符号 Hell World 空格不是组成规则符号
3.2. 标识符中常见的命名规则【掌握】
原则:驼峰命名,见名知意 目的:增强可读性 1.1 包 包其实就是文件夹,用于解决相同类名问题,后面会详细讲解。 不管是单级包还是多级包,所有字母都小写。 l 单级包,如xxx l 多级包,使用点.隔开,一般是域名倒过来,要求所有的字母小写,如xxx.yyy.zzz 示例: 单级包liuyi 多级包cn.itcast.模块名 1.2 类或者接口 l 如果是一个单词首字母大写,如Xxx l 如果是多个单词每个单词首字母大写(驼峰标识) ,如XxxYyyZzz 示例: 一个单词Student 多个单词HelloWorld 1.3 方法或者变量 l 如果是一个单词全部小写,如xxx l 如果是多个单词,从第二个单词首字母大写,如xxxYyyZzz 示例: 一个单词name,main 多个单词studentName 1.4 常量 l 如果是一个单词,所有字母大写,如XXX l 如果是多个单词,所有的单词大写,用下划线_连接每个单词,如XXX_YYY_ZZZ 示例: 一个单词MAX 多个单词STUDENT_MAX_AGE
第五部分:Java中的常量及进制
1. 常量的概述和使用【掌握】
1.1. 什么是常量
在程序执行的过程中其值不可以发生改变 。
1.2. Java中常量的分类
l 字面值常量 l 自定义常量(面向对象部分讲)
1.2.1. 字面值常量的分类(六类)
字面值常量可以通过输出语句直接输出,null除外。 序号 分类 说明 注意事项 1 整数常量 所有整数 举例:12,23 2 小数常量 所有小数 举例:12.34,56.78 3 字符串常量 用双引号括起来的内容 "",代表长度为0的空字符串 " ",代表空格字符串 4 字符常量 用单引号括起来的内容,里面只能放单个数字,单个字母或单个符号 ''中必须放的是单个字符; ''中什么也不放,也是不可以的,因为代表不了任何字符; ' ' 代表空格字符; 举例:'a','A','0' 5 布尔常量 较为特殊,只有两个值true和false 6 空常量 null(数组部分讲解) 案例 class Demo1_Constant { //constant 常量 public static void main(String[] args) { /* * 字符串常量 用双引号括起来的内容 * 整数常量 所有整数 * 小数常量 所有小数 * 字符常量 用单引号括起来的内容,里面只能放单个数字,单个字母或单个符号 * 布尔常量 较为特殊,只有true和false * 空常量 null(数组部分讲解) */ System.out.println("abc"); //字符串常量 System.out.println(123); //整数常量 System.out.println(12.3); //小数常量 //System.out.println('10'); //''中必须放的是单个字符,10代表的是1字符和0字符 //System.out.println(''); //''中什么也不放,也是不可以的,因为代表不了任何字符 System.out.println(' '); //' '代表空格字符 System.out.println(true); //boolean类只有两个值,true和false System.out.println(false); } }
1.2.2. 自定义常量
2. 进制概述和二,八,十六进制图解(了解)
3. 不同进制数据的表现形式【掌握】
1.1 二进制的数据表现形式 由0,1组成。以0b(b可以大写也可以小写)开头(JDK1.7版本可以表示二进制了)。 示例:0b100 1.2 八进制的数据表现形式 由0,1,…7组成。以0开头。 示例:0100 1.3 十进制的数据表现形式 由0,1,…9组成。整数默认是十进制的。 示例:100 1.4 十六进制的数据表现形式 由0,1,…9,a,b,c,d,e,f(大小写均可)。以0x开头。 示例:0x100 1.5 不同进制对比 进制 组成 开头 注意事项 二进制 由0,1组成 以0b开头 (b可以大写也可以小写) 从JDK1.7版本开始可以表示二进制了 八进制 由0-7组成 以0开头 十进制 由0-9组成 整数默认是十进制的 十六进制 由0-9,a,b,c,d,e,f(大小写均可) 以0x开头 (x可大写也可小写) 1.6 案例 输出不同进制表现100的数据。 0b100 0100 100 0x100 class Demo1_Scale { //scale 进制 public static void main(String[] args) { /* * 0b100 * 0100 * 100 * 0x100 */ System.out.println(0b100); //4? 二进制表示形式前面加0b(b可以大写也可以小写) System.out.println(0100); //64? 八进制表示形式前面加0 System.out.println(100); System.out.println(0x100); //256? 十六进制表示形式前面加0x(可以大写也可以小写) } }
第六部分:变量,数据类型转换
1. 变量的概述及格式【掌握】
1.1 什么是变量 变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。 特点:变量其实就是将不确定的数据进行存储,也就是需要在内存中开辟一个空间。 从本质上讲,变量其实是内存中的一小块存储区域,该区域有自己的名称(变量名)和类型(数据类型),该区域的数据可以在同一类型范围内不断变化。我们通过使用变量名来访问这块区域,因此,每一个变量使用前必须要先申请(声明),然后必须进行赋值(填充内容),才能使用。  1.2 变量的定义格式 l 格式1:数据类型 变量名 = 变量值; 【常用方式】 l 格式2:数据类型 变量名; 变量名 = 变量值; 1.3 为什么要定义变量 用来不断的存放同一类型的常量,并可以重复使用。
2. 数据类型的概述和分类【掌握】
2.1. 为什么有数据类型
Java语言是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存中分配了不同大小的内存空间。
2.2. 10.2Java中数据类型的分类
l 基本数据类型 l 引用数据类型 
2.2.1. 基本数据类型分类(4类8种)
2.2.1.1. 整数型
l byte 字节 占一个字节 -128到127【记住】 l short 短整型 占两个字 -2^15~2^15-1 l int 整型 占四个字节 -2^31~2^31-1 整数的默认类型是int l long 长整型 占八个字节 -2^63~2^63-1  注:一个字节=8个二进制位 byte b = 10; // 占一个字节,-128 到 127 short s = 20; // 占两个字节 int i = 30; // 占四个字节 整数默认的数据类型就是int类型 long x = 8888888888L; // 占八个字节 // 当等号右边的数值超出了int取值范围,必须加L或l标识 // 如果long类型后面加L进行标识最好加大L,因为小l太像一了
2.2.1.2. 浮点型
l float 单精度 占四个字节 -3.403E38~3.403E38 l double 双精度 占八个字节 -1.798E308~1.798E308 小数的默认类型是double  注:E表示指数计数法。3.403E38是3.403乘以10的38次方的意思。 float f = 12.3F; // 占四个字节 给float赋值时,必须加f标识,f大小写都可 double d = 33.4; // 占八个字节 小数默认的数据类型是double,double类型后面也可以用D或d标识,但是一般不加
2.2.1.3. 字符型
char 占两个字节 0~65535 2^16 = 65536 // 字符类型 char c = 'a'; // 占两个字节
2.2.1.4. 布尔型
l boolean boolean理论上是占八分之一个字节,因为一个开关就可以决定是true和false了, 但是java中boolean类型没有明确指定大小,因此也不能参与运算。 // 布尔类型 boolean b1 = true; boolean b2 = false;
3. 使用变量的注意事项【掌握】
3.1. 作用域
变量定义在哪一级大括号中,哪个大括号的范围就是这个变量的作用域。 class day02 { public static void main(String[] args) { int z = 9; // 作用域就是变量定义的那对大括号内 } System.out.println(z); // 错误:需要<标识符> } 注意:相同的作用域中不能定义两个同名变量。 public static void main(String[] args) { int a = 12; int a = 15; // 错误: 已在方法 main(String[])中定义了变量 a }
3.2. 初始化值
a. 局部变量没有初始化值不能直接使用。局部变量在使用之前必须赋值。 b. 如果声明局部变量而未赋值,但也从未使用该局部变量,程序编译不会报错。 (我们现在所使用的变量都是局部变量,因为都是定义在方法中的) public static void main(String[] args) { int a; System.out.println(a); // 错误: 可能尚未初始化变量a }
3.3. 在一行上建议只定义一个变量
可以定义多个,但是不建议。在实际开发中,建议在一行上只定义一个变量。 一条语句可以定义多个变量。 int a,b,c...; public static void main(String[] args) { int a,b,c; a=b=c=15; int x=y=z; //错误: 找不到符号 int x=y=z=4; //错误: 找不到符号 }
4. 数据类型转换之隐式转换(自动类型提升)【掌握】
自动类型转换就是不需要我们手动对类型来进行强制转换。
4.1. 案例演示
l byte + int class Demo3_DataTypeConversion { // Conversion转换 public static void main(String[] args) { // 数据类型转换之隐式转换 int x = 3; byte b = 4; x = x + b; // b类型从byte自动提升为int,再进行运算 System.out.println(x); } }
4.2. Java中的默认转换规则
取值范围小的数据类型与取值范围大的数据类型进行运算, 会先将小的数据类型提升为大的,再运算。
4.3. 画图解释byte+int类型的问题

5. 数据类型转换之强制转换(显式类型转换)【掌握】
强制类型转换需要把类型进行手动转换,否则无法正常使用。
5.1. 强制转换问题
int a = 10; byte b = 20; b = a + b; //有问题,错误: 可能损失精度 当byte类型的变量b提升为int类型与int类型的变量a相加后,结果依然是int类型, 再赋值给byte类型,当然会出现损失精度的错误。
5.2. 强制转换的格式
目标类型 变量名=(目标类型)(被转换的数据); 示例: int a = 10; byte b = 20; b = (byte)(a + b); // 强制转换,建议将被转换的结果使用小括号括起来
5.3. 强制转换的注意事项
如果强制转换的数值,超出了被赋值的数据类型的取值范围得到的结果会与你期望的结果不同。 byte b = (byte)(126 + 4); // b的结果为-126 byte b2 = (byte)300; // b2的结果为44 图解:  
5.4. 案例:数据类型转换之强制转换
class Demo3_DataTypeConversion { // Conversion转换 public static void main(String[] args) { // 数据类型转换之强制转换 /* int x = 3; byte b = 4; b = (byte)(x + b); System.out.println(b); */ // 00000000 00000000 00000000 10000010 130的二进制 // 10000010 -126补码 // 00000001 -1求反码 // 10000001 -126反码 // 11111110 -126原码 byte b = (byte) (126 + 4); System.out.println(b); // 结果:-126 // 00000000 00000000 00000001 00101100 300的二进制 // 00101100 byte b2 = (byte) 300; System.out.println(b2); // 结果:44 } }
6. 面试题之变量相加和常量相加的区别【掌握】
1.1 面试题 byte b1=3,b2=4,b; b=b1+b2; b=3+4; 哪句是编译失败的呢?为什么呢? 1.2 解答与常量优化机制 class Test1_DataTypeConversion { public static void main(String[] args) { // 面试题:看下面的程序是否有问题,如果有问题,请指出并说明理由。 byte b1 = 3; byte b2 = 4; byte b3 = b1 + b2; /* * 从两方面 1,byte与byte(或short,char)进行运算的时候会提升为int(因为整数默 认的类型为int),两个int类型相加的结果也是int类型,不能直接赋值给byte类型变量,需要强转 2,b1和b2是两个变量,变量存储的值是变化,在编译的时候无法判断里面具体的值,相加有可能会超出byte的取值范围 */ // System.out.println(b3); // byte b4 = 3 + 4; //java编译器有常量优化机制,在编译的时候就把3+4的结果计算出来了, byte b4 = 7; // 以判断7在-128至127之间 System.out.println(b4); } } public static void main(String[] args) { int x; int x1 = 2000000000; int x2 = 2000000000; x = x1 + x2; System.out.println(x); // 运行结果:-294967296 } 说明:原因是因为int类型的两个变量相加,最后还是int类型,虽然结果溢出,但是不会报错。
7. long与float的取值范围谁大谁小
进行混合运算的时候,byte、short、char之间不会相互转换,都会自动类型提升为int类型, 其他类型进行混合运算的是小的数据类型提升为大的。 a.几个基本类型的取值范围如下:byte,short,char < int < long < float < double b. boolean类型不能转换为其他的数据类型。
8. 字符和字符
8.1. char数据类型
char c = 97; 0到65535 ,取值范围没有负数 l Java语言中的字符char可以存储一个中文汉字吗?为什么呢? 可以。因为Java语言采用的是Unicode编码,Java中的内置码表是Unicode,既包含中文,也包含英文。Unicode编码中的每个字符占用两个字节。中文也是占的两个字节。所以,Java中的字符可以存储一个中文汉字。 注:Unicode是国际标准字符集,可译为万国码或统一码等,这是电脑系统采用字库的字符集标准,包含中日韩越汉字和世界上绝大多数语言文字,便于实现全球间信息交流。
8.2. 字符串
8.3. 字符和字符串参与运算【掌握】
8.3.1. 字符参与运算案例
请写出下列程序结果 System.out.println('a'); //结果: 97 System.out.println((char)('a'+1)); //结果: b 字符参与运算,先自动提升为int类型,再参与运算。 通过看结果知道'a'的值是97,由此引出ASCII码表。
8.3.2. ASCII码表的概述

8.3.3. 字符串参与运算案例
System.out.println("hello"+'a'+1); // helloa1 System.out.println('a'+1+"hello"); // 98hello System.out.println("5+5="+5+5); // 5+5=55 System.out.println(5+5+"=5+5"); // 10=5+5 System.out.println(" 5 + 5 = " + (5 + 5)); // 5 + 5 = 10 小括号改变运算优先级
第七部分:运算符
1.1 运算符的分类 ① 算术运算符 ② 赋值运算符 ③ 比较(关系或条件)运算符 ④ 逻辑运算符 ⑤ 位运算符 ⑥ 三目(元)运算符
1. 算术运算符
1.1 什么是运算符 就是对常量和变量进行操作的符号。 1.2 算术运算符有哪些 ① + ② - ③ * ④ / ⑤ % ⑥ ++ ⑦ -- 
1.1. 注意事项
l + 加:在java中有三种作用: a. 代表正号 b. 做加法运算 c. 字符串的连接符 l / 除:整数相除,只能得到整数。 如果想得到小数,必须把数据变化为浮点数类型,即有浮点型数据参与运算。 l / 除:获取的是除法操作的商 % 取模:获取的是除法操作的余数 l % 取模运算符: 左边%右边 a. 当左边的绝对值小于右边绝对值时,结果是左边。举例:5%10=5;-5%10=-5 b. 当左边的绝对值等于右边或是右边的倍数时,结果是0。举例:5%5=0;-5%5=0 c. 当左边的绝对值大于右边绝对值时,结果是余数。举例:5%3=2;-5%3=-2 d. %运算符结果的符号只和左边有关系,与右边无关。举例:-5%3=-2;5%-3=2;-5%-3=-2 任何一个正整数%2结果不是0就是1可以用来当作切换条件。 class Demo1_Operator { //operator 运算符 public static void main(String[] args) { //整数相除结果只能是整数 //System.out.println(10 / 3); // 3 //如果想得到小数,把其中一个数变成小数,另一个数在运算的时候会自动类型提升 //System.out.println(10 / 3.0); // 3.3333333333333335 //System.out.println(-5 % 5); // 0 System.out.println(13 % -5); // 3 } }
1.2. 算术运算符++和--
1.2.1. 算术运算符++和--的用法
1.2.1.1. ++,--运算符的作用
自加(++)、自减(--)运算: a. ++:自加。对原有的数据进行+1 b. --:自减。对原有的数据进行-1
1.2.1.2. 单独使用
单独使用时,放在操作数的前面和后面效果一样。(这种用法是我们比较常见的) 单独使用示例: a++; ++a;
1.2.1.3. 参与运算使用
放在操作数的前面,先自增或者自减,然后再参与运算。 放在操作数的后面,先参与运算(相当于先取出一个副本),再自增或者自减。 简单说,++在前,先自增后运算。 简单说,++在后,先运算在自增。 参与运算示例:=号表示赋值运算 b = a++; b = ++a;
1.2.1.4. 案例
class Demo2_Operator { /* * a:单独使用: * 放在操作数的前面和后面效果一样。(这种用法是我们比较常见的) * b:参与运算使用: * 放在操作数的前面,先自增或者自减,然后再参与运算。 * 放在操作数的后面,先参与运算,再自增或者自减。 */ public static void main(String[] args) { //单独使用 int a = 3; a++; //a = a + 1; ++a; //a = a + 1; System.out.println(a); //参与运算使用 int c = 3; int d; // d = c++; //当++在变量后面的时候,会先将变量中的值取出做赋值操作,然后再自身加1 d = ++c; //当++在变量前面的时候,会先自身加1,然后在将结果赋值 System.out.println("c = " + c); System.out.println("d = " + d); } }
1.2.2. 算术运算符++和--的练习
1.2.2.1. 基本小题目
请分别计算出a,b,c的值 int a = 10; int b = 10; int c = 10; a = b++; //a = 10 ,b = 11 c = --a; //a = 9, c = 9 b = ++a; //a = 10, b = 10 a = c--; //a = 9, c = 8 System.out.println("a = " + a + ",b = " + b + ",c = " + c);
1.2.2.2. 比较复杂的题目
int a = 4; int b = (a++)+(++a)+(a*10); 引出运算符的优先级 int x = 4; // 4 + 6 + 60 int y = (x++)+(++x)+(x*10); System.out.println("x = " + x + ",y = " + y);//x=6,y=70
1.2.2.3. 面试题:隐含强制类型转换
考点: ++、--运算符隐含了强制类型转换 byte b = 10; b++; b = b + 1; 问哪句会报错,为什么 byte b = 10; //b++; //b = (byte)(b + 1) // ++、--运算符隐含了强制类型转换 b = b + 1; //当byte与int进行混合运算的时候,会提升为int类型,两个int相加的结果还是int,赋值给byte会损失精度 System.out.println("b = " + b);
2. 赋值运算符
2.1. 基本的赋值运算符:=
把=右边的数据赋值给左边。
2.2. 扩展的赋值运算符:+=,-=,*=,/=,%=
+= 把左边和右边做加法,然后赋值给左边。
2.2.1. 案例:
public static void main(String[] args) { //赋值运算符 int a = 3; //把右边的常量值赋值给左边的变量,左边必须是变量 //a += 4; //a = a + 4; a = a + 4; System.out.println(a); }
2.2.2. 赋值运算符的面试题
public static void main(String[] args) { // 面试题:看下面的程序是否有问题,如果有问题,请指出并说明理由。 //short s=1;s = s+1; //当short与int进行运算的时候,会提升为int类型,两个int类型相加的结果也是int类型 short s=1;s+=1; //s = (short)(s + 1); += 隐含了强制类型转换 System.out.println(s); }
3. 比较(关系或条件)运算符
3.1. 关系运算符有哪些(比较运算符,条件运算符)
① == ② != ③ > ④ >= ⑤ < ⑥ <= 
3.2. 注意事项:
l 对于比较运算符,无论你的操作是简单还是复杂,结果都是boolean型,也就是要么是true,要么是false。 l "=="不能写成"="。否则,会得到意想不到的结果。 1:注意2的时候举例:"=="不能写成"=" class day02 { public static void main(String[] args) { int a = 5; int b = 8; System.out.println(a==b); // false System.out.println(a=b); // 8 ,先完成赋值,在执行输出语句 } } 2:赋值的时候要注意类型问题 class day02 { public static void main(String[] args) { int x = 10; int y = 10; boolean flag = (x == y); // flag = true // boolean flag = (x = y); // 报错:等号左边需要布尔型的值,而x=y结果为10 boolean b1 = true; boolean b2 = false; boolean b3 = (b1 == b2); boolean b4 = (b1 = b2); System.out.println(b3); // false System.out.println(b4); // false } } 1.1 案例 class Demo1_Operator { public static void main(String[] args) { //==,!=,>,>=,<,<= System.out.println(4 == 3); System.out.println(4 != 3); System.out.println(4 > 4); System.out.println(4 >= 4); System.out.println(4 < 3); System.out.println(4 <= 3); } } 结果: false true false true false false
4. 逻辑运算符
4.1. 逻辑运算符的基本用法
4.1.1. 逻辑运算符有哪些
 ① & ② | ③ ^ ④ ! ⑤ && ⑥ ||
4.1.2. 注意事项
l 逻辑运算符一般用于连接boolean类型的表达式或者值,最终运算结果还是boolean类型。 l 表达式:就是用运算符把常量或者变量连接起来的符合java语法的式子。 * 算术表达式:a + b * 比较表达式:a == b(条件表达式) 1.1 结论 l &逻辑与:有false则false。 l |逻辑或:有true则true。 l ^逻辑异或:相同为false,不同为true。 !逻辑非:非false则true,非true则false。 特点:偶数个不改变本身。
4.1.3. 案例
class Demo1_Operator { public static void main(String[] args) { //&,|,^,! //int x = 10; //5 < x < 15 //x > 5 & x < 15 int a = 10; int b = 20; int c = 30; //逻辑与 & 并且and 遇false则false /*System.out.println(a < b & b < c); //true & true = true System.out.println(a < b & b > c); //true & false = false System.out.println(a > b & b < c); //false & true = false System.out.println(a > b & b > c); //false & false = false*/ //逻辑或 或or 遇true则true /*System.out.println(a < b | b < c); //true | true = true System.out.println(a < b | b > c); //true | false = true System.out.println(a > b | b < c); //false | true = true System.out.println(a > b | b > c); //false | flase = false*/ //逻辑异或 ^ 两边相同为false,两边不同为true /*System.out.println(a < b ^ b < c); //true ^true = false System.out.println(a < b ^ b > c); //true ^false = true System.out.println(a > b ^ b < c); //false ^ true = true System.out.println(a > b ^ b > c); //false^flase = false*/ //逻辑非! System.out.println(!true); System.out.println(!!true); } }
4.2. 逻辑运算符&&和&的区别
4.2.1. &&和&的区别
l 最终结果一样。 l &&具有短路效果。左边是false,右边不执行。 &是无论左边是false还是true,右边都会执行。
4.2.2. 同理||和|的区别
l 最终结果一样 l ||具有短路效果。左边是true,右边不执行 |是无论左边是false还是true,右边都会执行
4.2.3. 开发中常用(三个:&&、||、!)
l && l || l !
5. 位运算符
5.1. 位运算符有哪些
① & ② | ③ ^ ④ ~ ⑤ >> ⑥ >>> ⑦ <<  
5.2. 位运算符的基本用法1
5.2.1. &,|,^,~ 的用法:
&,|,^,~ 的用法: l &:有0则0 l |:有1则1 l ^:相同则0,不同则1 ~:按位取反 class Demo1_Operator { public static void main(String[] args) { /* * &,|,^,~ 的用法 * &:有0则0 * |:有1则1 * ^:相同则0,不同则1 * ~:按位取反 */ System.out.println(6 & 3); //2 System.out.println(6 | 3); //7 System.out.println(6 ^ 3); //5 System.out.println(~6); //-7? } } 结果分析: /* 110 6 & 011 3 ----------- 010 2 110 6 | 011 3 ----------- 111 7 110 6 ^ 011 3 ----------- 101 5 00000000 00000000 00000000 00000110 6的原码反码补码都是本身 11111111 11111111 11111111 11111001 对6取反 结果是补码 - 00000000 00000000 00000000 00000001 --------------------------------------- 11111111 11111111 11111111 11111000 反码 10000000 00000000 00000000 00000111 原码(-7) */
5.3. 位异或运算符的特点及面试题【掌握】
5.3.1. 位异或运算符的特点
^的特点:一个数据对另一个数据位异或两次,该数本身不变。
5.3.2. 4.2面试题
请自己实现两个整数变量的交换。 注意:以后讲课的过程中,我没有明确指定数据的类型,默认int类型。 l 方式一:引入第三方变量,【开发推荐用这种】 l 方式二:先做加法,再做减法,弊端:有可能会超出int的取值范围 方式三:利用位异或^的特点来做【面试用】 class Demo2_Operator { public static void main(String[] args) { /* * 位异或运算符的特点 * ^的特点:一个数据对另一个数据位异或两次,该数本身不变。 */ //System.out.println(5 ^ 10 ^ 10); //System.out.println(5 ^ 10 ^ 5); /* * 请自己实现两个整数变量的交换(不需要定义第三方变量) * 注意:以后讲课的过程中,我没有明确指定数据的类型,默认int类型。 */ int x = 10; int y = 5; //方式一:需要第三方变量,开发推荐用这种 /*int temp; temp = x; x = y; y = temp;*/ //方式二:不需要定义第三方变量,有弊端,有可能会超出int的取值范围 /*x = x + y; //10 + 5 = 15 y = x - y; //15 - 5 = 10 x = x - y; //15 - 10 = 5*/ //方式三:不需要第三方变量,通过^来做 x = x ^ y; // 10 ^ 5 y = x ^ y; // 10 ^ 5 ^ 5 y = 10 x = x ^ y; // 10 ^ 5 ^ 10 x = 5 System.out.println("x = " + x + ",y = " + y); } }
5.4. 位运算符的基本用法2
5.4.1. <<,>>,>>>的用法
l <<:左移 左边最高位丢弃,右边补齐0(正负数都适合) l >>:右移 最高位是0,左边补齐0;最高为是1,左边补齐1(正数适合,负数不适合) l >>>:无符号右移 无论最高位是0还是1,左边补齐0(正数适合,负数不适合,负数右移会变成正数) 1.1 结论 l << 左移,向左移动几位就是乘以2的几次幂 l >> 右移,向右移动几位就是除以2的几次幂
5.4.2. 面试题
最有效率的算出2 * 8的结果 2 << 3 1.1 案例 class Demo3_Operator { public static void main(String[] args) { /* * <<:左移 左边最高位丢弃,右边补齐0 * >>:右移 最高位是0,左边补齐0;最高为是1,左边补齐1 * >>>:无符号右移 无论最高位是0还是1,左边补齐0 * 最有效率的算出2 * 8的结果 */ //左移,向左移动几位就是乘以2的几次幂 //System.out.println(12 << 1); //24 //System.out.println(12 << 2); //48 /* 00000000 00000000 00000000 00001100 12的补码 (0)0000000 00000000 00000000 000011000 24的补码 (00)000000 00000000 00000000 0000110000 48的补码 */ //右移,向右移动几位就是除以2的几次幂 //System.out.println(12 >> 1); //System.out.println(12 >> 2); /* 00000000 00000000 00000000 00001100 12的补码 000000000 00000000 00000000 0000110(0) 6 0000000000 00000000 00000000 000011(00) 3 */ //最有效率的算出2 * 8的结果 System.out.println(2<<3); } }
6. 三目(元)运算符
6.1. 三元运算符的基本用法
6.1.1. 三元运算符的格式
(关系表达式) ? 表达式1 : 表达式2;
6.1.2. 三元运算符的执行流程
(关系表达式) ? 表达式1 : 表达式2; l 如果条件为true,运算后的结果是表达式1; l 如果条件为false,运算后的结果是表达式2;
6.1.3. 案例
l 获取两个数中的最大值 class Demo1_Operator { public static void main(String[] args) { //(关系表达式) ? 表达式1 : 表达式2; int x = 10; int y = 5; int z; z = (x > y) ? x : y; System.out.println("z = " + z); } }
6.1.4. 三元运算符的练习【掌握】
1.1 比较两个整数是否相同 1.2 获取三个整数中的最大值 class Test1_Operator { public static void main(String[] args) { /* * A:案例演示 * 比较两个整数是否相同 * B:案例演示 * 获取三个整数中的最大值 */ //比较两个整数是否相同 /*int x = 10; int y = 10; //boolean b = (x == y) ? true : false; boolean b = (x == y); System.out.println("b = " + b);*/ //获取三个整数中的最大值 int a = 10; int b = 20; int c = 30; //先比较任意两个数的值,找出这两个数中的最大值 int temp = (a > b) ? a : b; //用前两个数的最大值与第三个数比较,获取最大值 int max = (temp > c) ? temp : c; System.out.println("max =" + max); } } 只用三元运算符求三个值的最大值: int max = (((a > b) ? a : b) > c) ? ((a > b) ? a : b) : c;
第八部分:键盘录入数据
第九部分:流程控制语句
1.1 什么是流程控制语句 流程控制语句:可以控制程序的执行流程。 在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。也就是说程序的流程对运行结果有直接的影响。所以,我们必须清楚每条语句的执行流程。而且,很多时候我们要通过控制语句的执行顺序来实现我们要完成的功能。 1.2 流程控制语句的分类 l 顺序结构 l 选择结构 l 循环结构
1. 流程控制语句之顺序结构
是程序中最简单最基本的流程控制,没有特定的语法结构, 按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。 总的来说:写在前面的先执行,写在后面的后执行。 从上往下,依次执行  class Demo1_Sequence { //sequence 顺序 public static void main(String[] args) { System.out.println("Hello World!11111"); System.out.println("Hello World!3333"); System.out.println("Hello World!22222"); System.out.println("Hello World!44444"); } }
2. 流程控制语句之选择结构
选择结构也被称为分支结构。 选择结构有特定的语法规则,代码要执行具体的逻辑运算进行判断, 逻辑运算的结果有两个,所以产生选择,按照不同的选择执行不同的代码。 Java语言提供了两种选择结构语句: l if语句 l switch语句
2.1. 选择结构if语句
2.1.1. if语句格式1及其使用【掌握】
2.1.1.1. if语句的格式1
1.1 if语句的格式1 if(关系表达式){ 语句体; }
2.1.1.2. 执行流程
先计算比较表达式的值,看其返回值是true还是false。 l 如果是true,就执行语句体; l 如果是false,就不执行语句体; 
2.1.1.3. 案例
class Demo1_If { public static void main(String[] args) { int age = 17; if (age >= 18) { System.out.println("可以浏览本网站"); } System.out.println("完了"); } }
2.1.2. if语句格式2及其使用【掌握】
2.1.2.1. if语句的格式2
1.1 if语句的格式2 (条件表达式)?表达式1:表达式2; if(比较表达式) { 语句体1; }else { 语句体2; }
2.1.2.2. 执行流程
首先计算比较表达式的值,看其返回值是true还是false。 l 如果是true,就执行语句体1; l 如果是false,就执行语句体2; 
2.1.2.3. 注意事项
else后面是没有比较表达式的,只有if后面有。
2.1.2.4. 案例
获取两个数据中较大的值; 判断一个数据是奇数还是偶数,并输出是奇数还是偶数; class Demo3_If { public static void main(String[] args) { /*int x = 0; if (x == 1) { System.out.println("男厕所欢迎您"); }else { System.out.println("女厕所欢迎您"); }*/ //a:获取两个数据中较大的值 /*int x = 10; int y = 20; int z; if (x > y) { z = x; }else { z = y; } System.out.println(z);*/ //b:判断一个数据是奇数还是偶数,并输出是奇数还是偶数 int num = 11; if (num % 2 == 0) { System.out.println(num + "是一个偶数"); }else { System.out.println(num + "是一个奇数"); } } }
2.1.2.5. if语句的格式2和三元的相互转换问题
我们前面讲解过三元运算符,它根据比较判断后,给出的也是两个结果, 所以,这种情况和if语句的第二种格式很相似,他们在某些情况下应该是可以相互转换的。 1.1 if语句和三元运算符完成同一个效果 class Demo4_If { public static void main(String[] args) { int x = 10; int y = 20; int z; if (x > y) { //z = x; System.out.println(x + "是最大值"); }else { //z = y; System.out.println(y + "是最大值"); } //System.out.println(z); int a = 20; int b = 30; int c = (a > b)? a : b; } }
2.1.2.5.1. if语句和三元运算符的区别
l 三元运算符实现的,都可以采用if语句实现。反之不成立。 l 什么时候if语句实现不能用三元改进呢? 当if语句控制的操作是一个输出语句的时候就不能。 为什么呢?因为三元运算符是一个运算符,运算符操作完毕就应该有一个结果,而不是一个输出语句。
2.1.3. if语句格式3及其使用【掌握】
2.1.3.1. if语句的格式3
if(比较表达式1) { 语句体1; }else if(比较表达式2) { 语句体2; }else if(比较表达式3) { 语句体3; } ... else { 语句体n+1; }
2.1.3.2. 执行流程
l 首先计算比较表达式1看其返回值是true还是false, 如果是true,就执行语句体1,if语句结束。 如果是false,接着计算比较表达式2看其返回值是true还是false, 如果是true,就执行语句体2,if语句结束。 如果是false,接着计算比较表达式3看其返回值是true还是false, 如果都是false,就执行语句体n+1。 
2.1.3.3. 注意事项
最后一个else可以省略,但是建议不要省略,可以对范围外的错误值提示
2.1.3.4. 案例
int x = 2; if (x == 1) { System.out.println("男厕所欢迎您"); }else if (x == 0) { System.out.println("女厕所欢迎您"); }else { System.out.println("无法识别您的性别"); }
2.1.3.5. 选择结构if语句格式3练习
2.1.4. if语句的嵌套使用【掌握】
1.1 案例 :获取三个数据中的最大值 if语句的嵌套使用。 class Demo6_IfIf { public static void main(String[] args) { int a = 40; int b = 50; int c = 30; if (a > b) { if (a > c) { System.out.println(a + "是最大值"); }else { System.out.println(c + "是最大值"); } }else { //b >= a if (b > c) { System.out.println(b + "是最大值"); }else { System.out.println(c + "是最大值"); } } } }
2.1.5. 选择结构if语句注意事项
1.1 注意事项 l 比较表达式无论简单还是复杂,结果必须是boolean类型 l if语句控制的语句体如果是一条语句,大括号可以省略; 如果是多条语句,就不能省略。建议永远不要省略。 l 一般来说:有左大括号就没有分号,有分号就没有左大括号 1.1 案例 class Demo2_If { public static void main(String[] args) { int age = 17; if (age >= 18 && age <= 60) { System.out.println("可以浏览本网站"); //int x = 10; 是两句话,int x声明是一句,x = 10 赋值是一句 } System.out.println("完了"); } }
2.2. 选择结构switch语句
2.2.1. 选择结构switch语句的格式及其解释
2.2.1.1. switch语句的格式
switch(表达式) { case 值1: 语句体1; break; case 值2: 语句体2; break; … default: 语句体n+1; break; }
2.2.1.2. switch语句的格式解释
l switch表示这是switch语句 表达式的取值:byte,short,char,int JDK5以后可以是枚举 JDK7以后可以是String l case后面跟的是要和表达式进行比较的值 l 语句体部分可以是一条或多条语句 l break表示中断,结束的意思,可以结束switch语句 default语句表示所有情况都不匹配的时候,就执行该处的内容,和if语句的else相似。
2.2.1.3. 执行流程
先计算表达式的值, 然后和case后面的匹配, 如果有就执行对应的语句,否则执行default控制的语句 直到遇到break或者右大括号},结束switch语句。 
2.2.1.4. 面试题(表达式的取值)
l byte可以作为switch的表达式吗? l long可以作为switch的表达式吗? l String可以作为switch的表达式吗? 基本数据类型,只要能提升为int的都可以, 引用数据类型中的枚举(JDK1.5)和String(JDK1.7)
2.2.1.5. 案例
String name = "rose"; String gender = "妖"; switch (gender) { case "男士": System.out.println(name + "是一位" + gender + "喜欢吃饭睡觉打dota"); break; case "女士": System.out.println(name + "是一位" + gender + "喜欢逛街购物美容"); break; default: System.out.println(name + "是一位" + gender + "打雌性激素维持美貌容颜"); break; }
2.2.2. 选择结构switch语句的练习
2.2.2.1. 练习1
// * A:整数(给定一个值,输出对应星期几) int week = 1; switch (week) { case 1: System.out.println("星期一"); break; case 2: System.out.println("星期二"); break; case 3: System.out.println("星期三"); break; case 4: System.out.println("星期四"); break; case 5: System.out.println("星期五"); break; case 6: System.out.println("星期六"); break; case 7: System.out.println("星期日"); break; default: System.out.println("对不起没有对应的星期"); break; }
2.2.2.2. 练习2
1.1 看程序写结果 int x = 2; int y = 3; switch(x){ default: y++; break; case 3: y++; case 4: y++; } System.out.println("y="+y); // y=4 1.2 看程序写结果 int x = 2; int y = 3; switch(x){ default: y++; case 3: y++; case 4: y++; } System.out.println("y="+y); // y=6
2.2.3. 选择结构switch语句的注意事项【掌握】
l case后面只能是常量,不能是变量,而且,多个case后面的值不能出现相同的。 l default可以省略吗? 可以省略。一般不建议省略。因为它的作用是对不正确的情况给出提示。 除非判断的值是固定的。(单选题) 特殊情况: case就可以把值固定。A,B,C,D l break可以省略吗? 可以省略,一般不建议。否则结果可能不是你想要的。 会出现一个现象:case穿透。 最终我们建议不要省略。 l default的位置一定要在最后吗? 可以出现在switch语句任意位置。但是建议在最后。 l switch语句的结束条件: n 遇到break n 执行到程序的末尾,即执行到switch的右大括号就结束了
2.2.4. 总结
switch语句先和case后的值进行匹配,如果没有匹配项,再执行default,执行过程中遇到break或者右大括号},结束switch语句。
2.3. 选择结构if语句和switch语句的区别【掌握】
2.3.1. 总结switch语句和if语句的各自使用场景
l switch建议判断固定值的时候用 l if建议判断区间或范围的时候用
2.3.2. 案例:键盘录入月份,输出对应的季节
分别用switch语句和if语句实现下列需求: 键盘录入月份,输出对应的季节 import java.util.Scanner; class Test3_SwitchIf { public static void main(String[] args) { /* * 键盘录入月份,输出对应的季节 一年有四季 3,4,5春季 6,7,8夏季 9,10,11秋季 12,1,2冬季 */ Scanner sc = new Scanner(System.in); //创建键盘录入对象 System.out.println("请输入月份"); int month = sc.nextInt(); //将键盘录入的结果存储在month /* // switch语句实现 switch (month) { case 3: case 4: case 5: System.out.println(month + "月是春季"); break; case 6: case 7: case 8: System.out.println(month + "月是夏季"); break; case 9: case 10: case 11: System.out.println(month + "月是秋季"); break; case 12: case 1: case 2: System.out.println(month + "月是冬季"); break; default: System.out.println("对不起没有对应的季节"); break; }*/ //用if语句来完成月份对应季节方法一: if (month > 12 || month < 1) { System.out.println("对不起没有对应的季节"); }else if (month >= 3 && month <= 5) { System.out.println(month + "月是春季"); }else if (month >= 6 && month <= 8) { System.out.println(month + "月是夏季"); }else if (month >= 9 && month <= 11) { System.out.println(month + "月是秋季"); }else { System.out.println(month + "月是冬季"); } //用if语句来完成月份对应季节的方法二: /* if(month>12 || month<1) { System.out.println("输入的数字不正确"); } else if (month==3 || month==4 || month==4) { System.out.println("春季"); } else if (month==6 || month==7 || month==8) { System.out.println("夏季"); } else if (month==9 || month==10|| month==11) { System.out.println("秋季"); } else { System.out.println("冬季"); } */ } }
3. 流程控制语句之循环结构
循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体语句,当反复执行这个循环体时,需要在合适的时候把循环判断条件修改为false,从而结束循环,否则循环将一直执行下去,形成死循环。 循环语句的组成: l 初始化语句: 一条或者多条语句,这些语句完成一些初始化操作。 l 判断条件语句: 这是一个boolean 表达式,这个表达式能决定是否执行循环体。 l 循环体语句: 这个部分是循环体语句,也就是我们要多次做的事情。 l 控制条件语句: 这个部分在一次循环体结束后,下一次循环判断条件执行前执行。 通过用于控制循环条件中的变量,使得循环在合适的时候结束。 1.1 循环结构的分类 l for l while l do...while
3.1. 循环结构for语句
3.1.1. 循环结构概述和for语句的格式及其使用
3.1.1.1. 循环结构for语句的格式
for(初始化表达式; 条件表达式; 循环后的操作表达式) { 循环体; }
3.1.1.2. 执行流程
① 执行初始化语句 ② 执行判断条件语句,看其返回值是true还是false 如果是true,就继续执行 如果是false,就结束循环 ③ 执行循环体语句; ④ 执行循环后的操作表达式 ⑤ 回到②继续。 
3.1.1.3. 案例:在控制台输出10次"helloworld"
在控制台输出10次"helloworld" class Demo1_For { public static void main(String[] args) { /* //在控制输出10次helloworld,这样做不推荐,因为复用性太差 System.out.println("helloworld"); //............ */ for (int i = 1;i <= 10 ;i++ ) { System.out.println("helloworld"); } } }
3.1.2. 循环结构for语句的练习
3.1.2.1. 练习之获取数据
1.1 获取数据案例 需求:请在控制台输出数据1-10 需求:请在控制台输出数据10-1 class Test1_For { public static void main(String[] args) { for (int i = 1;i <= 10 ;i++ ) { System.out.println("i = " + i); } System.out.println("-----------------------"); for (int i = 10;i >= 1 ;i-- ) { System.out.println("i = " + i); } } } 1.2 注意事项 a. 判断条件语句无论简单还是复杂,结果是boolean类型。 b. 循环体语句如果是一条语句,大括号可以省略; 如果是多条语句,大括号不能省略。建议永远不要省略。 c. 一般来说:有左大括号就没有分号,有分号就没有左大括号
3.1.2.2. 练习之求和思想
1.1 案例:求出1-10之间数据之和 1.2 练习:求偶数和与奇数和 需求:求出1-100之间偶数和 需求:求出1-100之间奇数和 class Test2_For { public static void main(String[] args) { //1-10的和 /*int sum = 0; for (int i = 1;i <= 10 ;i++ ) { sum = sum + i; // sum+=i; } System.out.println("sum = " + sum);*/ //1-100的偶数和 /*int sum = 0; for (int i = 1;i <= 100 ;i++ ) { if (i % 2 == 0) { sum = sum + i; } } System.out.println("sum = " + sum);*/ //1-100的奇数和 int sum = 0; for (int i = 1;i <= 100 ;i+=2 ) { /*if (i % 2 != 0) { sum = sum + i; }*/ sum = sum + i; } System.out.println("sum = " + sum); } }
3.1.2.3. 练习之水仙花数
1.1 案例:在控制台输出所有的”水仙花数” 1所谓的水仙花数是指一个三位数,其各位数字的立方和等于该数本身。 举例:153就是一个水仙花数。 153 = 1*1*1 + 5*5*5 + 3*3*3 = 1 + 125 + 27 = 153 2分析: ① 100 - 999 ② 获取每一个位数的值,百位,十位,个位 ③ 判断各个位上的立方和是否等于这个数,如果等于打印 class Test3_Flower { public static void main(String[] args) { int count = 0; for (int i = 100;i <= 999 ;i++ ) { //获取100到999之间的数 int ge = i % 10; //123 % 10 int shi = i / 10 % 10; //12 % 10; int bai = i / 10 / 10 % 10; //1 % 10 if (ge * ge * ge + shi * shi * shi + bai * bai * bai == i) { count++; } } 输出count } }
3.1.2.4. 练习之统计思想
1.1 案例:统计”水仙花数”共有多少个 分析: 1,需要有一个变量记录住水仙花数的个数 2,获取到所有的3位数 3,判断是否满足水仙花数 4,如果满足条件,计数器就自增 class Test4_FlowerCount { public static void main(String[] args) { int count = 0; for (int i = 100;i <= 999 ;i++ ) { int ge = i % 10; int shi = i / 10 % 10; int bai = i / 10 / 10; if (i == ge * ge * ge + shi * shi * shi + bai * bai * bai) { count ++; //满足条件就自增,计数器思想 } } System.out.println(count); } }
3.2. 循环结构while语句
3.2.1. 循环结构while语句的格式和基本使用
3.2.1.1. 循环结构while语句的格式
l while循环的基本格式: while(判断条件语句) { 循环体语句; } l 完整格式: 初始化语句; while(判断条件语句) { 循环体语句; 控制条件语句; }
3.2.1.2. 执行流程
① 执行初始化语句 ② 执行判断条件语句,看其返回值是true还是false 如果是true,就继续执行 如果是false,就结束循环 ③ 执行循环体语句; ④ 执行控制条件语句 ⑤ 回到②继续。 
3.2.1.3. 6.3案例:请在控制台输出数据1-10
1.1 案例:请在控制台输出数据1-10 class Demo1_While { public static void main(String[] args) { int x = 1; while (x <= 10) { System.out.println("x = " + x); x++; } } }
3.2.2. 循环结构while语句的练习
3.2.2.1. 求和思想:求1-100之和
public void test20() { int i = 1; int sum = 0; while (i <= 100) { sum += i; i++; } System.out.println("sum="+sum); }
3.2.2.2. 统计思想:统计”水仙花数”共有多少个
public void test21() { int num = 0; int i = 100; while (i < 1000) { int ge = i % 10; int shi = i / 10 % 10; int bai = i / 10 / 10 % 10; if (ge * ge * ge + shi * shi * shi + bai * bai * bai == i) { num++; } i++; } System.out.println(num); }
3.3. 循环结构do...while语句
3.3.1. 循环结构do...while语句的格式和基本使用
3.3.1.1. 循环结构do...while语句的格式
l 基本格式 do { 循环体语句; }while(判断条件语句); l 完整格式: 初始化语句; do { 循环体语句; 控制条件语句; }while(判断条件语句);
3.3.1.2. 执行流程
① 执行初始化语句 ② 执行循环体语句; ③ 执行控制条件语句 ④ 执行判断条件语句,看其返回值是true还是false 如果是true,就继续执行 如果是false,就结束循环 ⑤ 回到②继续。 
3.3.1.3. 案例:请在控制台输出数据1-10
public void test22() { int i = 1; do { System.out.println(i); i++; } while (i<=10); }
3.4. 循环结构三种循环语句的区别
3.4.1. 三种循环语句的区别:
a. do...while循环至少执行一次循环体。 b. for,while循环必须先判断条件是否成立,然后决定是否执行循环体语句。 public void test23() { //while 和do while的区别 int i = 11; do { System.out.println("i = " + i); i++; } while (i <= 10); System.out.println("---------------------"); int j = 11; while (j <= 10) { System.out.println("j = " + j); j++; }
3.4.2. for循环和while循环的区别
如果你想在循环结束后,继续使用控制条件的那个变量,用while循环,否则用for循环。 不知道用谁就用for循环。因为变量及早的从内存中消失,可以提高内存的使用效率。 public void test24() { for (int i = 1;i <= 10 ;i++ ) { System.out.println("i = " + i); } //System.out.println("i = " + i); for语句执行后变量会被释放,不能再使用 System.out.println("-------------------"); int i = 1; while (i <= 10) { System.out.println("i = " + i); i++; } System.out.println("-------------------"); System.out.println("i = " + i); //while语句执行后,初始化变量还可以继续使用 }
3.5. 循环结构注意事项之死循环
3.5.1. 注意事项
一定要注意控制条件语句控制的那个变量的问题,不要弄丢了,否则就容易死循环。
3.5.2. 两种最简单的死循环格式
① while(true){...} ② for(;;){...} public void test25() { //while语句的无限循环 while (true) { System.out.println("hello world"); } System.out.println("hello world"); // 无法执行到的语句 // for语句的无限循环 for (; ; ) { System.out.println("hello world"); }
3.6. 循环结构循环嵌套练习
3.6.1. 输出4行5列的星星
for (int i = 1;i <= 4 ;i++ ) { //外循环决定的是行数 for (int j = 1;j <= 5 ;j++ ) { //内循环决定的是列数 System.out.print("*"); } System.out.println(); }
3.6.2. 输出直角三角形
for (int i = 1; i <= 5; i++) { //外循环决定行数 for (int j = 1; j <= i; j++) { //内循环决定列数 System.out.print("*"); } System.out.println(); //将光标换到下一行的行首 }
3.6.3. 九九乘法表
for (int i = 1;i <= 9 ;i++ ) { //行数 for (int j = 1;j <= i ;j++ ) { //列数 System.out.print(j + "*" + i + "=" + (i * j) + "\t" ); } System.out.println(); }
3.7. 控制跳转语句
3.7.1. 代码优化:转义字符
注意: '\x' x表示任意,\是转义符号,这种做法叫转移字符。 '\t' tab键的位置 '\r' 回车 '\n' 换行 '\"' 双引号 '\'' 单引号控制跳转语句break语句【掌握】
3.7.2. 控制跳转语句标号【了解】
l 标号:标记某个循环,对其进行控制 l 标号组成规则:其实就是合法的标识符 一般在开发中给外循环声明标号,内循环声明标号没有意义。 在最外层for的前面定义一个标记A,在多层for循环中如果有满足条件的时候就可以使用break A直接跳出多层循环 class Demo3_Mark { //mark 标记 public static void main(String[] args) { /*outer: for (int i = 1;i <= 10 ;i++ ) { //a就是标号,只要是合法的标识符即可 System.out.println("i = " + i); inner: for (int j = 1;j <= 10 ;j++ ) { System.out.println("j = " + j); break outer; } }*/ System.out.println("大家好"); http://www.heima.com //这里http:就是一个标号,而后面的//是java中的注释,所以相当于给输出语句做了一个标记,没有什么实际的意义 System.out.println("才是真的好"); } }
3.7.3. break语句
3.7.3.1. break的使用场景
a. 在选择结构switch语句中 b. 在循环语句中 c. 离开使用场景的存在是没有意义的
3.7.3.2. break作用
跳出循环,即退出当前循环。
3.7.3.3. 案例
class Demo1_Break { public static void main(String[] args) { //break;写在这报错,break只能用在循环和switch语句中 for (int x = 1;x <= 10 ;x++ ) { if (x == 4) { break; //跳出循环 } System.out.println("x = " + x); } } }
3.7.3.4. 控制跳转语句练习【掌握】
l 练习题: for(int x=1; x<=10; x++) { if(x%3==0) { //在此处填写代码 } System.out.println(“Java基础班”); } 我想在控制台输出2次:“Java基础班“ 我想在控制台输出7次:“Java基础班“ 我想在控制台输出13次:“Java基础班“ class Test1 { public static void main(String[] args) { for(int x=1; x<=10; x++) { if(x%3==0) { //break; //我想在控制台输出2次:“Java基础班“ //continue; //我想在控制台输出7次:“Java基础班“ System.out.println("Java基础班"); //我想在控制台输出13次:“Java基础班“ } System.out.println("Java基础班"); } } }
3.7.4. continue语句
3.7.4.1. continue的使用场景
只能在循环中
3.7.4.2. continue作用
退出本次循环,继续下次循环
3.7.4.3. 案例
class Demo2_Continue { public static void main(String[] args) { for (int x = 1;x <= 10 ;x++ ) { if (x == 4) { continue; //终止本次循环,继续下次循环 } System.out.println("x = " + x); } } }
3.7.4.4. 控制跳转语句练习【掌握】
l 练习题: for(int x=1; x<=10; x++) { if(x%3==0) { //在此处填写代码 } System.out.println(“Java基础班”); } 我想在控制台输出2次:“Java基础班“ 我想在控制台输出7次:“Java基础班“ 我想在控制台输出13次:“Java基础班“ class Test1 { public static void main(String[] args) { for(int x=1; x<=10; x++) { if(x%3==0) { //break; //我想在控制台输出2次:“Java基础班“ //continue; //我想在控制台输出7次:“Java基础班“ System.out.println("Java基础班"); //我想在控制台输出13次:“Java基础班“ } System.out.println("Java基础班"); } } }
3.7.5. return语句
3.7.5.1. return的作用
a. 返回的意思 b. 其实它的作用不是结束循环的,而是结束方法的。
3.7.5.2. 案例
return和break以及continue的区别? ① return是结束方法 ② break是跳出循环 ③ continue是终止本次循环继续下次循环 class Demo4_Return { public static void main(String[] args) { for (int i = 1;i <= 10 ;i++ ) { if (i == 4) { //break; //停止循环 return; //返回的意思,用来返回方法 } } System.out.println("循环结束了"); } }
第十部分:方法
1. 方法概述和格式说明【掌握】
1.1. 什么是方法
完成特定功能的代码块。
1.2. 为什么要有方法
提高代码的复用性。
1.3. 方法的格式
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2,...) 方法体语句; return 返回值; }
1.4. 方法的格式说明
l 修饰符:目前就用 public static。后面我们再详细的讲解其他的修饰符。 l 返回值类型:就是功能结果的数据类型。 l 方法名:符合命名规则即可。方便我们的调用。 l 参数: 实际参数:就是实际参与运算的。 形式参数;就是方法定义上的,用于接收实际参数的。 l 参数类型:就是参数的数据类型 l 参数名:就是变量名 l 方法体语句:就是完成功能的代码。 l return:结束方法的。 返回值:就是功能的结果,由return带给调用者。
2. 方法之求和案例及其调用【掌握】
2.1. 如何写一个方法
,明确返回值类型 2,明确参数列表
2.2. 案例演示:求两个数据之和的案例
public static void main(String[] args) { /*int a = 10; int b = 20; int sum = a + b; System.out.println(sum); int c = 30; int d = 40; int sum2 = c + d; System.out.println(sum2);*/ int sum = add(10,20); System.out.println(sum); //add(30,40); //有返回值方法的单独调用,没有意义 System.out.println(add(30,40)); //这样调用是可以,but如果需要用这个结果不推荐这样调用 //盘子 = 炒菜(地沟油,苏丹红,镉大米,烂白菜); } public static int add(int a,int b) { //int a = 10,int b = 20 int sum = a + b; return sum; //如果有返回值必须用return语句带回 } /* 盘子 炒菜(油,调料,米,菜) { 炒菜的动作 return 一盘菜; } */
2.3. 方法调用图解

3. 方法的注意事项【掌握】
3.1. 方法调用(有具体返回值)
单独调用,一般来说没有意义,所以不推荐 b:输出调用,但是不够好。因为我们可能需要针对结果进行进一步的操作。 c:赋值调用,推荐方案。 int sum = add(3,4);
3.2. 注意事项
a:方法不调用不执行 b:方法与方法是平级关系,不能嵌套定义 c:方法定义的时候参数之间用逗号隔开 d:方法调用的时候不用在传递数据类型 e:如果方法有明确的返回值,一定要有return带回一个值
4. 方法的练习【掌握】
4.1. 案例:键盘录入两个数据,返回两个数中的较大值
public static void main(String[] args) { Scanner sc = new Scanner(System.in); //创建键盘录入对象 System.out.println("请输入第一个整数:"); int x = sc.nextInt(); //将键盘录入的整数存储在x中 System.out.println("请输入第二个整数:"); int y = sc.nextInt(); //将键盘录入的整数存储在y中 int max = getMax(x,y); System.out.println(max); } /* 返回连个整数的较大值 1,明确返回值类型 int 2,明确参数列表 int a,int b */ public static int getMax(int a,int b) { return a > b ? a : b; }
4.2. 案例:键盘录入两个数据,比较两个数是否相等
public static void main(String[] args) { Scanner sc = new Scanner(System.in); //创建键盘录入对象 System.out.println("请输入第一个整数:"); int x = sc.nextInt(); //将键盘录入的整数存储在x中 System.out.println("请输入第二个整数:"); int y = sc.nextInt(); //将键盘录入的整数存储在y中 boolean b = isEquals(x,y); System.out.println(b); } /* 判断两个整数是否相等 1,明确返回值类型 boolean 2,明确参数列表 int a,int b */ public static boolean isEquals(int a,int b) { //isEquals 是否相等 return a == b; }
4.3. 方法之输出星形及其调用【掌握】
import java.util.Scanner; class Demo3_Method { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //创建键盘录入对象 System.out.println("请输入行数:"); int row = sc.nextInt(); //将键盘录入的行数存储在row中 System.out.println("请输入列数:"); int column = sc.nextInt(); //将键盘录入的列数存储在column中 //System.out.println(print(row,column)); //错误: 此处不允许使用 '空' 类型,返回值是void的方法不能输出调用 //返回值是void的方法只能单独调用 print(row,column); } /* 在控制台输出矩形星形 1,明确返回值类型,经分析没有具体的返回值类型,void 2,明确参数列表int a,int b */ public static void print(int a,int b) { for (int i = 1;i <= a ;i++ ) { //行数 for (int j = 1;j <= b ;j++ ) { //列数 System.out.print("*"); } System.out.println(); } //return ; //如果返回值类型是void,return可以省略,即使省略系统也会默认给加上,形式是return; } } 注意: //如果返回值类型是void,return可以省略,即使省略系统也会默认给加上,形式是return; 1.1 方法调用:(无返回值,void) * 单独调用(只能) * 输出调用(错误) * 赋值调用(错误)
4.4. 案例:根据键盘录入的数据输出对应的乘法表
import java.util.Scanner; class Test2_Method { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //创建键盘录入对象 System.out.println("请录入一个整数,范围在1-9之间"); int num = sc.nextInt(); //将键盘录入的整数存储在num中 print99(num); } /* 打印99乘法表 1,返回值类型void 2,参数列表,int a */ public static void print99(int a) { for (int i = 1;i <= a ;i++ ) { //行数 for (int j = 1;j <= i ;j++ ) { //列数 System.out.print(j + "*" + i + "=" + (i * j) + "\t" ); } System.out.println(); } } }
5. 方法重载概述和基本使用【掌握】
5.1. 方法重载概述
1.1 方法重载: l 方法重载:在同一个类中,方法名相同,参数列表不同。与返回值类型无关。 l 参数列表不同: * A:参数个数不同add(int a) add(int a ,int b) * B:参数类型不同add(int a ,int b) add(double a ,double b) * C:参数的顺序不同(算重载,但是在开发中不用) add(int a ,double b) add(double a ,int b)
5.2. 求和案例
求和案例 * 2个整数 * 3个整数 * 4个整数 class Demo4_Overload { //overload重载 public static void main(String[] args) { double sum1 = add(10,20.1); System.out.println(sum1); int sum2 = add(10,20,30); System.out.println(sum2); double sum3 = add(12.3,13); System.out.println(sum3); } /* 求两个整数的和 1,返回值类型int 2,参数列表 int a,int b */ public static double add(int a,double b) { return a + b; } /* 求三个整数的和 1,返回值类型int 2,参数列表 int a,int b,int c */ public static int add(int a,int b,int c) { return a + b + c; } /* 求两个小数的和 1,返回值类型double 2,参数列表 double a,double b */ public static double add(double a,int b) { return a + b; } }
5.3. 方法重载练习比较数据是否相等【掌握】
1.1 案例演示 * 需求:比较两个数据是否相等。 * 参数类型分别为两个int类型,两个double类型,并在main方法中进行测试 class Test3_Overload { public static void main(String[] args) { boolean b1 = isEquals(10,10); System.out.println(b1); boolean b2 = isEquals(10.5,10.5); System.out.println(b2); } /* 比较两个数据是否相等 1,返回值类型boolean 2,参数列表int a,int b */ public static boolean isEquals(int a,int b) { return a == b; } /* 比较两个数据是否相等 1,返回值类型boolean 2,参数列表double a,double b */ public static boolean isEquals(double a,double b) { return a == b; } } 1.2 选择题 已知函数 : void show(int a, int b, float c){ }, 哪个答案和show不是函数重载? B A.void show(int a,float c,int b){ } //参数类型顺序不同 B,void show(int x,int y,float z){ } C.int show(int a, float c, int b){return a;} //参数类型顺序不同,与返回值无关 D.int show(int a, float c ){return a;} //参数个数不同,与返回值无关
第十一部分:数组
1. 数组概述和定义格式说明(了解)
1.1. 为什么要有数组(容器)
为了存储同种数据类型的多个值。
1.2. 数组概念
l 数组是存储同一种数据类型多个元素的集合。也可以看成是一个容器。 数组既可以存储基本数据类型,也可以存储引用数据类型。
1.3. 数组定义格式
数据类型[] 数组名 = new 数据类型[数组的长度]; class Demo1_Array { public static void main(String[] args) { int x = 10; x = 20; System.out.println("x = " + x); //数据类型[] 数组名 = new 数据类型[数组的长度]; int[] arr = new int[5]; //可以存储五个int类型的数据 /* 左边: int:数据类型 []:代表的数组,几个中括号就代表几维数组 arr:合法的标识符 右边: new:创建新的实体或对象 int:数据类型 []:代表的数组 5:代表数组的长度 */ } }
2. 数组的初始化
2.1. 数组的初始化动态初始化【掌握】
2.1.1. 什么是数组的初始化
就是为数组开辟连续的内存空间,并为每个数组元素赋予值。 Java中的数组必须先初始化,然后才能使用。
2.1.2. 如何对数组进行动态初始化
l 格式: 数据类型[] 数组名 = new 数据类型[数组长度]; l 动态初始化 只指定长度,由系统给出初始化值 举例:int[] arr = new int[5];
2.1.3. 案例
2.1.3.1. 输出数组名称和数组元素
 class Demo2_Array { public static void main(String[] args) { //数据类型[] 数组名 = new 数据类型[数组长度]; int[] arr = new int[5]; //动态初始化,在内存中开辟连续的5块空间 System.out.println(arr[0]); //系统给出默认初始化值,整数类型的都是0 arr[0] = 10; System.out.println(arr[0]); System.out.println(arr); //[I@19bb25a } }
2.1.4. 数组元素默认初始化值
数据类型 默认初始化值 整数类型:byte,short,int,long 0 浮点类型:float,double 0.0 布尔类型:boolean false 字符类型:char 一个空字符,即'\u0000' 引用数据类型 null,表示变量不引用任何对象 字符类型:char默认初始化值'\u0000' 之前讲过'',只能放一个字符,但是'\'代表转义字符, u代表unicode编码,java采用的是unicode编码,\u相当于把后面的4个0给转义了。 char在内存中占的两个字节,是16个二进制位 \u0000,每一个0其实代表的是16进制的0,那么四个0就是代表16个二进制位
2.1.5. 数组内存地址值说明
举例:[I@19bb25a l [代表是数组,几个就代表几维 l I代表是int类型 l @是固定的 19bb25a代表的是数组的地址值
2.2. 数组的初始化静态初始化及内存图【掌握】
2.2.1. 如何对数组进行静态初始化
l 格式: 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…}; l 简化格式: 数据类型[] 数组名 = {元素1,元素2,…}; l 静态初始化 给出初始化值,由系统决定长度 举例: int[] arr = new int[]{1,2,3,4,5}; 简化格式: int[] arr = {1,2,3,4,5};
2.2.2. 案例演示
对数组的解释 输出数组名称和数组元素 class Demo6_Array { public static void main(String[] args) { //数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…}; //int[] arr = new int[5]{11,22,33,44,55}; //不允许动静结合 int[] arr2 = {11,22,33,44,55}; //静态初始化的简写形式 //int[] arr; //声明数组引用 //arr = new int[]{11,22,33,44,55}; // 这样写可以 //int[] arr2; //arr2 = {11,22,33,44,55}; //简写形式声明和赋值在同一行,这样写会报错 System.out.println(arr2); System.out.println(arr2[4]); } }
2.2.3. 画图演示
一个数组  
3. 数组的内存图解
3.1. 数组的内存图解1一个数组【掌握】
3.1.1. 案例:一个数组
class Demo3_Array { public static void main(String[] args) { int[] arr = new int[3]; //动态初始化,创建3块连续的空间 System.out.println(arr); arr[0] = 10; arr[1] = 20; System.out.println(arr[0]); System.out.println(arr[1]); } } 1.1 图解 
3.2. 数组的内存图解2二个数组(了解)
3.2.1. 案例:两个数组
class Demo4_Array { public static void main(String[] args) { int[] arr1 = new int[3]; //创建数组,长度为3 int[] arr2 = new int[3]; //创建数组,长度为3 System.out.println(arr1); //打印数组的地址值 System.out.println(arr2); arr1[0] = 10; //给第一个数组中第一个元素赋值 arr2[1] = 20; //给第二个数组中第二个元素赋值 System.out.println(arr1[0]); System.out.println(arr1[1]); System.out.println(arr1[2]); System.out.println("-------------------"); System.out.println(arr2[0]); System.out.println(arr2[1]); System.out.println(arr2[2]); } } 1.1 图解  
3.3. 数组的内存图解3三个引用两个数组(了解)
3.3.1. 案例:三个引用两个数组
class Demo5_Array { public static void main(String[] args) { int[] arr1 = new int[3]; int[] arr2 = new int[5]; int[] arr3 = arr2; System.out.println(arr1); System.out.println(arr2); System.out.println(arr3); arr1[0] = 10; arr1[1] = 20; arr2[1] = 30; arr3[1] = 40; arr3[2] = 50; System.out.println(arr1[0]); System.out.println(arr1[1]); System.out.println(arr1[2]); System.out.println("-------------------------------"); System.out.println(arr2[0]); System.out.println(arr2[1]); System.out.println(arr2[2]); System.out.println(arr2[3]); System.out.println(arr2[4]); System.out.println("-------------------------------"); System.out.println(arr3[0]); System.out.println(arr3[1]); System.out.println(arr3[2]); System.out.println(arr3[3]); System.out.println(arr3[4]); } } 1.1 图解  
4. 数组的操作
4.1. 数组操作的两个常见小问题越界和空指针【掌握】
4.1.1. ArrayIndexOutOfBoundsException:数组索引越界异常
原因:你访问了不存在的索引。 int[] arr = new int[5]; //0x0011 //System.out.println(arr[-1]); //当访问数组中不存在的索引,会出现索引越界异常
4.1.2. NullPointerException:空指针异常
原因:数组已经不在指向堆内存了。而你还用数组名去访问元素。 int[] arr = {1,2,3}; arr = null; System.out.println(arr[0]);
4.2. 数组的操作1遍历【掌握】
1.1 案例:数组遍历 l 数组遍历:就是依次输出数组中的每一个元素。 l 数组的属性:arr.length数组的长度 l 数组的最大索引:arr.length - 1; public static void print(int[] arr) { for (int i = 0;i < arr.length ;i++ ) { System.out.print(arr[i] + " "); } } class Demo8_Array { public static void main(String[] args) { int[] arr = {11,22,33,44,55}; /*System.out.println(arr[0]);//这么做代码的复用性太差,我们学习了循环 System.out.println(arr[1]); System.out.println(arr[2]); System.out.println(arr[3]); System.out.println(arr[4]);*/ for (int i = 0;i < 5 ;i++ ) { System.out.println(arr[i]); } System.out.println("---------------"); //arr.length 代表的是数组的长度 System.out.println(arr.length); for (int i = 0;i < arr.length ;i++ ) { System.out.println(arr[i]); } int[] arr2 = {3,4,5}; print(arr2); } /* 数组的遍历 1,返回值类型void 2,参数列表int[] arr */ public static void print(int[] arr) { for (int i = 0;i < arr.length ;i++ ) { System.out.print(arr[i] + " "); } } }
4.3. 数组的操作2获取最值【掌握】
1.1 案例:数组获取最值(获取数组中的最大值最小值) class Demo9_Array { public static void main(String[] args) { int[] arr = {33,77,22,44,55}; int max = getMax(arr); System.out.println(max); } /* 获取数组中最大值 1,返回值类型int 2,参数列表int[] arr */ public static int getMax(int[] arr) { int max = arr[0]; for (int i = 1;i < arr.length ;i++ ) { //从数组的第二个元素开始遍历 if (max < arr[i]) { //如果max记录的值小于的数组中的元素 max = arr[i]; //max记录住较大的 } } return max; } }
4.4. 数组的操作3反转【掌握】
1.1 案例:数组元素反转(就是把元素对调) class Demo10_Array { public static void main(String[] args) { int[] arr = {11,22,33,44,55}; reverseArray(arr); print(arr); } /* 数组元素反转 1,明确返回值类型void 2,明确参数列表int[] arr */ public static void reverseArray(int[] arr) { for (int i = 0;i < arr.length / 2 ; i++) { //arr[0]和arr[arr.length-1-0]交换 //arr[1]和arr[arr.length-1-1]交换 //arr[2]和arr[arr.lentth-1-2] //... int temp = arr[i]; arr[i] = arr[arr.length-1-i]; arr[arr.length-1-i] = temp; } } public static void reverseArray1(int[] arr) { for(int i=0,j=arr.length-1;i<=j;i++,j--) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } /* 数组遍历 1,明确返回值类型void 2,明确参数列表int[] arr */ public static void print(int[] arr) { for (int i = 0;i < arr.length ;i++ ) { //遍历数组中的每一个元素 System.out.print(arr[i] + " "); //打印在控制台 } } }
4.5. 数组的操作4查表法【掌握】
1.1 案例:数组查表法(根据键盘录入索引,查找对应星期) import java.util.Scanner; class Demo11_Array { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入对应的星期范围在1-7"); int week = sc.nextInt(); System.out.println("星期" + getWeek(week)); } /* 根据索引返回对应的星期 1,返回值类型char 2,参数列表int week */ public static char getWeek(int week) { char[] arr = {' ','一','二','三','四','五','六','日'}; //定义了一张星期表 return arr[week]; //通过索引获取表中的元素 } }
4.6. 数组的操作5基本查找【掌握】
1.1 案例:数组元素查找(查找指定元素第一次在数组中出现的索引) class Demo12_Array { public static void main(String[] args) { int[] arr = {11,22,33,44,55,66,77}; int index = getIndex(arr,88); System.out.println(index); } /* 查找元素索引 1,返回值类型int 2,明确参数列表,int[] arr,int value */ public static int getIndex(int[] arr,int value) { for (int i = 0;i < arr.length ;i++ ) { //数组的遍历 if (arr[i] == value) { //如果数组中的元素与查找的元素匹配 return i; } } return -1; } }
5. 二维数组
5.1. 二维数组概述
我们传智播客的Java基础班每个班有很多个学生,所以,可以用数组来存储,而我们又同时有很多个Java基础班。这个也应该用一个数组来存储。如何来表示这样的数据呢?Java就提供了二维数组供我们使用。 由此可见:其实二维数组其实就是一个元素为一维数组的数组。
5.2. 二维数组格式
5.2.1. 二维数组格式1
数据类型[][] 变量名 = new 数据类型[m][n]; 举例:int[][] arr = new int[3][2];
5.2.1.1. 二维数组格式1的解释
数据类型[][] 变量名 = new 数据类型[m][n]; m表示这个二维数组有多少个一维数组 n表示每一个一维数组的元素个数 举例: int[][] arr = new int[3][2]; 定义了一个二维数组arr 这个二维数组有3个一维数组,名称是arr[0],arr[1],arr[2] 每个一维数组有2个元素,可以通过arr[m][n]来获取 表示获取第m+1个一维数组的第n+1个元素
5.2.1.2. 注意事项
l 以下格式也可以表示二维数组 1:数据类型 数组名[][] = new 数据类型[m][n]; 2:数据类型[] 数组名[] = new 数据类型[m][n]; 但是不建议这样书写,建议中括号跟在数据类型后边。 l 注意下面定义的区别 int x; int y; int x,y; int[] x; int[] y[]; int[] x,y[]; x是一维数组,y是二维数组
5.2.1.3. 案例:定义二维数组,输出二维数组名称,一维数组名称,一个元素
class Demo1_Array { public static void main(String[] args) { int[][] arr = new int[3][2]; /* 这是一个二维数组 这个二维数组中有3个一维数组 每个一维数组中有2个元素 [[I@19bb25a //二维数组的地址值 [I@da6bf4 //一维数组的地址值 0 //元素值 */ System.out.println(arr); //二维数组 System.out.println(arr[0]); //二维数组中的第一个一维数组 System.out.println(arr[0][0]); //二维数组中的第一个一维数组的第一个元素 } }
5.2.1.4. 二维数组格式1的内存图解(了解)
画图讲解上面的二维数组名称,一维数组名称,一个元素的值的问题 class Demo2_Array { public static void main(String[] args) { int[][] arr = new int[3][2]; System.out.println(arr); //打印二维数组 System.out.println(arr[0]); //打印二维数组中的第一个一维数组 System.out.println(arr[0][0]); //打印二维数组中的第一个一维数组中的第一个元素 } }  
5.2.2. 二维数组格式2
数据类型[][] 变量名 = new 数据类型[m][]; 举例: int[][] arr = new int[3][];
5.2.2.1. 二维数组格式2的解释
数据类型[][] 变量名 = new 数据类型[m][]; m表示这个二维数组有多少个一维数组 这一次没有直接给出一维数组的元素个数,可以动态的给出。 举例: int[][] arr = new int[3][]; arr[0] = new int[2]; arr[1] = new int[3] arr[2] = new int[1];
5.2.2.2. 案例演示
讲解格式,输出数据,并画内存图 class Demo3_Array { public static void main(String[] args) { int[][] arr = new int[3][]; //这是一个二维数组,这个二维数组中有三个一维数组,三个一维数组都没有被赋值 System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); arr[0] = new int[3]; //第一个一维数组中可以存储三个int值 arr[1] = new int[5]; //第二个一维数组中可以存储五个int值 System.out.println("------------------"); System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); } }  
5.2.3. 二维数组格式3
数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…}}; 举例: int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};
5.2.3.1. 二维数组格式3的解释
数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…}}; 简化版格式: 数据类型[][] 变量名 = {{元素…},{元素…},{元素…}}; 举例: int[][] arr = {{1,2,3},{4,6},{6}};
5.2.3.2. 案例演示
讲解格式,输出数据,并画内存图 class Demo4_Array { public static void main(String[] args) { int[][] arr = {{1,2,3},{4,5},{6,7,8,9}}; //这是一个二维数组,这个二维数组中每个大括号都代表一个一维数组 System.out.println(arr); //[[I@19bb25a,二维数组的地址值 System.out.println(arr[0]); //[I@da6bf4,一维数组的地址值 System.out.println(arr[0][0]); //1,一维数组中的元素值 } }  
5.3. 二维数组练习
5.3.1. 练习1遍历【掌握】
1.1 案例:二维数组遍历 外循环控制的是二维数组的长度,其实就是一维数组的个数。 内循环控制的是一维数组的长度。 class Test1_Array { public static void main(String[] args) { int[][] arr = {{1,2,3},{4,5},{6,7,8,9}}; for (int i = 0;i < arr.length ;i++ ) { //获取到每个二维数组中的一维数组 for (int j = 0;j < arr[i].length ;j++ ) { //获取每个一维数组中的元素 System.out.print(arr[i][j] + " "); } System.out.println(); } } }
5.3.2. 练习2求和【掌握】
1.1 案例:公司年销售额求和 某公司按照季度和月份统计的数据如下:单位(万元) 第一季度:22,66,44 第二季度:77,33,88 第三季度:25,45,65 第四季度:11,66,99 class Test2_Array { public static void main(String[] args) { int[][] arr = {{22,66,44},{77,33,88},{25,45,65},{11,66,99}}; int sum = 0; //定义变量,记录每次相加的结果 for (int i = 0;i < arr.length ;i++ ) { //获取每一个一维数组 for (int j = 0;j < arr[i].length ;j++ ) { //获取每一个一维数组中的元素 sum = sum + arr[i][j]; //累加 } } System.out.println(sum); } }
6. Java中的参数传递问题及图解【掌握】
基本数据类型的值传递,不改变原值,因为调用后就会弹栈,局部变量随之消失 引用数据类型的值传递,改变原值,因为即使方法弹栈,但是堆内存数组对象还在,可以通过地址继续访问 Java中到底是传值还是传址: 1,既是传值,也是传地址,基本数据类型传递的值,引用数据类型传递的地址 2,java中只有传值,因为地址值也是值(出去面试都说这种,支持者是高司令(java之父)) class Test3_Array { public static void main(String[] args) { /* 基本数据类型 int a = 10; int b = 20; System.out.println("a:"+a+",b:"+b); //a = 10,b = 20 change(a,b); System.out.println("a:"+a+",b:"+b); //?*/ // 引用数据类型 int[] arr = {1,2,3,4,5}; change(arr); System.out.println(arr[1]); } // 基本数据类型值传递 public static void change(int a,int b) { //a = 10, b= 20 System.out.println("a:"+a+",b:"+b); //a = 10,b = 20 a = b; //a = 20 b = a + b; //b = 40 System.out.println("a:"+a+",b:"+b); //a = 20, b = 40 } // 引用数据类型值传递 public static void change(int[] arr) { //1,4,3,8,5 for(int x=0; x<arr.length; x++) { if(arr[x]%2==0) { arr[x]*=2; } } } }   
第十二部分:Java中的内存分配
Java 程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
1. 栈(掌握)
存储局部变量。 哪些是局部变量呢? A:定义在方法中的变量 B:定义在方法的参数上的变量(形式参数) C:定义在for循环里边的变量都是局部变量
2. 堆(掌握)
存储new出来的数组或对象。 a:每一个实体对象都有内存地址值,是一串二进制数值,一般使用十六进制的表示方法。如0x0079。 b:每一个实体对象内的成员变量,都有默认初始化值 c:垃圾回收机制:在垃圾回收器空闲的时候不被引用的对象被回收。 当堆内存中的数组不在被使用的时候,jvm视其为垃圾,会在不确定的时间被垃圾回收器清除。
3. 方法区
面向对象部分讲解 。
4. 本地方法区
和系统相关
5. 寄存器
给CPU使用。 当编译时会生成class文件,这些class文件会保存在硬盘上,当运行时,class文件被加载到内存中,内存中要进行代码的执行,此时有进栈的也有进堆的,谁进栈,谁进堆,要看它属于哪一块,如果是局部变量就进栈,new出来的东西就进堆。一定要跑到内存中才能执行,如果在电脑中开了过多的应用程序,电脑就会卡。   class Demo3_Array { public static void main(String[] args) { int[] arr = new int[3]; } }
第十三部分:面向对象
1. 程序设计思想
1.1. 面向对象
1.1.1. 概述
Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
1.1.2. 举例
洗衣服: 面向过程:把衣服脱下来-->找一个盆-->放点洗衣粉-->加点水-->浸泡10分钟-->揉一揉-->清洗衣服-->拧干-->晾起来 面向对象:把衣服脱下来-->打开全自动洗衣机-->扔衣服-->按钮-->晾起来 区别: 面向过程:强调步骤。 面向对象:强调对象,这里的对象就是洗衣机。
1.1.3. 特点
面向对象思想是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成了指挥者。 面向对象的语言中,包含了三大基本特征,即封装、继承和多态。
1.2. 面向过程
2. 类与对象
2.1. 类
什么是类 类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该 类事物。 现实中,描述一类事物: 属性:就是该事物的状态信息。行为:就是该事物能够做什么。 举例:小猫。 属性:名字、体重、年龄、颜色。 行为:走、跑、叫。
2.1.1. 类的定义
2.1.1.1. 事物与类的对比
现实世界的一类事物: 属性:事物的状态信息。 行为:事物能够做什么。 Java中用class描述事物也是如此: 成员变量:对应事物的属性 成员方法:对应事物的行为
2.1.1.2. 类的定义格式
类的定义格式 public class ClassName { //成员变量 //成员方法 } 定义类:就是定义类的成员,包括成员变量和成员方法。 成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外。 成员方法:和以前定义方法几乎是一样的。只不过把static去掉,static的作用在面向对象后面课程中再详细 讲解。 类的定义格式举例: public class Student { //成员变量 String name; //姓名 int age; //年龄 //成员方法 //学习的方法 public void study() { System.out.println("好好学习,天天向上"); } //吃饭的方法 public void eat() { System.out.println("学习饿了要吃饭"); } }
2.2. 对象
什么是对象 对象:是一类事物的具体体现。对象是类的一个实例(对象并不是找个女朋友),必然具备该类事物的属性 和行为。 现实中,一类事物的一个实例:一只小猫。举例:一只小猫。 属性:tom、5kg、2 years、yellow。 行为:溜墙根走、蹦跶的跑、喵喵叫。
2.2.1. 对象的使用
2.2.1.1. 对象的使用格式
创建对象: 类名 对象名 = new 类名(); 使用对象访问类中的成员: 对象名.成员变量; 对象名.成员方法(); 对象的使用格式举例: public class DiShiSanBuFen { public static void main(String[] args) { //创建对象格式:类名 对象名 = new 类名(); Student s = new Student(); System.out.println("s:" + s); // //直接输出成员变量值 System.out.println("姓名:" + s.name); //null System.out.println("年龄:" + s.age); //0 System.out.println("‐‐‐‐‐‐‐‐‐‐"); //给成员变量赋值 s.name = "赵丽颖"; s.age = 18; //再次输出成员变量的值 System.out.println("姓名:" + s.name); //赵丽颖 System.out.println("年龄:" + s.age); //18 System.out.println("‐‐‐‐‐‐‐‐‐‐"); //调用成员方法 s.study(); // "好好学习,天天向上" s.eat(); // "学习饿了要吃饭" } }
2.2.1.2. 成员变量的默认值
数据类型 默认值 基本类型 整数(byte,short,int,long) 0 浮点数(float,double) 0.0 字符(char) '\u0000' 布尔(boolean) false 引用类型 数组,类,接口 null
2.2.2. 对象内存图
2.2.2.1. 一个对象,调用一个方法内存图
一个对象,调用一个方法内存图 通过上图,我们可以理解,在栈内存中运行的方法,遵循"先进后出,后进先出"的原则。变量p指向堆内存中 的空间,寻找方法信息,去执行该方法。 但是,这里依然有问题存在。创建多个对象时,如果每个对象内部都保存一份方法信息,这就非常浪费内存 了,因为所有对象的方法信息都是一样的。那么如何解决这个问题呢?请看如下图解。 
2.2.2.2. 两个对象,调用同一方法内存图
两个对象,调用同一方法内存图  对象调用方法时,根据对象中方法标记(地址值),去类中寻找方法信息。这样哪怕是多个对象,方法信息 只保存一份,节约内存空间。
2.2.2.3. 一个引用,作为参数传递到方法中内存图
一个引用,作为参数传递到方法中内存图  引用类型作为参数,传递的是地址值。
2.2.3. 对象的简单分类
2.2.3.1. 匿名对象【了解】
2.2.3.1.1. 概念
概念 创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量。虽然是创建对象的简化写法,但是应用 场景非常有限。 匿名对象 :没有变量名的对象。 格式: new 类名(参数列表); 举例: new Scanner(System.in);
2.2.3.1.2. 应用场景
应用场景 1. 创建匿名对象直接调用方法,没有变量名。 new Scanner(System.in).nextInt(); 2. 一旦调用两次方法,就是创建了两个对象,造成浪费,请看如下代码。 new Scanner(System.in).nextInt(); new Scanner(System.in).nextInt(); 小贴士:一个匿名对象,只能使用一次。 3. 匿名对象可以作为方法的参数和返回值 作为参数: class Test { public static void main(String[] args) { // 普通方式 Scanner sc = new Scanner(System.in); input(sc); //匿名对象作为方法接收的参数 input(new Scanner(System.in)); } public static void input(Scanner sc) { System.out.println(sc); } } 作为返回值 : class Test2 { public static void main(String[] args) { // 普通方式 Scanner sc = getScanner(); } public static Scanner getScanner() { //普通方式 // Scanner sc = new Scanner(System.in); // return sc; //匿名对象作为方法返回值 return new Scanner(System.in); } }
2.3. 类与对象的关系
类是对一类事物的描述,是抽象的。 对象是一类事物的实例,是具体的。 类是对象的模板,对象是类的实体。 
2.4. 类与对象的练习
2.5. 成员变量和局部变量区别
变量根据定义位置的不同,我们给变量起了不同的名字。如下图所示:  在类中的位置不同 重点 成员变量:类中,方法外 局部变量:方法中或者方法声明上(形式参数) 作用范围不一样 重点 成员变量:类中 局部变量:方法中 初始化值的不同 重点 成员变量:有默认值 局部变量:没有默认值。必须先定义,赋值,最后使用 在内存中的位置不同 了解 成员变量:堆内存 局部变量:栈内存 生命周期不同 了解 成员变量:随着对象的创建而存在,随着对象的消失而消失 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
2.6. 抽象类
2.6.1. 概述
2.6.1.1. 由来
父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有 意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法 的类就是抽象类。
2.6.1.2. 定义
抽象方法 : 没有方法体的方法。 抽象类:包含抽象方法的类。
2.6.2. abstract使用格式
2.6.2.1. 抽象方法
使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。 定义格式: 修饰符 abstract 返回值类型 方法名 (参数列表); 代码举例: public abstract void run();
2.6.2.2. 抽象类
如果一个类包含抽象方法,那么该类必须是抽象类。 定义格式: abstract class 类名字 { } 代码举例: public abstract class Animal { public abstract void run(); }
2.6.2.3. 抽象的使用
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父 类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。 代码举例: public abstract class Animal { public abstract void run(); } public class Cat extends Animal { public void run (){ System.out.println("小猫在墙头走~~~"); } } public class CatTest { public static void main(String[] args) { // 创建子类对象 Cat c = new Cat(); // 调用run方法 c.run(); } } 输出结果: 小猫在墙头走~~~ 此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法。
2.6.3. 注意事项
关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。 1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。 理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。 2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。 理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。 3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。 理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设 计。 4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象 类。 理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有 意义。
2.7. 接口
2.7.1. 概述
接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么 接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。 接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并 不是类,而是另外一种引用数据类型。 引用数据类型:数组,类,接口。 接口的使用,它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做 是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象 类。
2.7.2. 定义格式
public interface 接口名称 { // 抽象方法 // 默认方法 // 静态方法 // 私有方法 }
2.7.2.1. 含有抽象方法
抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。 代码如下: public interface InterFaceName { public abstract void method(); }
2.7.2.2. 含有默认方法
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。 public interface InterFaceName { public default void method() { // 执行语句 } }
2.7.2.3. 含有静态方法
静态方法:使用 static 修饰,供接口直接调用。 代码如下: public interface InterFaceName { public static void method2() { // 执行语句 } }
2.7.2.4. 含有私有方法
私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。 代码如下: public interface InterFaceName { private void method() { // 执行语句 } }
2.7.3. 基本的实现
2.7.3.1. 实现的概述
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类 似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。 非抽象子类实现接口: 1. 必须重写接口中所有抽象方法。 2. 继承了接口的默认方法,即可以直接调用,也可以重写。 实现格式: class 类名 implements 接口名 { // 重写接口中抽象方法【必须】 // 重写接口中默认方法【可选】 }
2.7.3.2. 方法的使用
2.7.3.2.1. 抽象方法的使用
必须全部实现,代码如下: 定义接口: public interface LiveAble { // 定义抽象方法 public abstract void eat(); public abstract void sleep(); } 定义实现类: public class Animal implements LiveAble { @Override public void eat() { System.out.println("吃东西"); } @Override public void sleep() { System.out.println("晚上睡"); } } 定义测试类: public class InterfaceDemo { public static void main(String[] args) { // 创建子类对象 Animal a = new Animal(); // 调用实现后的方法 a.eat(); a.sleep(); } } 输出结果: 吃东西 晚上睡
2.7.3.2.2. 默认方法的使用
可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。
2.7.3.2.2.1. 继承
1. 继承默认方法,代码如下: 定义接口: public interface LiveAble { public default void fly(){ System.out.println("天上飞"); } } 定义实现类: public class Animal implements LiveAble { // 继承,什么都不用写,直接调用 } 定义测试类: public class InterfaceDemo { public static void main(String[] args) { // 创建子类对象 Animal a = new Animal(); // 调用默认方法 a.fly(); } 输出结果: 天上飞
2.7.3.2.2.2. 重写
2. 重写默认方法,代码如下: 定义接口: public interface LiveAble { public default void fly(){ System.out.println("天上飞"); } } 定义实现类: public class Animal implements LiveAble { @Override public void fly() { System.out.println("自由自在的飞"); } } 定义测试类: public class InterfaceDemo { public static void main(String[] args) { // 创建子类对象 Animal a = new Animal(); // 调用重写方法 a.fly(); } } 输出结果: 自由自在的飞
2.7.3.2.3. 静态方法的使用
静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用,代码如下: 定义接口: public interface LiveAble { public static void run(){ System.out.println("跑起来~~~"); } } 定义实现类: public class Animal implements LiveAble { // 无法重写静态方法 } 定义测试类: public class InterfaceDemo { public static void main(String[] args) { // Animal.run(); // 【错误】无法继承方法,也无法调用 LiveAble.run(); // } } 输出结果: 跑起来~~~
2.7.3.2.4. 私有方法的使用
私有方法:只有默认方法可以调用。 私有静态方法:默认方法和静态方法可以调用。 如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。同学们在已学技术的基础上,可以自行测 试。 定义接口: public interface LiveAble { default void func(){ func1(); func2(); } private void func1(){ System.out.println("跑起来~~~"); } private void func2(){ System.out.println("跑起来~~~"); } }
2.7.4. 接口的多实现
之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接 口的多实现。并且,一个类能继承一个父类,同时实现多个接口。 实现格式: class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... { // 重写接口中抽象方法【必须】 // 重写接口中默认方法【不重名时可选】 } [ ]: 表示可选操作。
2.7.4.1. 抽象方法
接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。代码如 下: 定义多个接口: interface A { public abstract void showA(); public abstract void show(); } interface B { public abstract void showB(); public abstract void show(); } 定义实现类: public class C implements A,B{ @Override public void showA() { System.out.println("showA"); } @Override public void showB() { System.out.println("showB"); } @Override public void show() { System.out.println("show"); } }
2.7.4.2. 默认方法
接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须重写一次。代码如下: 定义多个接口: interface A { public default void methodA(){} public default void method(){} } interface B { public default void methodB(){} public default void method(){} } 定义实现类: public class C implements A,B{ @Override public void method() { System.out.println("method"); } }
2.7.4.3. 静态方法
接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
2.7.4.4. 优先级的问题
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执 行父类的成员方法。代码如下: 定义接口: interface A { public default void methodA(){ System.out.println("AAAAAAAAAAAA"); } } 定义父类: class D { public void methodA(){ System.out.println("DDDDDDDDDDDD"); } } 定义子类: class C extends D implements A { // 未重写methodA方法 } 定义测试类: public class Test { public static void main(String[] args) { C c = new C(); c.methodA(); } } 输出结果: DDDDDDDDDDDD
2.7.5. 接口的多继承【了解】
一个接口能继承另一个或者多个接口,这和类之间的继承比较相似。接口的继承使用 extends 关键字,子接口继 承父接口的方法。如果父接口中的默认方法有重名的,那么子接口需要重写一次。代码如下: 定义父接口: interface A { public default void method(){ System.out.println("AAAAAAAAAAAAAAAAAAA"); } } interface B { public default void method(){ System.out.println("BBBBBBBBBBBBBBBBBBB"); } } 定义子接口: interface D extends A,B{ @Override public default void method() { System.out.println("DDDDDDDDDDDDDD"); } } 小贴士: 子接口重写默认方法时,default关键字可以保留。 子类重写默认方法时,default关键字不可以保留。
2.7.6. 其他成员特点
接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。 接口中,没有构造方法,不能创建对象。 接口中,没有静态代码块。
2.8. 内部类
2.8.1. 概述
2.8.1.1. 什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
2.8.1.2. 成员内部类
成员内部类 :定义在类中方法外的类。 定义格式: class 外部类 { class 内部类{ } } 在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类 Car 中包含发动机 类 Engine ,这时, Engine 就可以使用内部类来描述,定义在成员位置。 代码举例: class Car { //外部类 class Engine { //内部类 } }
2.8.1.3. 访问特点
内部类可以直接访问外部类的成员,包括私有成员。 外部类要访问内部类的成员,必须要建立内部类的对象。 创建内部类对象格式: 外部类名.内部类名 对象名 = new 外部类型().new 内部类型(); 访问演示,代码如下: 定义类: public class Person { private boolean live = true; class Heart { public void jump() { // 直接访问外部类成员 if (live) { System.out.println("心脏在跳动"); } else { System.out.println("心脏不跳了"); } } } public boolean isLive() { return live; } public void setLive(boolean live) { this.live = live; } } 定义测试类: public class InnerDemo { public static void main(String[] args) { // 创建外部类对象 Person p = new Person(); // 创建内部类对象 Heart heart = p.new Heart(); // 调用内部类方法 heart.jump(); // 调用外部类方法 p.setLive(false); // 调用内部类方法 heart.jump(); } } 输出结果: 心脏在跳动 心脏不跳了 内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名 和$符号 。 比如,Person$Heart.class
2.8.2. 匿名内部类【重点】
匿名内部类 :是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。 开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作, 1. 定义子类 2. 重写接口中的方法 3. 创建子类对象 4. 调用重写后的方法 我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快 捷方式。
2.8.2.1. 前提
匿名内部类必须继承一个父类或者实现一个父接口。
2.8.2.2. 格式
new 父类名或者接口名(){ // 方法重写 @Override public void method() { // 执行语句 } };
2.8.2.3. 使用方式
以接口为例,匿名内部类的使用,代码如下: 定义接口: public abstract class FlyAble{ public abstract void fly(); } 创建匿名内部类,并调用: public class InnerDemo { public static void main(String[] args) { /* 1.等号右边:是匿名内部类,定义并创建该接口的子类对象 2.等号左边:是多态赋值,接口类型引用指向子类对象 */ FlyAble f = new FlyAble(){ public void fly() { System.out.println("我飞了~~~"); } }; //调用 fly方法,执行重写后的方法 f.fly(); } } 通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下: public class InnerDemo2 { public static void main(String[] args) { /* 1.等号右边:定义并创建该接口的子类对象 2.等号左边:是多态,接口类型引用指向子类对象 */ FlyAble f = new FlyAble(){ public void fly() { System.out.println("我飞了~~~"); } }; // 将f传递给showFly方法中 showFly(f); } public static void showFly(FlyAble f) { f.fly(); } } 以上两步,也可以简化为一步,代码如下: public class InnerDemo3 { public static void main(String[] args) { /* 创建匿名内部类,直接传递给showFly(FlyAble f) */ showFly( new FlyAble(){ public void fly() { System.out.println("我飞了~~~"); } }); } public static void showFly(FlyAble f) { f.fly(); } }
2.9. 包装类
2.9.1. 概述
Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为 对象可以做更多的功能,如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类,如下: 基本类型 对应的包装类(位于java.lang包中) byte Byte short Short int Integer long Long flfloat Float double Double char Character boolean Boolean
2.9.2. 装箱与拆箱
基本类型与对应的包装类对象之间,来回转换的过程称为”装箱“与”拆箱“: 装箱:从基本类型转换为对应的包装类对象。 拆箱:从包装类对象转换为对应的基本类型。 用Integer与 int为例:(看懂代码即可) 基本数值---->包装对象 Integer i = new Integer(4);//使用构造函数函数 Integer iii = Integer.valueOf(4);//使用包装类中的valueOf方法 包装对象---->基本数值 int num = i.intValue();
2.9.3. 自动装箱与自动拆箱
由于我们经常要做基本类型与包装类之间的转换,从Java 5(JDK 1.5)开始,基本类型与包装类的装箱、拆箱动作 可以自动完成。例如: Integer i = 4;//自动装箱。相当于Integer i = Integer.valueOf(4); i = i + 5;//等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5; //加法运算完成后,再次装箱,把基本数值转成对象。
2.9.4. 基本类型与字符串之间的转换
2.9.4.1. 基本类型转换为String
基本类型转换String总共有三种方式,查看课后资料可以得知,这里只讲最简单的一种方式: 基本类型直接与””相连接即可;如:34+""
2.9.4.2. String转换成对应的基本类型
除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型: public static byte parseByte(String s) :将字符串参数转换为对应的byte基本类型。 public static short parseShort(String s) :将字符串参数转换为对应的short基本类型。 public static int parseInt(String s) :将字符串参数转换为对应的int基本类型。 public static long parseLong(String s) :将字符串参数转换为对应的long基本类型。 public static float parseFloat(String s) :将字符串参数转换为对应的flfloat基本类型。 public static double parseDouble(String s) :将字符串参数转换为对应的double基本类型。 public static boolean parseBoolean(String s) :将字符串参数转换为对应的boolean基本类型。 代码使用(仅以Integer类的静态方法parseXxx为例)如: public class Demo18WrapperParse { public static void main(String[] args) { int num = Integer.parseInt("100"); } } 注意:如果字符串参数的内容无法正确转换为对应的基本类型,则会抛出 java.lang.NumberFormatException 异常。
3. 面向对象的三个基本特性
3.1. 封装
3.1.1. 封装概述
3.1.1.1. 概述
面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。 封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的 方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
3.1.1.2. 原则
将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。
3.1.2. 封装的步骤
1. 使用 private 关键字来修饰成员变量。 2. 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。
3.1.3. 封装的操作——private关键字
3.1.3.1. private的含义
1. private是一个权限修饰符,代表最小权限。 2. 可以修饰成员变量和成员方法。 3. 被private修饰后的成员变量和成员方法,只在本类中才能访问。
3.1.3.2. private的使用格式
private 数据类型 变量名 ; 1. 使用 private 修饰成员变量,代码如下: public class Student { //成员变量 public String name; //姓名 public int age; //年龄 } 2. 提供 getXxx 方法 / setXxx 方法,可以访问成员变量,代码如下: public class Student { //成员变量 public String name; //姓名 public int age; //年龄 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
3.1.4. 封装优化
3.1.4.1. 封装优化1——this关键字
3.1.4.1.1. 发现问题
我们发现 setXxx 方法中的形参名字并不符合见名知意的规定,那么如果修改与成员变量名一致,是否就见名知意 了呢?代码如下: public class Student { private String name; private int age; public void setName(String name) { name = name; } public void setAge(int age) { age = age; } } 经过修改和测试,我们发现新的问题,成员变量赋值失败了。也就是说,在修改了 setXxx() 的形参变量名后,方 法并没有给成员变量赋值!这是由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无 法访问到成员变量,从而赋值失败。所以,我们只能使用this关键字,来解决这个重名问题。
3.1.4.1.2. this的含义
this代表所在类的当前对象的引用(地址值),即对象自己的引用。 记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
3.1.4.1.3. this使用格式
this.成员变量名; 使用 this 修饰方法中的变量,解决成员变量被隐藏的问题,代码如下: public class Student { private String name; private int age; public void setName(String name) { //name = name; this.name = name; } public String getName() { return name; } public void setAge(int age) { //age = age; this.age = age; } public int getAge() { return age; } } 小贴士:方法中只有一个变量名时,默认也是使用 this 修饰,可以省略不写。
3.1.4.2. 封装优化2——构造方法
当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。 小贴士:无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法, 一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。
3.1.4.2.1. 构造方法的定义格式
修饰符 构造方法名(参数列表){ // 方法体 } 构造方法的写法上,方法名与它所在的类名相同。它没有返回值,所以不需要返回值类型,甚至不需要void。使用 构造方法后,代码如下: public class Student { private String name; private int age; // 无参数构造方法 public Student() { } // 有参数构造方法 public Student(String name, int age) { this.name = name; this.age = age; } }
3.1.4.2.2. 注意事项
1. 如果你不提供构造方法,系统会给出无参数构造方法。 2. 如果你提供了构造方法,系统将不再提供无参数构造方法。 3. 构造方法是可以重载的,既可以定义参数,也可以不定义参数。
3.1.5. 标准代码——JavaBean
JavaBean 是 Java语言编写类的一种标准规范。符合 JavaBean 的类,要求类必须是具体的和公共的,并且具有无 参数的构造方法,提供用来操作成员变量的 set 和 get 方法。 public class ClassName { //成员变量 //构造方法 //无参构造方法【必须】 //有参构造方法【建议】 //成员方法 //getXxx() //setXxx() } 编写符合 JavaBean 规范的类,以学生类为例,标准代码如下: public class Student { //成员变量 private String name; private int age; //构造方法 public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } //成员方法 public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } } 测试类,代码如下: public class TestStudent { public static void main(String[] args) { //无参构造使用 Student s = new Student(); s.setName("柳岩"); s.setAge(18); System.out.println(s.getName() + "‐‐‐" + s.getAge()); //带参构造使用 Student s2 = new Student("赵丽颖", 18); System.out.println(s2.getName() + "‐‐‐" + s2.getAge()); } }
3.2. 继承
3.2.1. 概述
3.2.1.1. 由来
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要 继承那一个类即可。如图所示:  其中,多个类可以称为子类,单独那一个类称为父类、超类(superclass)或者基类。 继承描述的是事物之间的所属关系,这种关系是: is-a 的关系。例如,图中兔子属于食草动物,食草动物属于动 物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。
3.2.1.2. 定义
继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接 访问父类中的非私有的属性和行为。
3.2.1.3. 好处
1. 提高代码的复用性。 2. 类与类之间产生了关系,是多态的前提。
3.2.2. 继承的格式
通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下: class 父类 { ... } class 子类 extends 父类 { ... } 继承演示,代码如下: /** * @Description: 继承 继承的格式 * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/6 22:23 * 定义员工类Employee,做为父类 */ static class Employee { String name; // 定义name属性 // 定义员工的工作方法 public void work() { System.out.println("尽心尽力地工作"); } } /* * 定义讲师类Teacher 继承 员工类Employee */ static class Teacher extends Employee { // 定义一个打印name的方法 public void printName() { System.out.println("name=" + name); } } /* * 定义测试类 */ public static class ExtendDemo01 { public static void main(String[] args) { // 创建一个讲师类对象 Teacher t = new Teacher(); // 为该员工类的name属性进行赋值 t.name = "小明"; // 调用该员工的printName()方法 t.printName(); // name = 小明 // 调用Teacher类继承来的work()方法 t.work(); // 尽心尽力地工作 } }
3.2.3. 继承后的特点
3.2.3.1. 成员变量
3.2.3.1.1. 成员变量不重名
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码如下: /** * @Description: 继承后的特点 成员变量 成员变量不重名 * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/6 22:40 */ static class Fu { // Fu中的成员变量。 int num = 5; } static class Zi extends Fu { // Zi中的成员变量 int num2 = 6; // Zi中的成员方法 public void show() { // 访问父类中的num, System.out.println("Fu num=" + num); // 继承而来,所以直接访问。 // 访问子类中的num2 System.out.println("Zi num2=" + num2); } } static class ExtendDemo02 { public static void main(String[] args) { // 创建子类对象 Zi z = new Zi(); // 调用子类中的show方法 z.show(); } } 演示结果: Fu num = 5 Zi num2 = 6
3.2.3.1.2. 成员变量重名
如果子类父类中出现重名的成员变量,这时的访问是有影响的。代码如下: /** * @Description: 继承后的特点 成员变量 成员变量重名 * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/6 22:46 */ static class Fu2 { // Fu中的成员变量。 int num = 5; } static class Zi2 extends Fu2 { // Zi中的成员变量 int num = 6; public void show() { // 访问父类中的num System.out.println("Fu2 num=" + num); // 访问子类中的num System.out.println("Zi2 num=" + num); } } static class ExtendsDemo03 { public static void main(String[] args) { // 创建子类对象 Zi2 z = new Zi2(); // 调用子类中的show方法 z.show(); } } 演示结果: Fu num = 6 Zi num = 6 子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰 父类成员变量,类似于之前学过的 this 。 使用格式: super.父类成员变量名 子类方法需要修改,代码如下: class Zi extends Fu { // Zi中的成员变量 int num = 6; public void show() { //访问父类中的num System.out.println("Fu num=" + super.num); //访问子类中的num System.out.println("Zi num=" + this.num); } } 演示结果: Fu num = 5 Zi num = 6
3.2.3.2. 成员方法
3.2.3.2.1. 成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代码如下: /** * @Description: 继承后的特点 成员方法 成员方法不重名 * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/6 22:56 */ static class Fu3 { public void show() { System.out.println("Fu类中的show方法执行"); } } static class Zi3 extends Fu3 { public void show2() { System.out.println("Zi类中的show2方法执行"); } } public static class ExtendsDemo04 { public static void main(String[] args) { Zi3 z = new Zi3(); //子类中没有show方法,但是可以找到父类方法去执行 z.show(); z.show2(); } }
3.2.3.2.2. 成员方法重名——重写(Override)
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。 方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。 代码如下: /** * @Description: 继承后的特点 成员方法 成员方法重名——重写(Override) * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/6 23:01 */ static class Fu4 { public void show() { System.out.println("Fu show"); } } static class Zi4 extends Fu4 { //子类重写了父类的show方法 public void show() { System.out.println("Zi show"); } } public static class ExtendsDemo05{ public static void main(String[] args) { Zi4 z = new Zi4(); // 子类中有show方法,只执行重写后的show方法 z.show(); // Zi show } }
3.2.3.2.2.1. 重写的应用
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从 而进行扩展增强。比如新的手机增加来电显示头像的功能,代码如下: /** * @Description: 继承后的特点 成员方法 成员方法重名——重写(Override) 重写的应用 * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/6 23:06 */ static class Phone { public void sendMessage() { System.out.println("发短信"); } public void call() { System.out.println("打电话"); } public void showNum() { System.out.println("来电显示号码"); } } //智能手机类 static class NewPhone extends Phone { //重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能 public void showNum() { //调用父类已经存在的功能使用super super.showNum(); //增加自己特有显示姓名和图片功能 System.out.println("显示来电姓名"); System.out.println("显示头像"); } } public static class ExtendsDemo06 { public static void main(String[] args) { // 创建子类对象 NewPhone np = new NewPhone(); // 调用父类继承而来的方法 np.call(); // 调用子类重写的方法 np.showNum(); } } 小贴士:这里重写时,用到super.父类成员方法,表示调用父类的成员方法。
3.2.3.2.2.2. 注意事项
1. 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。 2. 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
3.2.3.3. 构造方法
首先我们要回忆两个事情,构造方法的定义格式和作用。 1. 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。 2. 构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构 造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。代 码如下: /** * @Description: 继承后的特点 构造方法 * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/7 21:56 */ static class Fu5 { private int n; Fu5() { System.out.println("Fu5()"); } } static class Zi5 extends Fu5 { Zi5() { // super(),调用父类构造方法 super(); System.out.println("Zi5()"); } } public static class ExtendsDemo07 { public static void main(String args[]) { Zi5 zi = new Zi5(); } } 输出结果: Fu5() Zi5()
3.2.4. super和this
3.2.4.1. 父类空间优先于子类对象产生
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空 间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构 造方法调用时,一定先调用父类的构造方法。理解图解如下: 
3.2.4.2. super和this的含义
super :代表父类的存储空间标识(可以理解为父亲的引用)。 this :代表当前对象的引用(谁调用就代表谁)。
3.2.4.3. super和this的用法
3.2.4.3.1. 访问成员
this.成员变量 ‐‐ 本类的 super.成员变量 ‐‐ 父类的 this.成员方法名() ‐‐ 本类的 super.成员方法名() ‐‐ 父类的 用法演示,代码如下: /** * @Description: 继承 super和this super和this的用法 访问成员 * @Param: * @return: * @Author: Mr.Yang * @Date: 2020/5/7 22:12 */ static class Animal { public void eat() { System.out.println("animal : eat"); } } static class Cat extends Animal { public void eat() { System.out.println("cat : eat"); } public void eatTest() { this.eat(); // this 调用本类的方法 super.eat(); // super 调用父类的方法 } } public static class ExtendsDemo08 { public static void main(String[] args) { Animal a = new Animal(); a.eat(); Cat c = new Cat(); c.eatTest(); } } 输出结果为: animal : eat cat : eat animal : eat
3.2.4.3.2. 访问构造方法
this(...) ‐‐ 本类的构造方法 super(...) ‐‐ 父类的构造方法 子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。 super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。
3.2.5. 继承的特点
1. Java只支持单继承,不支持多继承。 //一个类只能有一个父类,不可以有多个父类。 class C extends A{} //ok class C extends A,B... //error 2. Java支持多层继承(继承体系)。 class A{} class B extends A{} class C extends B{} 顶层父类是Object类。所有的类默认继承Object,作为父类。 3. 子类和父类是一种相对的概念。
3.2.6. 综合案例
群主发普通红包。某群有多名成员,群主给成员发普通红包。普通红包的规则: 1. 群主的一笔金额,从群主余额中扣除,平均分成n等份,让成员领取。 2. 成员领取红包后,保存到成员余额中。 请根据描述,完成案例中所有类的定义以及指定类之间的继承关系,并完成发红包的操作。 3.2 案例分析 根据描述分析,得出如下继承体系:  3.3 案例实现 定义用户类: public class User { // 成员变量 private String username; // 用户名 private double leftMoney; // 余额 // 构造方法 public User() { } public User(String username, double leftMoney) { this.username = username; this.leftMoney = leftMoney; } // get/set方法 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public double getLeftMoney() { return leftMoney; } public void setLeftMoney(double leftMoney) { this.leftMoney = leftMoney; } // 展示信息的方法 public void show() { System.out.println("用户名:"+ username +" , 余额为:" + leftMoney + "元"); } } 定义群主类: public class QunZhu extends User { // 添加构造方法 public QunZhu() { } public QunZhu(String username, double leftMoney) { // 通过super 调用父类构造方法 super(username, leftMoney); } /* 群主发红包,就是把一个整数的金额,分层若干等份。 1.获取群主余额,是否够发红包. 不能则返回null,并提示. 能则继续. 2.修改群主余额. 3.拆分红包. 3.1.如果能整除,那么就平均分。 3.2.如果不能整除,那么就把余数分给最后一份。 */ public ArrayList<Double> send(int money, int count) { // 获取群主余额 double leftMoney = getLeftMoney(); if(money > leftMoney) { return null; } // 修改群主余额的 setLeftMoney(leftMoney ‐ money); // 创建一个集合,保存等份金额 ArrayList<Double> list = new ArrayList<>(); // 扩大100倍,相当于折算成'分'为单位,避免小数运算损失精度的问题 money = money * 100; // 每份的金额 int m = money / count; // 不能整除的余数 int l = money % count; // 无论是否整除,n‐1份,都是每份的等额金额 for (int i = 0; i < count ‐ 1; i++) { // 缩小100倍,折算成 '元' list.add(m / 100.0); } // 判断是否整除 if (l == 0) { // 能整除, 最后一份金额,与之前每份金额一致 list.add(m / 100.0); } else { // 不能整除, 最后一份的金额,是之前每份金额+余数金额 list.add((m + l) / 100.00); } // 返回集合 return list; } } 定义成员类: public class Member extends User { public Member() { } public Member(String username, double leftMoney) { super(username, leftMoney); } // 打开红包,就是从集合中,随机取出一份,保存到自己的余额中 public void openHongbao(ArrayList<Double> list) { // 创建Random对象 Random r = new Random(); // 随机生成一个角标 int index = r.nextInt(list.size()); // 移除一个金额 Double money = list.remove(index); // 直接调用父类方法,设置到余额 setLeftMoney( money ); } } 定义测试类: public class Test { public static void main(String[] args) { // 创建一个群主对象 QunZhu qz = new QunZhu("群主" , 200); // 创建一个键盘录入 Scanner sc = new Scanner(); System.out.println("请输入金额:"); int money = sc.nextInt(); System.out.println("请输入个数:"); int count = sc.nextInt(); // 发送红包 ArrayList<Double> sendList = s.send(money,count); // 判断,如果余额不足 if(sendList == null){ System.out.println(" 余额不足..."); return; } // 创建三个成员 Member m = new Member(); Member m2 = new Member(); Member m3 = new Member(); // 打开红包 m.openHongbao(sendList); m2.openHongbao(sendList); m3.openHongbao(sendList); // 展示信息 qz.show(); m.show(); m2.show(); m3.show(); } } 课后请同学自己思考并完成扩展需求。 案例扩展: 1. 如果成员的余额不为0呢,将如何处理? 2. 如果群主想输入带小数的金额呢,将如何处理?
3.3. 多态
3.3.1. 概述
3.3.1.1. 引入
多态是继封装、继承之后,面向对象的第三大特性。 生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
3.3.1.2. 定义
多态: 是指同一行为,具有多个不同表现形式。
3.3.1.3. 前提【重点】
1. 继承或者实现【二选一】 2. 方法的重写【意义体现:不重写,无意义】 3. 父类引用指向子类对象【格式体现】
3.3.2. 多态的体现
多态体现的格式: 父类类型 变量名 = new 子类对象; 变量名.方法名(); 父类类型:指子类对象继承的父类类型,或者实现的父接口类型。 代码如下: Fu f = new Zi(); f.method(); 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写 后方法。 代码如下: 定义父类: public abstract class Animal { public abstract void eat(); } 定义子类: class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨头"); } } 定义测试类: public class Test { public static void main(String[] args) { // 多态形式,创建对象 Animal a1 = new Cat(); // 调用的是 Cat 的 eat a1.eat(); // 多态形式,创建对象 Animal a2 = new Dog(); // 调用的是 Dog 的 eat a2.eat(); } }
3.3.3. 多态的好处
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展 性与便利。代码如下: 定义父类: public abstract class Animal { public abstract void eat(); } 定义子类: class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨头"); } } 定义测试类: public class Test { public static void main(String[] args) { // 多态形式,创建对象 Cat c = new Cat(); Dog d = new Dog(); // 调用showCatEat showCatEat(c); // 调用showDogEat showDogEat(d); /* 以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代 而执行效果一致 */ showAnimalEat(c); showAnimalEat(d); } public static void showCatEat (Cat c){ c.eat(); } public static void showDogEat (Dog d){ d.eat(); } public static void showAnimalEat (Animal a){ a.eat(); } } 由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当 然可以把Cat对象和Dog对象,传递给方法。 当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致, 所以showAnimalEat完全可以替代以上两方法。 不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用 showAnimalEat都可以完成。 所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。
3.3.4. 引用类型转换
3.3.4.1. 向上转型
向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。 使用格式: 父类类型 变量名 = new 子类类型(); 如:Animal a = new Cat();
3.3.4.2. 向下转型
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。 使用格式: 子类类型 变量名 = (子类类型) 父类变量名; 如:Cat c =(Cat) a;
3.3.4.3. 为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥 有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子 类特有的方法,必须做向下转型。 转型演示,代码如下: 定义类: abstract class Animal { abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨头"); } public void watchHouse() { System.out.println("看家"); } } 定义测试类: public class Test { public static void main(String[] args) { // 向上转型 Animal a = new Cat(); a.eat(); // 调用的是 Cat 的 eat // 向下转型 Cat c = (Cat)a; c.catchMouse(); // 调用的是 Cat 的 catchMouse } }
3.3.4.4. 转型的异常
转型的过程中,一不小心就会遇到这样的问题,请看如下代码: public class Test { public static void main(String[] args) { // 向上转型 Animal a = new Cat(); a.eat(); // 调用的是 Cat 的 eat // 向下转型 Dog d = (Dog)a; d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】 } } 这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了 Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。 为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下: 变量名 instanceof 数据类型 如果变量属于该数据类型,返回true。 如果变量不属于该数据类型,返回false。 所以,转换前,我们最好先做一个判断,代码如下: public class Test { public static void main(String[] args) { // 向上转型 Animal a = new Cat(); a.eat(); // 调用的是 Cat 的 eat // 向下转型 if (a instanceof Cat){ Cat c = (Cat)a; c.catchMouse(); // 调用的是 Cat 的 catchMouse } else if (a instanceof Dog){ Dog d = (Dog)a; d.watchHouse(); // 调用的是 Dog 的 watchHouse } } }
3.3.5. 接口多态的综合案例
3.1 笔记本电脑 笔记本电脑(laptop)通常具备使用USB设备的功能。在生产时,笔记本都预留了可以插入USB设备的USB接口, 但具体是什么USB设备,笔记本厂商并不关心,只要符合USB规格的设备都可以。 定义USB接口,具备最基本的开启功能和关闭功能。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守 USB规范,实现USB接口,否则鼠标和键盘的生产出来也无法使用。 3.2 案例分析 进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘 USB接口,包含开启功能、关闭功能 笔记本类,包含运行功能、关机功能、使用USB设备功能 鼠标类,要实现USB接口,并具备点击的方法 键盘类,要实现USB接口,具备敲击的方法 3.3 案例实现 定义USB接口: interface USB { void open();// 开启功能 void close();// 关闭功能 } 定义鼠标类: class Mouse implements USB { public void open() { System.out.println("鼠标开启,红灯闪一闪"); } public void close() { System.out.println("鼠标关闭,红灯熄灭"); } public void click(){ System.out.println("鼠标单击"); } } 定义键盘类: class KeyBoard implements USB { public void open() { System.out.println("键盘开启,绿灯闪一闪"); } public void close() { System.out.println("键盘关闭,绿灯熄灭"); } public void type(){ System.out.println("键盘打字"); } } 定义笔记本类: class Laptop { // 笔记本开启运行功能 public void run() { System.out.println("笔记本运行"); } // 笔记本使用usb设备,这时当笔记本对象调用这个功能时,必须给其传递一个符合USB规则的USB设备 public void useUSB(USB usb) { // 判断是否有USB设备 if (usb != null) { usb.open(); // 类型转换,调用特有方法 if(usb instanceof Mouse){ Mouse m = (Mouse)usb; m.click(); }else if (usb instanceof KeyBoard){ KeyBoard kb = (KeyBoard)usb; kb.type(); } usb.close(); } } public void shutDown() { System.out.println("笔记本关闭"); } } 测试类,代码如下: public class Test { public static void main(String[] args) { // 创建笔记本实体对象 Laptop lt = new Laptop(); // 笔记本开启 lt.run(); // 创建鼠标实体对象 USB u = new Mouse(); // 笔记本使用鼠标 lt.useUSB(u); // 创建键盘实体对象 KeyBoard kb = new KeyBoard(); // 笔记本使用键盘 lt.useUSB(kb); // 笔记本关闭 lt.shutDown(); } }
4. 引用类型用法总结
实际的开发中,引用类型的使用非常重要,也是非常普遍的。我们可以在理解基本类型的使用方式基础上,进一步 去掌握引用类型的使用方式。基本类型可以作为成员变量、作为方法的参数、作为方法的返回值,那么当然引用类 型也是可以的。
4.1. class作为成员变量
在定义一个类Role(游戏角色)时,代码如下: class Role { int id; // 角色id int blood; // 生命值 String name; // 角色名称 } 使用 int 类型表示 角色id和生命值,使用 String 类型表示姓名。此时, String 本身就是引用类型,由于使用 的方式类似常量,所以往往忽略了它是引用类型的存在。如果我们继续丰富这个类的定义,给 Role 增加武器,穿 戴装备等属性,我们将如何编写呢? 定义武器类,将增加攻击能力: class Weapon { String name; // 武器名称 int hurt; // 伤害值 } 定义穿戴盔甲类,将增加防御能力,也就是提升生命值: class Armour { String name;// 装备名称 int protect;// 防御值 } 定义角色类: class Role { int id; int blood; String name; // 添加武器属性 Weapon wp; // 添加盔甲属性 Armour ar; // 提供get/set方法 public Weapon getWp() { return wp; } public void setWeapon(Weapon wp) { this.wp = wp; } public Armour getArmour() { return ar; } public void setArmour(Armour ar) { this.ar = ar; } // 攻击方法 public void attack(){ System.out.println("使用"+ wp.getName() +", 造成"+wp.getHurt()+"点伤害"); } // 穿戴盔甲 public void wear(){ // 增加防御,就是增加blood值 this.blood += ar.getProtect(); System.out.println("穿上"+ar.getName()+", 生命值增加"+ar.getProtect()); } } 测试类: public class Test { public static void main(String[] args) { // 创建Weapon 对象 Weapon wp = new Weapon("屠龙刀" , 999999); // 创建Armour 对象 Armour ar = new Armour("麒麟甲",10000); // 创建Role 对象 Role r = new Role(); // 设置武器属性 r.setWeapon(wp); // 设置盔甲属性 r.setArmour(ar); // 攻击 r.attack(); // 穿戴盔甲 r.wear(); } } 输出结果: 使用屠龙刀,造成999999点伤害 穿上麒麟甲 ,生命值增加10000 类作为成员变量时,对它进行赋值的操作,实际上,是赋给它该类的一个对象。
4.2. interface作为成员变量
接口是对方法的封装,对应游戏当中,可以看作是扩展游戏角色的技能。所以,如果想扩展更强大技能,我们在 Role 中,可以增加接口作为成员变量,来设置不同的技能。 定义接口: // 法术攻击 public interface FaShuSkill { public abstract void faShuAttack(); } 定义角色类: public class Role { FaShuSkill fs; public void setFaShuSkill(FaShuSkill fs) { this.fs = fs; } // 法术攻击 public void faShuSkillAttack(){ System.out.print("发动法术攻击:"); fs.faShuAttack(); System.out.println("攻击完毕"); } } 定义测试类: public class Test { public static void main(String[] args) { // 创建游戏角色 Role role = new Role(); // 设置角色法术技能 role.setFaShuSkill(new FaShuSkill() { @Override public void faShuAttack() { System.out.println("纵横天下"); } }); // 发动法术攻击 role.faShuSkillAttack(); // 更换技能 role.setFaShuSkill(new FaShuSkill() { @Override public void faShuAttack() { System.out.println("逆转乾坤"); } }); // 发动法术攻击 role.faShuSkillAttack(); } } 输出结果: 发动法术攻击:纵横天下 攻击完毕 发动法术攻击:逆转乾坤 攻击完毕 我们使用一个接口,作为成员变量,以便随时更换技能,这样的设计更为灵活,增强了程序的扩展性。 接口作为成员变量时,对它进行赋值的操作,实际上,是赋给它该接口的一个子类对象。
4.3. interface作为方法参数和返回值类型
当接口作为方法的参数时,需要传递什么呢?当接口作为方法的返回值类型时,需要返回什么呢?对,其实都是它的 子类对象。 ArrayList 类我们并不陌生,查看API我们发现,实际上,它是 java.util.List 接口的实现类。所 以,当我们看见 List 接口作为参数或者返回值类型时,当然可以将 ArrayList 的对象进行传递或返回。 请观察如下方法:获取某集合中所有的偶数。 定义方法: public static List<Integer> getEvenNum(List<Integer> list) { // 创建保存偶数的集合 ArrayList<Integer> evenList = new ArrayList<>(); // 遍历集合list,判断元素为偶数,就添加到evenList中 for (int i = 0; i < list.size(); i++) { Integer integer = list.get(i); if (integer % 2 == 0) { evenList.add(integer); } } /* 返回偶数集合 因为getEvenNum方法的返回值类型是List,而ArrayList是List的子类, 所以evenList可以返回 */ return evenList; } 调用方法: public class Test { public static void main(String[] args) { // 创建ArrayList集合,并添加数字 ArrayList<Integer> srcList = new ArrayList<>(); for (int i = 0; i < 10; i++) { srcList.add(i); } /* 获取偶数集合 因为getEvenNum方法的参数是List,而ArrayList是List的子类, 所以srcList可以传递 */ List list = getEvenNum(srcList); System.out.println(list); } } 接口作为参数时,传递它的子类对象。 接口作为返回值类型时,返回它的子类对象。
第十四部分:Java的API
第十五部分:泛型
1. 泛型概述
在前面学习集合时,我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升 成Object类型。当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换。 大家观察下面代码: public class GenericDemo { public static void main(String[] args) { Collection coll = new ArrayList(); coll.add("abc"); coll.add("itcast"); coll.add(5);//由于集合没有做任何限定,任何类型都可以给其中存放 Iterator it = coll.iterator(); while(it.hasNext()){ //需要打印每个字符串的长度,就要把迭代出来的对象转成String类型 String str = (String) it.next(); System.out.println(str.length()); } } } 程序在运行时发生了问题java.lang.ClassCastException。 为什么会发生类型转换异常呢? 我们来分析下:由于 集合中什么类型的元素都可以存储。导致取出时强转引发运行时ClassCastException。 怎么来解决这个问题呢? Collection虽然可以存储各种对象,但实际上通常Collection只存储同一类型对象。例如都是存储字符串对象。因此 在JDK5之后,新增了泛型(Generic)语法,让你在设计API时可以指定类或方法支持泛型,这样我们使用API的时候 也变得更为简洁,并得到了编译时期的语法检查。 泛型:可以在类或方法中预支地使用未知的类型。 tips:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
2. 使用泛型的好处
上一节只是讲解了泛型的引入,那么泛型带来了哪些好处呢? 将运行时期的ClassCastException,转移到了编译时期变成了编译失败。 避免了类型强转的麻烦。 通过我们如下代码体验一下: public class GenericDemo2 { public static void main(String[] args) { Collection<String> list = new ArrayList<String>(); list.add("abc"); list.add("itcast"); // list.add(5);//当集合明确类型后,存放类型不一致就会编译报错 // 集合已经明确具体存放的元素类型,那么在使用迭代器的时候,迭代器也同样会知道具体遍历元素类型 Iterator<String> it = list.iterator(); while(it.hasNext()){ String str = it.next(); //当使用Iterator<String>控制元素类型后,就不需要强转了。获取到的元素直接就是String类型 System.out.println(str.length()); } } } tips:泛型是数据类型的一部分,我们将类名与泛型合并一起看做数据类型。
3. 泛型的定义与使用
3.1. 定义和使用含有泛型的类
定义格式: 修饰符 class 类名<代表泛型的变量> { } 例如,API中的ArrayList集合: class ArrayList<E>{ public boolean add(E e){ } public E get(int index){ } .... } 使用泛型: 即什么时候确定泛型。 在创建对象的时候确定泛型 例如, ArrayList<String> list = new ArrayList<String>(); 此时,变量E的值就是String类型,那么我们的类型就可以理解为: class ArrayList<String>{ public boolean add(String e){ } public String get(int index){ } ... } 再例如, ArrayList<Integer> list = new ArrayList<Integer>(); 此时,变量E的值就是Integer类型,那么我们的类型就可以理解为: class ArrayList<Integer> { public boolean add(Integer e) { } public Integer get(int index) { } ... } 举例自定义泛型类 public class MyGenericClass<MVP> { //没有MVP类型,在这里代表 未知的一种数据类型 未来传递什么就是什么类型 private MVP mvp; public void setMVP(MVP mvp) { this.mvp = mvp; } public MVP getMVP() { return mvp; } } 使用: public class GenericClassDemo { public static void main(String[] args) { // 创建一个泛型为String的类 MyGenericClass<String> my = new MyGenericClass<String>(); // 调用setMVP my.setMVP("大胡子登登"); // 调用getMVP String mvp = my.getMVP(); System.out.println(mvp); //创建一个泛型为Integer的类 MyGenericClass<Integer> my2 = new MyGenericClass<Integer>(); my2.setMVP(123); Integer mvp2 = my2.getMVP(); } }
3.2. 含有泛型的方法
定义格式: 修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ } 例如, public class MyGenericMethod { public <MVP> void show(MVP mvp) { System.out.println(mvp.getClass()); } public <MVP> MVP show2(MVP mvp) { return mvp; } } 使用格式:调用方法时,确定泛型的类型 public class GenericMethodDemo { public static void main(String[] args) { // 创建对象 MyGenericMethod mm = new MyGenericMethod(); // 演示看方法提示 mm.show("aaa"); mm.show(123); mm.show(12.45); } }
3.3. 含有泛型的接口
定义格式: 修饰符 interface接口名<代表泛型的变量> { } 例如, public interface MyGenericInterface<E>{ public abstract void add(E e); public abstract E getE(); } 使用格式: 1、定义类时确定泛型的类型 例如 public class MyImp1 implements MyGenericInterface<String> { @Override public void add(String e) { // 省略... } @Override public String getE() { return null; } } 此时,泛型E的值就是String类型。 2、始终不确定泛型的类型,直到创建对象时,确定泛型的类型 例如 public class MyImp2<E> implements MyGenericInterface<E> { @Override public void add(E e) { // 省略... } @Override public E getE() { return null; } } 确定泛型: /* * 使用 */ public class GenericInterface { public static void main(String[] args) { MyImp2<String> my = new MyImp2<String>(); my.add("aa"); } }
4. 泛型通配符
4.1. 通配符基本使用
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。 此时只能接受数据,不能往该集合中存储数据。 举个例子大家理解使用即可: public static void main(String[] args) { Collection<Intger> list1 = new ArrayList<Integer>(); getElement(list1); Collection<String> list2 = new ArrayList<String>(); getElement(list2); } public static void getElement(Collection<?> coll){} //?代表可以接收任意类型 tips:泛型不存在继承关系 Collection list = new ArrayList();这种是错误的。
4.2. 通配符高级使用----受限泛型
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个 泛型的上限和下限。 泛型的上限: 格式: 类型名称 <? extends 类 > 对象名称 意义: 只能接收该类型及其子类 泛型的下限: 格式: 类型名称 <? super 类 > 对象名称 意义: 只能接收该类型及其父类型 比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类 public static void main(String[] args) { Collection<Integer> list1 = new ArrayList<Integer>(); Collection<String> list2 = new ArrayList<String>(); Collection<Number> list3 = new ArrayList<Number>(); Collection<Object> list4 = new ArrayList<Object>(); getElement(list1); getElement(list2);//报错 getElement(list3); getElement(list4);//报错 getElement2(list1);//报错 getElement2(list2);//报错 getElement2(list3); getElement2(list4); } // 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类 public static void getElement1(Collection<? extends Number> coll){} // 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类 public static void getElement2(Collection<? super Number> coll){}
第十六部分:IO流
1. File类
2. 递归
3. Properties类
4. IO异常的处理
5. 各种流
5.1. 字节流
5.2. 字符流
5.3. 缓冲流
5.4. 转换流
5.5. 序列化流
5.6. 打印流
第十七部分:多线程
1. 线程多线程概述
2. 线程安全
3. 线程状态
4. 等待唤醒机制
5. 线程池
6. wait(), notify(), notifyAll(),join(),sleep(),yield()等方法介绍
第十八部分:数据结构和算法
1. 数据结构
1.1. 数据结构有什么用?
1.2. 常见的数据结构
1.2.1. 栈
1.2.2. 队列
1.2.3. 数组
1.2.4. 链表
1.2.5. 红黑树
2. 算法
第十九部分:异常
第二十部分:网络编程
第二十一部分:函数式接口