ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java基础

2020-12-24 18:29:27  阅读:143  来源: 互联网

标签:Java 对象 基础 线程 数组 方法 public


Java基础知识图解

在这里插入图片描述

Java基础概述

第一部分:编程语言核心结构

主要知识点:变量、基本语法、分支、循环、数组、…

第二部分:Java面向对象的核心逻辑

主要知识点:OOP、封装、继承、多态、接口、…

第三部分:开发Java SE高级应用程序

主要知识点:异常、集合、I/O、多线程、反射机制、网络编程、……

Java基础体系

第1章 Java语言概述

第2章 基本语法

第3章 数组

第4章 面向对象编程(上)

第5章 面向对象编程(中)

第6章 面向对象编程(下)

第7章 异常处理

第8章 枚举类&注解

第9章 Java集合

 第10章 泛型

 第11章 IO流

 第12章 多线程

 第13章 Java常用类

 第14章 Java反射机制

 第15章 网络编程

 第16章 Lambda表达式与Stream API

 第17章 Java 9 & 10 & 11新特性

1.1 软件开发介绍

 软件开发 软件,即一系列按照特定顺序组织的计算机数据和指令的集合。有系统软
件和应用软件之分。
 人机交互方式
 图形化界面(Graphical User Interface GUI)这种方式简单直观,使用
者易于接受,容易上手操作。
 命令行方式(Command Line Interface CLI):需要有一个控制台,输
入特定的指令,让计算机完成一些操作。较为麻烦,需要记录住一些
命令。
Pascal之父Nicklaus Wirth: “Algorithms+Data Structures=Programs”

1.2 软件开发介绍

常用的DOS命令 dir : 列出当前目录下的文件以及文件夹 md : 创建目录 rd : 删除目录 cd : 进入指定目录 cd… : 退回到上一级目录 cd: 退回到根目录 del : 删除文件 exit : 退出 dos 命令行  补充:echo javase>1.doc  常用快捷键  ← →:移动光标  ↑ ↓:调阅历史操作命令  Delete和Backspace:删除字符

1.2 计算机编程语言介绍

什么是计算机语言
语言:是人与人之间用于沟通的一种方式。例如:中国人与中国人用普通话沟通。而
中国人要和英国人交流,就要学习英语。
计算机语言:人与计算机交流的方式。
如果人要与计算机交流,那么就要学习计算机语言。
计算机语言有很多种。如:C ,C++ ,Java ,PHP , Kotlin,Python,Scala等。
 第一代语言  机器语言。指令以二进制代码形式存在。
 第二代语言  汇编语言。使用助记符表示一条机器指令。
在这里插入图片描述
 第三代语言:高级语言
 C、Pascal、Fortran面向过程的语言  C++面向过程/面向对象  Java跨平台的纯面向对象的语言  .NET跨语言的平台  Python、Scala…
在这里插入图片描述
1.从java语言的市场需求来看
在这里插入图片描述
在这里插入图片描述

1.3 Java语言概述

 是SUN(Stanford University Network,斯坦福大学网络公司 ) 1995年推出的一 门高级编程语言。
 是一种面向Internet的编程语言。Java一开始富有吸引力是因为Java程序可以 在Web浏览器中运行。这些Java程序被称为Java小程序(applet)。applet使 用现代的图形用户界面与Web用户进行交互。 applet内嵌在HTML代码中。
 随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。
后台开发:Java、PHP、Python、Go、Node.js
1.3 Java语言概述:Java简史
 1991年 Green项目,开发语言最初命名为Oak (橡树)  1994年,开发组意识到Oak 非常适合于互联网  1996年,发布JDK 1.0,约8.3万个网页应用Java技术来制作  1997年,发布JDK 1.1,JavaOne会议召开,创当时全球同类会议规模之最  1998年,发布JDK 1.2,同年发布企业平台J2EE  1999年,Java分成J2SE、J2EE和J2ME,JSP/Servlet技术诞生  2004年,发布里程碑式版本:JDK 1.5,为突出此版本的重要性,更名为JDK 5.0  2005年,J2SE -> JavaSE,J2EE -> JavaEE,J2ME -> JavaME  2009年,Oracle公司收购SUN,交易价格74亿美元  2011年,发布JDK 7.0  2014年,发布JDK 8.0,是继JDK 5.0以来变化最大的版本  2017年,发布JDK 9.0,最大限度实现模块化  2018年3月,发布JDK 10.0,版本号也称为18.3  2018年9月,发布JDK 11.0,版本号也称为18.9
在这里插入图片描述
在这里插入图片描述

1.3 Java语言概述:Java在各领域的应用

• 从Java的应用领域来分,Java语言的应用方向主要表现在以下几个方面: • 企业级应用:主要指复杂的大企业的软件系统、各种类型的网站。Java的安全机制以及
它的跨平台的优势,使它在分布式系统领域开发中有广泛应用。应用领域包括金融、电
信、交通、电子商务等。
• Android平台应用:Android应用程序使用Java语言编写。Android开发水平的高低 很大程度上取决于Java语言核心能力是否扎实。
• 大数据平台开发:各类框架有Hadoop,spark,storm,flink等,就这类技术生态 圈来讲,还有各种中间件如flume,kafka,sqoop等等 ,这些框架以及工具大多数
是用Java编写而成,但提供诸如Java,scala,Python,R等各种语言API供编程。
• 移动领域应用:主要表现在消费和嵌入式领域,是指在各种小型设备上的应用,包括手 机、PDA、机顶盒、汽车通信设备等。
1.3 Java语言概述:Java语言的诞生
java之父James Gosling团队在开发”Green”项目时,发现C缺少垃圾回收系统,还有可移植的安
全性、分布程序设计和多线程功能。最后,他们想要一种易于移植到各种设备上的平台。
Java确实是从C语言和C++语言继承了许多成份,甚至可以将Java看
成是类C语言发展和衍生的产物。比如Java语言的变量声明,操作符 形式,参数传递,流程控制等方面和C语言、C++语言完全相同。但同
时,Java是一个纯粹的面向对象的程序设计语言,它继承了C++语言
面向对象技术的核心。Java舍弃了C语言中容易引起错误的指针(以
引用取代)、运算符重载(operator overloading)、多重继承
(以接口取代)等特性,增加了垃圾回收器功能用于回收不再被引用
的对象所占据的内存空间。JDK1.5又引入了泛型编程(Generic
Programming)、类型安全的枚举、不定长参数和自动装/拆箱
在这里插入图片描述

1.3 Java语言概述:主要特性

• Java语言是易学的。Java语言的语法与C语言和C++语言很接近,使得大多数程序员 很容易学习和使用Java。 • Java语言是强制面向对象的。Java语言提供类、接口和继承等原语,为了简单起见, 只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制 (关键字为implements)。 • Java语言是分布式的。Java语言支持Internet应用的开发,在基本的Java应用编 程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类 库,包括URL、URLConnection、Socket、ServerSocket等。Java的RMI(远程 方法激活)机制也是开发分布式应用的重要手段。 • Java语言是健壮的。Java的强类型机制、异常处理、垃圾的自动收集等是Java程序 健壮性的重要保证。对指针的丢弃是Java的明智选择。
1.3 Java语言概述:主要特性
• Java语言是安全的。Java通常被用在网络环境中,为此,Java提供了一个安全机 制以防恶意代码的攻击。如:安全防范机制(类ClassLoader),如分配不同的 名字空间以防替代本地的同名类、字节代码检查。 • Java语言是体系结构中立的。Java程序(后缀为java的文件)在Java平台上被 编译为体系结构中立的字节码格式(后缀为class的文件),然后可以在实现这个 Java平台的任何系统中运行。 • Java语言是解释型的。如前所述,Java程序在Java平台上被编译为字节码格式, 然后可以在实现这个Java平台的任何系统的解释器中运行。
• Java是性能略高的。与那些解释型的高级脚本语言相比,Java的性能还是较优的。 • Java语言是原生支持多线程的。在Java语言中,线程是一种特殊的对象,它必须 由Thread类或其子(孙)类来创建。
1.4 Java语言运行机制及运行过程
 Java语言的特点
特点一:面向对象 两个基本概念:类、对象 三大特性:封装、继承、多态 特点二:健壮性 吸收了C/C++语言的优点,但去掉了其影响程序健壮性的部分(如指针、内存的申请与 释放等),提供了一个相对安全的内存管理和访问机制 特点三:跨平台性 跨平台性:通过Java语言编写的应用程序在不同的系统平台上都可以运行。“Write once , Run Anywhere” 原理:只要在需要运行 java 应用程序的操作系统上,先安装一个Java虚拟机 (JVM Java Virtual Machine) 即可。由JVM来负责Java程序在该系统中的运行。
在这里插入图片描述

1.4 Java语言运行机制及运行过程

Java两种核心机制
Java虚拟机 (Java Virtal Machine)
垃圾收集机制 (Garbage Collection)
核心机制—Java虚拟机
JVM是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指 令,管理数据、内存、寄存器。 对于不同的平台,有不同的虚拟机。 只有某平台提供了对应的java虚拟机,java程序才可在此平台运行 Java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行”
在这里插入图片描述
在这里插入图片描述
核心机制—垃圾回收
不再使用的内存空间应回收—— 垃圾回收。 在C/C++等语言中,由程序员负责回收无用内存。 Java 语言消除了程序员回收无用内存空间的责任:它提供一种系统级线程跟踪存储空 间的分配情况。并在JVM空闲时,检查并释放那些可被释放的存储空间。 垃圾回收在Java程序运行过程中自动进行,程序员无法精确控制和干预。
Java程序还会出现内存泄漏和内存溢出问题吗?Yes!

1.5 Java语言的环境搭建

在这里插入图片描述
明确什么是JDK, JRE
下载 JDK
安装 JDK
配置环境变量
path:windows系统执行命令时要搜寻的路径。
验证是否成功:javac java
选择合适的文本编辑器或 IDE 开发

什么是JDK,JRE
JDK(Java Development Kit Java开发工具包) JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了 JRE。所以安装了JDK,就不用在单独安装JRE了。  其中的开发工具:编译工具(javac.exe) 打包工具(jar.exe)等 JRE(Java Runtime Environment Java运行环境) 包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等, 如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。
简单而言,使用JDK的开发工具完成的java程序,交给JRE去运行。
1.5 Java语言的环境搭建:JDK、JRE、JVM关系
在这里插入图片描述
在这里插入图片描述
1.5 Java语言的环境搭建:下载并安装JDK
官方网址:
www.oracle.com
java.sun.com
安装JDK
傻瓜式安装,下一步即可。
建议:安装路径不要有中文或者空格等特殊符号。
如果操作系统是64位的,软件尽量选择支持64位的(除非软件本身不区分)。
当提示安装 JRE 时,正常在JDK安装时已经装过了,但是为了后续使用Eclipse等开发 工具不报错,建议也根据提示安装JRE。

配置环境变量 path 在dos命令行中敲入javac,出现错误提示:
在这里插入图片描述
错误原因:当前执行的程序在当前目录下如果不存在,windows系统会在系 统中已有的一个名为path的环境变量指定的目录中查找。如果仍未找到,会 出现以上的错误提示。所以进入到 jdk安装路径\bin目录下,执行javac,会 看到javac参数提示信息。
在这里插入图片描述
配置环境变量 path
每次执行 java 的工具都要进入到bin目录下,是非常麻烦的。可不可以在任何目 录下都可以执行java的工具呢?
配置方法: 我的电脑–属性–高级系统设置–环境变量 编辑 path 环境变量,在变量值开始处加上java工具所在目录,后面用 “ ; ”和其他值分隔 开即可。 打开DOS命令行,任意目录下敲入javac。如果出现javac 的参数信息,配置成功。
在这里插入图片描述
在这里插入图片描述

1.6 开发体验 — HelloWorld

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结:

学习编程最容易犯的错是语法错误。Java要求你必须按照语法规则编写代码。
如果你的程序违反了语法规则,例如:忘记了分号、大括号、引号,或者拼 错了单词,java编译器都会报语法错误。尝试着去看懂编译器会报告的错误
信息。

2.1 关键字与保留字

关键字(keyword)的定义和特点 定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词) 特点:关键字中所有字母都为小写 官方地址: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
在这里插入图片描述

在这里插入图片描述

保留字(reserved word)
Java保留字:现有Java版本尚未使用,但以后版本可能会作为关键字使
用。自己命名标识符时要避免使用这些保留字 goto 、const

2.2 标识符(Identifier)

标识符:
Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符
技巧:凡是自己可以起名字的地方都叫标识符。
定义合法标识符规则:
由26个英文字母大小写,0-9 ,_或 $ 组成
数字不可以开头。
不可以使用关键字和保留字,但能包含关键字和保留字。
Java中严格区分大小写,长度无限制。
标识符不能包含空格。

Java中的名称命名规范 Java中的名称命名规范:
包名:多单词组成时所有字母都小写:xxxyyyzzz
类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz
变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个 单词首字母大写:xxxYyyZzz
常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ
 注意1:在起名字时,为了提高阅读性,要尽量有意义,“见名知意”。
 注意2:java采用unicode字符集,因此标识符也可以使用汉字声明,但是不建议使用。

2.3 变 量

变量的概念: 内存中的一个存储区域 该区域的数据可以在同一类型范围内不断变化 变量是程序中最基本的存储单元。包含变量类型、变量名和存储的值 变量的作用: 用于在内存中保存数据 使用变量注意: Java中每个变量必须先声明,后使用 使用变量名来访问这块区域的数据 变量的作用域:其定义所在的一对{ }内 变量只有在其作用域内才有效 同一个作用域内,不能定义重名的变量
在这里插入图片描述
声明变量
 语法:<数据类型> <变量名称>
 例如:int var;  变量的赋值
 语法:<变量名称> = <值>
 例如:var = 10;  声明和赋值变量
 语法: <数据类型> <变量名> = <初始化值>
 例如:int var = 10;
在这里插入图片描述
在这里插入图片描述
●注意:二者在初始化值方面的异同: 同:都有生命周期 异:局部变量除形参外,需显式初始化。
整数类型:byte、short、int、long Java各整数类型有固定的表数范围和字段长度,不受具体OS的影响,以保 证java程序的可移植性。 java的整型常量默认为 int 型,声明long型常量须后加‘l’或‘L’ java程序中变量通常声明为int型,除非不足以表示较大的数,才使用long
在这里插入图片描述
500MB 1MB = 1024KB 1KB= 1024B B= byte ? bit? bit: 计算机中的最小存储单位。byte:计算机中基本存储单元。
在这里插入图片描述
浮点类型:float、double 与整数类型类似,Java 浮点类型也有固定的表数范围和字段长度,不受具体操作 系统的影响。
浮点型常量有两种表示形式: 十进制数形式:如:5.12 512.0f .512 (必须有小数点) 科学计数法形式:如:5.12e2 512E2 100E-2  float:单精度,尾数可以精确到7位有效数字。很多情况下,精度很难满足需求。 double:双精度,精度是float的两倍。通常采用此类型。  Java 的浮点型常量默认为double型,声明float型常量,须后加‘f’或‘F’。
在这里插入图片描述
字符类型:char
char 型数据用来表示通常意义上“字符”(2字节) Java中的所有字符都使用Unicode编码,故一个字符可以存储一个字 母,一个汉字,或其他书面语的一个字符。 字符型变量的三种表现形式: 字符常量是用单引号(‘ ’)括起来的单个字符。例如:char c1 = ‘a’; char c2 = ‘中’; char c3 = ‘9’;  Java中还允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量。 例如:char c3 = ‘\n’; // '\n’表示换行符 直接使用 Unicode 值来表示字符型常量:‘\uXXXX’。其中,XXXX代表 一个十六进制整数。如:\u000a 表示 \n。 char类型是可以进行运算的。因为它都对应有Unicode码。
了解:ASCII 码
在计算机内部,所有数据都使用二进制表示。每一个二进制位(bit)有 0 和 1 两种状态, 因此 8 个二进制位就可以组合出 256 种状态,这被称为一个字节(byte)。一个字节一 共可以用来表示 256 种不同的状态,每一个状态对应一个符号,就是 256 个符号,从 0000000 到 11111111。
ASCII码:上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的 关系,做了统一规定。这被称为ASCII码。ASCII码一共规定了128个字符的编码,比如 空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这 128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前 面的1位统一规定为0。 缺点: 不能表示所有字符。 相同的编码表示的字符不一样:比如,130在法语编码中代表了é,在希伯来语编码中却代表 了字母Gimel ( )
了解: UTF-8 UTF-8 是在互联网上使用最广的一种 Unicode 的实现方式。
UTF-8 是一种变长的编码方式。它可以使用 1-6 个字节表示一个符号,根据
不同的符号而变化字节长度。
UTF-8的编码规则:
对于单字节的UTF-8编码,该字节的最高位为0,其余7位用来对字符进行编码(等同于 ASCII码)。
对于多字节的UTF-8编码,如果编码包含 n 个字节,那么第一个字节的前 n 位为1,第一 个字节的第 n+1 位为0,该字节的剩余各位用来对字符进行编码。在第一个字节之后的 所有的字节,都是最高两位为"10",其余6位用来对字符进行编码。

布尔类型:boolean boolean 类型用来判断逻辑条件,一般用于程序流程控制: if条件控制语句;
while循环控制语句;
do-while循环控制语句;
for循环控制语句; boolean类型数据只允许取值true和false,无null。 不可以使用0或非 0 的整数替代false和true,这点和C语言不同。
Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达所操作的 boolean值,在编译之后都使用java虚拟机中的int数据类型来代替:true用1表示,false 用0表示。———《java虚拟机规范 8版》
基本数据类型转换
自动类型转换:容量小的类型自动转换为容量大的数据类型。数据类型按容 量大小排序为:
在这里插入图片描述
有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的 那种数据类型,然后再进行计算。 byte,short,char之间不会相互转换,他们三者在计算时首先转换为int类型。 boolean类型不能与其它数据类型运算。 当把任何基本数据类型的值和字符串(String)进行连接运算时(+),基本数据类 型的值将自动转化为字符串(String)类型。
字符串类型:String
 String不是基本数据类型,属于引用数据类型  使用方式与基本数据类型一致。例如:String str = “abcd”;  一个字符串可以串接另一个字符串,也可以直接串接其他类型的数据。例如: str = str + “xyz” ; int n = 100; str = str + n;
示 例—StringTest类 1 public class StringTest { 2 public static void main(String[] args) { 3 int no = 10; 4 String str = “abcdef”; 5 String str1 = str + “xyz” + no; 6 7 str1 = str1 + “123”; 8 char c = ‘国’; 9 10 double pi = 3.1416; 11 str1 = str1 + pi; 12 boolean b = false; 13 str1 = str1 + b; 14 str1 = str1 + c; 15 16 System.out.println("str1 = " + str1); 17 } 18 }

在这里插入图片描述
强制类型转换
自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使 用时要加上强制转换符:(),但可能造成精度降低或溢出,格外要注意。
通常,字符串不能直接转换为基本类型,但通过基本类型对应的包装类则可
以实现把字符串转换成基本类型。
如: String a = “43”; int i = Integer.parseInt(a);
boolean类型不可以转换为其它的数据类型。
在这里插入图片描述
进 制
世界上有10种人 ,认识和不认识二进制的
关于进制
 所有数字在计算机底层都以二进制形式存在。
 对于整数,有四种表示方式:
二进制(binary):0,1 ,满2进1.以0b或0B开头。
十进制(decimal):0-9 ,满10进1。
八进制(octal):0-7 ,满8进1. 以数字0开头表示。
十六进制(hex):0-9及A-F,满16进1. 以0x或0X开头表示。此处的A-F不区分大小写。 如:0x21AF +1= 0X21B0
在这里插入图片描述
在这里插入图片描述
二进制
Java整数常量默认是int类型,当用二进制定义整数时,其第32位是符号位; 当是long类型时,二进制默认占64位,第64位是符号位 二进制的整数有如下三种形式: 原码:直接将一个数值换成二进制数。最高位是符号位 负数的反码:是对原码按位取反,只是最高位(符号位)确定为1。 负数的补码:其反码加1。
计算机以二进制补码的形式保存所有的整数。 正数的原码、反码、补码都相同 负数的补码是其反码+1

为什么要使用原码、反码、补码表示形式呢?
计算机辨别“符号位”显然会让计算机的基础电路设计变得十分复杂! 于是 人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正 数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有 减法, 这样计算机运算的设计就更简单
在这里插入图片描述
二进制十进制
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4 运算符

运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
算术运算符
赋值运算符
比较运算符(关系运算符)
逻辑运算符
位运算符
三元运算符
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
逻辑运算符用于连接布尔型表达式,在Java中不可以写成3<x<6,应该写 成x>3 & x<6 。
“&”和“&&”的区别: 单&时,左边无论真假,右边都进行运算; 双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
“|”和“||”的区别同理,||表示:当左边为真,右边不参与运算。
异或( ^ )与或( | )的不同之处是:当左右都为true时,结果为false。 理解:异或,追求的是“异”!
在这里插入图片描述
在这里插入图片描述
运算符:三元运算符在这里插入图片描述
在这里插入图片描述

3.1 数组的概述

 数组(Array),是多个相同类型数据按一定顺序排列 的集合,并使用一个名字命名,并通过编号的方式 对这些数据进行统一管理。
 数组的常见概念  数组名  下标(或索引)  元素  数组的长度

 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括 基本数据类型和引用数据类型。
 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是 这块连续空间的首地址。  数组的长度一旦确定,就不能修改。  我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。  数组的分类:
 按照维度:一维数组、二维数组、三维数组、…
 按照元素的数据类型分:基本数据类型元素的数组、引用数据类型元素的数组(即对 象数组)

3.2 一维数组的使用:声明

 一维数组的声明方式: type var[] 或 type[] var;
例如: int a[]; int[] a1; double b[]; String[] c; //引用类型变量数组
 Java语言中声明数组时不能指定其长度(数组中元素的数), 例如: int a[5]; //非法

3.2 一维数组的使用:初始化

在这里插入图片描述

3.2 一维数组的使用:数组元素的引用

定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;
数组元素的引用方式:数组名[数组元素下标]
 数组元素下标可以是整型常量或整型表达式。如a[3] , b[i] , c[6*i];
数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 —>n-1;如int a[]=new int[3]; 可引用的数组元素为a[0]、a[1]、a[2]
每个数组都有一个属性length指明它的长度,例如:a.length 指明数组a的长 度(元素个数)
数组一旦初始化,其长度是不可变的
3.2 一维数组的使用:数组元素的默认初始化值
数组是引用类型,它的元素相当于类的成员变量,因此数组一经 分配空间,其中的每个元素也被按照成员变量同样的方式被隐式 初始化。例如:
public class Test { public static void main(String argv[]){ int a[]= new int[5]; System.out.println(a[3]); //a[3]的默认值为0 } }
对于基本数据类型而言,默认初始化值各有不同 对于引用数据类型而言,默认初始化值为null(注意与0不同!)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 多维数组的使用

 Java 语言里提供了支持多维数组的语法。
 如果说可以把一维数组当成几何中的线性图形, 那么二维数组就相当于是一个表格,像右图Excel 中的表格一样。
 对于二维数组的理解,我们可以看成是一维数组 array1又作为另一个一维数组array2的元素而存 在。其实,从数组底层的运行机制来看,其实没 有多维数组
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.4 数组中涉及到的常见算法

3.4 数组中涉及的常见算法

  1. 数组元素的赋值(杨辉三角、回形数等)
  2. 求数值型数组中元素的最大值、最小值、平均数、总和等
  3. 数组的复制、反转、查找(线性查找、二分法查找)
  4. 数组元素的排序算法
    在这里插入图片描述

3.5 Arrays工具类的使用

java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比 如排序和搜索)的各种方法。
1 boolean equals(int[] a,int[] b) 判断两个数组是否相等。
2 String toString(int[] a) 输出数组信息。
3 void fill(int[] a,int val) 将指定值填充到数组之中。
4 void sort(int[] a) 对数组进行排序。
5 int binarySearch(int[] a,int key) 对排序后的数组进行二分法检索指定的值。
在这里插入图片描述
3.6 数组使用中的常见异常
在这里插入图片描述

4-1 面向过程与面向对象

何谓“面向对象”的编程思想?
首先解释一下“思想”。 先问你个问题:你想做个怎样的人? 可能你会回答:我想做个好人,孝敬父母,尊重长辈,关爱亲朋…… 你看,这就是思想。这是你做人的思想,或者说,是你做人的原则。 做人有做人的原则,编程也有编程的原则。
顿 悟?OR 渐 悟?
在这里插入图片描述
 面向过程(POP) 与 面向对象(OOP)  二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的 是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对 象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。  面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如 抽象、分类、继承、聚合、多态等。  面向对象的三大特征 封装 (Encapsulation) 继承 (Inheritance) 多态 (Polymorphism)
面向对象:Object Oriented Programming 面向过程:Procedure Oriented Programming
在这里插入图片描述
面向对象的思想概述
程序员从面向过程的执行者转化成了面向对象的指挥者
面向对象分析方法分析问题的思路和步骤:
根据问题需要,选择问题所针对的现实世界中的实体。
从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序
语言,把类构造成计算机能够识别和处理的数据结构。
将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。

4.2 Java语言基本元素:类和对象

 类(Class)和对象(Object)是面向对象的核心概念。  类是对一类事物的描述,是抽象的、概念上的定义
 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
 “万事万物皆对象”
在这里插入图片描述

Java类及类的成员
 现实世界的生物体,大到鲸鱼,小到蚂蚁,都是由最基本的细胞构成的。同 理,Java代码世界是由诸多个不同功能的类构成的。
 现实生物世界中的细胞又是由什么构成的呢?细胞核、细胞质、… 那么, Java中用类class来描述事物也是如此。常见的类的成员有:  属 性:对应类中的成员变量  行 为:对应类中的成员方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 对象的创建和使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 对象的创建和使用:匿名对象

 我们也可以不定义对象的句柄,而直接调用这个对象的方法。这 样的对象叫做匿名对象。 如:new Person().shout();
 使用情况 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。 我们经常将匿名对象作为实参传递给一个方法调用

4-4 类的成员之一: 属性(field)

 语法格式: 修饰符 数据类型 属性名 = 初始化值 ;  说明1: 修饰符  常用的权限修饰符有:private、缺省、protected、public  其他修饰符:static、final (暂不考虑)  说明2:数据类型  任何基本数据类型(如int、Boolean) 或 任何引用数据类型。  说明3:属性名  属于标识符,符合命名规则和规范即可。  举例: public class Person{ private int age; //声明private变量 age public String name = “Lila”; //声明public变量 name }
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.5 类的成员之二:方 法(method)

什么是方法(method、函数):  方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中 也称为函数或过程。  将功能封装为方法的目的是,可以实现代码重用,简化代码  Java里的方法不能独立存在,所有的方法必须定义在类里。
举例:
public class Person{ private int age; public int getAge() { //声明方法getAge() return age; } public void setAge(int i) { //声明方法setAge age = i; //将参数i的值赋给类的成员变量age } }
方法的声明格式: 修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){ 方法体程序代码 return 返回值; }
其中: 修饰符:public,缺省,private, protected等
返回值类型:
 没有返回值:void。  有返回值,声明出返回值的类型。与方法体中“return 返回值”搭配使用 方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意” 形参列表:可以包含零个,一个或多个参数。多个参数时,中间用“,”隔开 返回值:方法在执行完毕后返还给调用它的程序的数据。
 如何理解方法返回值类型为void的情况 ?
在这里插入图片描述
在这里插入图片描述
注 意:
方法被调用一次,就会执行一次
没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可
以不必使用return语句。如果使用,仅用来结束方法。
定义方法时,方法的结果应该返回给调用者,交由调用者处理。
方法中只能调用方法或属性,不可以在方法内部定义方法。
4.6 再谈方法1:方法的重载(overload)
在这里插入图片描述

4.6 再谈方法2:可变个数的形参

  1. 声明格式:方法名(参数的类型名 …参数名) 2. 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个 3. 可变个数形参的方法与同名的方法之间,彼此构成重载 4. 可变参数方法的使用与方法参数部分使用数组是一致的 5. 方法的参数部分有可变形参,需要放在形参声明的最后 6. 在一个方法的形参位置,最多只能声明一个可变个数形参

4.6 再谈方法3:方法参数的值传递机制
 方法,必须由其所在类或对象调用才有意义。若方法含有参数: 形参:方法声明时的参数 实参:方法调用时实际传给形参的参数值
Java的实参值如何传入方法呢? Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本 (复制品)传入方法内,而参数本身不受影响。 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.6 再谈方法4:递归(recursion)方法

递归方法:一个方法体内调用它自身。 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执 行无须循环控制。 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死 循环。
//计算1-100之间所有自然数的和 public int sum(int num){ if(num == 1){ return 1; }else{ return num + sum(num - 1); } }

4.7 面向对象特征之一:封装和隐藏

 为什么需要封装?封装的作用和含义?  我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内 部的结构吗?有必要碰电动机吗?  我要开车,…
 我们程序设计追求“高内聚,低耦合”。  高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;  低耦合 :仅对外暴露少量的方法用于使用。
 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提 高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露 的暴露出来。这就是封装性的设计思想。
在这里插入图片描述
信息的封装和隐藏
Java中通过将数据声明为私有的(private),再提供公共的(public) 方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的: 隐藏一个类中不需要对外提供的实现细节; 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑, 限制对属性的不合理操作; 便于修改,增强代码的可维护性;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.8 类的成员之三:构造器(构造方法)

构造器的特征 它具有与类相同的名称 它不声明返回值类型。(与声明为void不同) 不能被static、final、synchronized、abstract、native修饰,不能有 return语句返回值
构造器的作用:创建对象;给对象进行初始化 如:Order o = new Order(); Person p = new Person(“Peter”,15); 如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的 构造器中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自 动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们 要“洗澡”了。在这里插入图片描述
根据参数不同,构造器可以分为如下两类: 隐式无参构造器(系统默认提供) 显式定义一个或多个构造器(无参、有参)
注 意: Java语言中,每个类都至少有一个构造器 默认构造器的修饰符与所属类的修饰符一致 一旦显式定义了构造器,则系统不再提供默认构造器 一个类可以创建多个重载的构造器 父类的构造器不可被子类继承
在这里插入图片描述

4.8 总结:属性赋值过程

截止到目前,我们讲到了很多位置都可以对类的属性赋值。现总结这几个位 置,并指明赋值的先后顺序。
 赋值的位置: ① 默认初始化 ② 显式初始化 ③ 构造器中初始化 ④ 通过“对象.属性“或“对象.方法”的方式赋值
 赋值的先后顺序: ① - ② - ③ - ④

4.8 拓展知识:JavaBean

JavaBean是一种Java语言写成的可重用组件。
所谓javaBean,是指符合如下标准的Java类: 类是公共的 有一个无参的公共的构造器 有属性,且有对应的get、set方法
 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用 户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关 心任何改变
在这里插入图片描述
在这里插入图片描述

4.9 关键字—this

this是什么?
在Java中,this关键字比较难理解,它的作用和其词义很接近。  它在方法内部使用,即这个方法所属对象的引用;  它在构造器内部使用,表示该构造器正在初始化的对象。  this 可以调用类的属性、方法和构造器  什么时候使用this关键字呢?  当在方法内需要用到调用该方法的对象时,就用this。 具体的:我们可以用this来区分属性和局部变量。 比如:this.name = name;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意:
 可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其 他的构造器!
 明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器
 如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了 “this(形参列表)”
 "this(形参列表)“必须声明在类的构造器的首行!
 在类的一个构造器中,最多只能声明一个"this(形参列表)”
4.10 关键字—package
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在 的包。(若缺省该语句,则指定为无名包)。它的格式为: package 顶层包名.子包名 ; 举例:pack1\pack2\PackageTest.java package pack1.pack2; //指定类PackageTest属于包pack1.pack2 public class PackageTest{ public void display(){ System.out.println(“in method display()”); } } 包对应于文件系统的目录,package语句中,用 “.” 来指明包(目录)的层次
包通常用小写单词标识。通常使用所在公司域名的倒置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.10 关键字—import

为使用定义在不同包中的Java类,需用import语句来引入指定包层次下所需要的类 或全部类(.)。import语句告诉编译器到哪里去寻找类。
语法格式: import 包名. 类名; 应用举例: import pack1.pack2.Test; //import pack1.pack2.
;表示引入pack1.pack2包中的所有结构 public class PackTest{ public static void main(String args[]){ Test t = new Test(); //Test类在pack1.pack2包中定义 t.display(); } }
注意: 1. 在源文件中使用import显式的导入指定包下的类或接口 2. 声明在包的声明和类的声明之间。 3. 如果需要导入多个类或接口,那么就并列显式多个import语句即可 4. 举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。 5. 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。 6. 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的 是哪个类。 7. 如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。 8. import static组合的使用:调用指定类或接口下的静态的属性或方法

5.1 面向对象特征之二:继承性(inheritance)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2 方法的重写(override/overwrite)

定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称 为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
要求: 1. 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表 2. 子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型 3. 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限 子类不能重写父类中声明为private权限的方法 4. 子类方法抛出的异常不能大于父类被重写方法的异常  注意: 子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为 static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法。
在这里插入图片描述
在这里插入图片描述

5.3 四种访问权限修饰符

在这里插入图片描述

5.4 关键字—super

在Java类中使用super来调用父类中的指定操作: super可用于访问父类中定义的属性 super可用于调用父类中定义的成员方法 super可用于在子类构造器中调用父类的构造器 注意: 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员 super的追溯不仅限于直接父类 super和this的用法相像,this代表本类对象的引用,super代表父类的内存 空间的标识
调用父类的构造器
子类中所有的构造器默认都会访问父类中空参数的构造器
 当父类中没有空参数的构造器时,子类的构造器必须通过this(参 数列表)或者super(参数列表)语句指定调用本类或者父类中相应的 构造器。同时,只能”二选一”,且必须放在构造器的首行
如果子类构造器中既未显式调用父类或本类的构造器,且父类中又
没有无参的构造器,则编译出错
在这里插入图片描述

5.6 面向对象特征之三:多态性

多态性,是面向对象中最重要的概念,在Java中的体现: 对象的多态性:父类的引用指向子类的对象 可以直接应用在抽象类和接口上
Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明 该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简 称:编译时,看左边;运行时,看右边。 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism) 多态情况下,“看左边”:看的是父类的引用(父类中不具备子类特有的方法)
“看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)
对象的多态 —在Java中,子类的对象可以替代父类的对象使用 一个变量只能有一种确定的数据类型 一个引用类型变量可能指向(引用)多种不同类型的对象 Person p = new Student(); Object o = new Person();//Object类型的变量o,指向Person类型的对象 o = new Student(); //Object类型的变量o,指向Student类型的对象
子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向 上转型(upcasting)。
一个引用类型变量如果声明为父类的类型,但实际引用的是子类
对象,那么该变量就不能再访问子类中添加的属性和方法
Student m = new Student(); m.school = “pku”; //合法,Student类有school成员变量 Person e = new Student(); e.school = “pku”; //非法,Person类没有school成员变量
属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编
译错误。
在这里插入图片描述
小结:方法的重载与重写

  1. 二者的定义细节:略
  2. 从编译和运行的角度看: 重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不 同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了 不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类 和子类的,即子类可以重载父类的同名不同参数的方法。 所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法, 这称为“早绑定”或“静态绑定”;
    而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体 方法,这称为“晚绑定”或“动态绑定”。
    引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。”
    多态小结
     多态作用:  提高了代码的通用性,常称作接口重用  前提: 需要存在继承或者实现关系 有方法的重写  成员方法: 编译时:要查看引用变量所声明的类中是否有所调用的方法。 运行时:调用实际new的对象所属的类中的重写方法。  成员变量: 不具备多态性,只看引用变量所声明的类。
    instanceof 操作符 x instanceof A:检验x是否为类A的对象,返回值为boolean型。  要求x所属的类与类A必须是子类和父类的关系,否则编译错误。  如果x属于类A的子类B,x instanceof A值也为true。 public class Person extends Object {…} public class Student extends Person {…} public class Graduate extends Person {…} ------------------------------------------------------------------public void method1(Person e) { if (e instanceof Person) // 处理Person类及其子类对象 if (e instanceof Student) //处理Student类及其子类对象 if (e instanceof Graduate) //处理Graduate类及其子类对象 }
    对象类型转换 (Casting )
    基本数据类型的Casting: 自动类型转换:小的数据类型可以自动转换成大的数据类型 如long g=20; double d=12.0f 强制类型转换:可以把大的数据类型强制转换(casting)成小的数据类型 如 float f=(float)12.0; int a=(int)1200L 对Java对象的强制类型转换称为造型 从子类到父类的类型转换可以自动进行 从父类到子类的类型转换必须通过造型(强制类型转换)实现 无继承关系的引用类型间的转换是非法的 在造型前可以使用instanceof操作符测试一个对象的类型
    在这里插入图片描述
    子类继承父类
    若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的 同名方法,系统将不可能把父类里的方法转移到子类中。 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的 实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量

5.7 Object 类的使用

 Object类是所有Java类的根父类  如果在类的声明中未使用extends关键字指明其父类,则默认父类 为java.lang.Object类
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
toString() 方法  toString()方法在Object类中定义,其返回值是String类型,返回类名和它 的引用地址。  在进行String与其它类型数据的连接操作时,自动调用toString()方法 Date now=new Date(); System.out.println(“now=”+now); 相当于 System.out.println(“now=”+now.toString()); 可以根据需要在用户自定义类型中重写toString()方法 如String 类重写了toString()方法,返回字符串的值。 s1=“hello”; System.out.println(s1);//相当于System.out.println(s1.toString()); 基本类型数据转换为String类型时,调用了对应包装类的toString()方法 int a=10; System.out.println(“a=”+a);

5.8 包装类(Wrapper)的使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.1 关键字:static

当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上 的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象, 其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少 对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个 国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中 都单独分配一个用于代表国家名称的变量。
在这里插入图片描述
class Circle{ private double radius; public Circle(double radius){this.radius=radius;} public double findArea(){return Math.PIradiusradius;}} 创建两个Circle对象 Circle c1=new Circle(2.0); //c1.radius=2.0 Circle c2=new Circle(3.0); //c2.radius=3.0 Circle类中的变量radius是一个实例变量(instance variable),它属于类的 每一个对象,不能被同一个类的不同对象所共享。 上例中c1的radius独立于c2的radius,存储在不同的空间。c1中的radius 变化不会影响c2的radius,反之亦然。
如果想让一个类的所有实例共享数据,就用类变量!
类属性、类方法的设计思想
 类属性作为该类各个对象之间共享的变量。在设计类时,分析哪 些属性不因对象的不同而改变,将这些属性设置为类属性。相应 的方法设置为类方法。
 如果方法与调用者无关,则这样的方法通常被声明为类方法,由 于不需要创建对象就可以调用类方法,从而简化了方法的调用。
 使用范围: 在Java类中,可用static修饰属性、方法、代码块、内部类
 被修饰后的成员具备以下特点: 随着类的加载而加载 优先于对象存在 修饰的成员,被所有对象所共享 访问权限允许时,可不创建对象,直接被类调用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
单例 (Singleton)设计模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典 的棋谱,不同的棋局,我们用不同的棋谱。”套路”
 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对 某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构 造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生 类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象 的变量也必须定义成静态的。
单例(Singleton)设计模式-饿汉式
class Singleton { // 1.私有化构造器 private Singleton() { }
// 2.内部提供一个当前类的实例 // 4.此实例也必须静态化 private static Singleton single = new Singleton();
// 3.提供公共的静态的方法,返回当前类的对象 public static Singleton getInstance() { return single; }
}
单例(Singleton)设计模式-懒汉式
class Singleton { // 1.私有化构造器 private Singleton() { } // 2.内部提供一个当前类的实例 // 4.此实例也必须静态化 private static Singleton single; // 3.提供公共的静态的方法,返回当前类的对象 public static Singleton getInstance() { if(single == null) { single = new Singleton(); } return single; } }
在这里插入图片描述
 网站的计数器,一般也是单例模式实现,否则难以同步。  应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志 文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。  数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库 资源。  项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置 文件数据,都生成一个对象去读取。  Application 也是单例的典型应用  Windows的Task Manager (任务管理器)就是很典型的单例模式  Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程 中,回收站一直维护着仅有的一个实例。

6.2 理解main方法的语法

由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是 public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须 是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令
时传递给所运行的类的参数。
 又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创
建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情
况,我们在之前的例子中多次碰到。
类的成员之四:代码块
 代码块(或初始化块)的作用:  对Java类或对象进行初始化  代码块(或初始化块)的分类:  一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块 (static block),没有使用static修饰的,为非静态代码块。  static代码块通常用于初始化static的属性 class Person { public static int total; static { total = 100;//为total赋初值 } …… //其它属性或方法声明 }
 静态代码块:用static 修饰的代码块 1. 可以有输出语句。 2. 可以对类的属性、类的声明进行初始化操作。 3. 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。 4. 若有多个静态的代码块,那么按照从上到下的顺序依次执行。 5. 静态代码块的执行要先于非静态代码块。 6. 静态代码块随着类的加载而加载,且只执行一次。
 非静态代码块:没有static修饰的代码块 1. 可以有输出语句。 2. 可以对类的属性、类的声明进行初始化操作。 3. 除了调用非静态的结构外,还可以调用静态的变量或方法。 4. 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。 5. 每次创建对象的时候,都会执行一次。且先于构造器执行。
在这里插入图片描述

6.4 关键字:final

在Java中声明类、变量和方法时,可使用关键字final来修饰,表示“最终的”。 final标记的类不能被继承。提高安全性,提高程序的可读性。 String类、System类、StringBuffer类 final标记的方法不能被子类重写。 比如:Object类中的getClass()。 final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只 能被赋值一次。 final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋 值,然后才能使用。 final double MY_PI = 3.14;

6.5 抽象类与抽象方法

在这里插入图片描述
用abstract关键字来修饰一个类,这个类叫做抽象类。  用abstract来修饰一个方法,该方法叫做抽象方法。 抽象方法:只有方法的声明,没有方法的实现。以分号结束: 比如:public abstract void talk();  含有抽象方法的类必须被声明为抽象类。  抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重 写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍 为抽象类。  不能用abstract修饰变量、代码块、构造器;  不能用abstract修饰私有方法、静态方法、final的方法、final的类
在这里插入图片描述
在这里插入图片描述

6.6 接 口:概述

 一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方 法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又 没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打 印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都 支持USB连接。 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则 必须能…”的思想。继承是一个"是不是"的关系,而接口实现则是 “能不能” 的关系。
 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都 要遵守。
在这里插入图片描述
在这里插入图片描述
 定义Java类的语法格式:先写extends,后写implements  class SubClass extends SuperClass implements InterfaceA{ }  一个类可以实现多个接口,接口也可以继承其它接口。  实现接口的类中必须提供接口中所有方法的具体实现内容,方可实 例化。否则,仍为抽象类。  接口的主要用途就是被实现类实现。(面向接口编程)  与继承关系类似,接口与实现类之间存在多态性  接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲, 接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义 (JDK7.0及之前),而没有变量和方法的实现。
在这里插入图片描述
在这里插入图片描述
接口的应用:代理模式(Proxy)
在这里插入图片描述
 应用场景:  安全代理:屏蔽对真实角色的直接访问。  远程代理:通过代理类处理远程方法调用(RMI)  延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象 比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有 100MB,在打开文件时,不可能将所有的图片都显示出来,这样就可以使用代理 模式,当需要查看图片时,用proxy来进行大图片的打开。
 分类  静态代理(静态定义代理类)  动态代理(动态生成代理类)  JDK自带的动态代理,需要反射等知识
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内 部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使 用内部类。 在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者 称为外部类。  Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完 整的名称。 Inner class的名字不能与包含它的外部类类名相同; 分类: 成员内部类(static成员内部类和非static成员内部类) 局部内部类(不谈修饰符)、匿名内部类
 成员内部类作为类的成员的角色:  和外部类不同,Inner class还可以声明为private或protected;  可以调用外部类的结构  Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员 变量;  成员内部类作为类的角色:  可以在内部定义属性、方法、构造器等结构  可以声明为abstract类 ,因此可以被其它的内部类继承  可以声明为final的  编译以后生成OuterClassKaTeX parse error: Unexpected character: '' at position 856: …r_FFFFFF,t_70) ̲ 如何使用局部内部类  只能…符号,以及数字编号。
 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方 都不能使用该类。
 局部内部类可以使用外部类的成员,包括私有的。  局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局 部变量的声明周期不同所致。
 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private  局部内部类不能使用static修饰,因此也不能包含静态成员
在这里插入图片描述
在这里插入图片描述

7.1 异常概述与异常体系结构

在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,
在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避
免的,比如:客户输入数据的格式,读取文件是否存在,网络是否始终保持
通畅等等。
 异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。 (开发过程中的语法错误和逻辑错误不是异常)  Java程序在执行过程中所发生的异常事件可分为两类: Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源 耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性 的代码进行处理。 Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使 用针对性的代码进行处理。例如: 空指针访问 试图读取不存在的文件 网络连接中断 数组角标越界
 对于这些错误,一般有两种解决方法:一是遇到错误就终止程序 的运行。另一种方法是由程序员在编写程序时,就考虑到错误的 检测、错误消息的提示,以及错误的处理。
 捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。 比如:除数为0,数组下标越界等  分类:编译时异常和运行时异常
在这里插入图片描述
1.运行时异常  是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序 员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子 类都是运行时异常。  对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对 程序的可读性和运行效率产生影响。
2.编译时异常  是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一 般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。  对于这类异常,如果程序不处理,可能会带来意想不到的结果。

7.2 常见异常

 java.lang.RuntimeException ClassCastException ArrayIndexOutOfBoundsException NullPointerException ArithmeticException NumberFormatException InputMismatchException 。。。  java.io.IOExeption  FileNotFoundException  EOFException  java.lang.ClassNotFoundException  java.lang.InterruptedException  java.io.FileNotFoundException  java.sql.SQLException

7.3 异常处理机制一

Java提供的是异常处理的抓抛模型。 Java程序的执行过程中如出现异常,会生成一个异常类对象, 该异常对象将被提交给Java运行时系统,这个过程称为抛出 (throw)异常。 异常对象的生成 由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当 前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例 对象并抛出——自动抛出 由开发人员手动创建:Exception exception = new ClassCastException();——创 建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样
 如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处 理。如果异常没有在调用者方法中处理,它继续被抛给这个调用 方法的上层方法。这个过程将一直继续下去,直到异常被处理。 这一过程称为捕获(catch)异常。  如果一个异常回到main()方法,并且main()也不处理,则程序运 行终止。  程序员通常只能处理Exception,而对Error无能为力
在这里插入图片描述

7.4 异常处理机制二:声明抛出异常

声明抛出异常是Java中处理异常的第二种方式 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这 种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理, 而由该方法的调用者负责处理。 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可 以是方法中产生的异常类型,也可以是它的父类。 声明抛出异常举例: public void readFile(String file) throws FileNotFoundException { …… // 读文件的操作可能产生FileNotFoundException类型的异常 FileInputStream fis = new FileInputStream(file); ……… }
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.6 用户自定义异常类

 一般地,用户自定义异常类都是RuntimeException的子类。  自定义异常类通常需要编写几个重载的构造器。  自定义异常需要提供serialVersionUID  自定义的异常通过throw抛出。  自定义异常最重要的是异常类的名字,当异常出现时,可以根据
名字判断异常类型。
用户自定义异常类MyException,用于描述数据取值范围错误信息。用户 自己的异常类必须继承现有的异常类。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.1 基本概念:程序、进程、线程

程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一 段静态的代码,静态对象。 进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态 的过程:有它自身的产生、存在和消亡的过程。——生命周期 如:运行中的QQ,运行中的MP3播放器 程序是静态的,进程是动态的 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域 线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。 若一个进程同一时间并行执行多个线程,就是支持多线程的 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开 销小 一个进程中的多个线程共享相同的内存单元/内存地址空间它们从同一堆中分配对象,可以 访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资 源可能就会带来安全的隐患。
在这里插入图片描述
 单核CPU和多核CPU的理解  单核CPU,其实是一种假的多线程,因为在一个时间单元内,也只能执行一个线程 的任务。例如:虽然有多车道,但是收费站只有一个工作人员在收费,只有收了费 才能通过,那么CPU就好比收费人员。如果有某个人不想交钱,那么收费人员可以 把他“挂起”(晾着他,等他想通了,准备好了钱,再去收费)。但是因为CPU时 间单元特别短,因此感觉不出来。
 如果是多核的话,才能更好的发挥多线程的效率。(现在的服务器都是多核的)  一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc() 垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。  并行与并发  并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。  并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事
使用多线程的优点
背景:以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方 法),肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?
多线程程序的优点: 1. 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。 2. 提高计算机系统CPU的利用率 3. 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和 修改
何时需要多线程
 程序需要同时执行两个或多个任务。
 程序需要实现一些需要等待的任务时,如用户输入、文件读写
操作、网络操作、搜索等。
 需要一些后台运行的程序时。

8.2 线程的创建和使用

线程的创建和启动
Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread 类来体现。
Thread类的特性 每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常 把run()方法的主体称为线程体 通过该Thread对象的start()方法来启动这个线程,而非直接调用run()
Thread类
 构造器
Thread():创建新的Thread对象
Thread(String threadname):创建线程并指定线程实例名
Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接 口中的run方法
Thread(Runnable target, String name):创建新的Thread对象
API中创建线程的两种方式
JDK1.5之前创建新执行线程有两种方法:  继承Thread类的方式  实现Runnable接口的方式
方式一:继承Thread类 1) 定义子类继承Thread类。 2) 子类中重写Thread类中的run方法。 3) 创建Thread子类对象,即创建了线程对象。 4) 调用线程对象start方法:启动线程,调用run方法。
在这里插入图片描述
注意点:
3. 如果自己手动调用run()方法,那么就只是普通方法,没有启动多线程模式。
4. run()方法由JVM调用,什么时候调用,执行的过程控制都有操作系统的CPU
调度决定。
5. 想要启动多线程,必须调用start方法。
6. 一个线程对象只能调用一次start()方法启动,如果重复调用了,则将抛出以上 的异常“IllegalThreadStateException”。

API中创建线程的两种方式
方式二:实现Runnable接口 1) 定义子类,实现Runnable接口。 2) 子类中重写Runnable接口中的run方法。 3) 通过Thread类含参构造器创建线程对象。 4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。 5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
继承方式和实现方式的联系与区别
public class Thread extends Object implements Runnable  区别  继承Thread:线程代码存放Thread子类run方法中。  实现Runnable:线程代码存在接口的子类的run方法。  实现方式的好处  避免了单继承的局限性  多个线程可以共享同一个接口实现类的对象,非常适合多个相同线 程来处理同一份资源。

Thread类的有关方法(1)
void start(): 启动线程,并执行对象的run()方法 run(): 线程在被调度时执行的操作 String getName(): 返回线程的名称 void setName(String name):设置该线程名称 static Thread currentThread(): 返回当前线程。在Thread子类中就 是this,通常用于主线程和Runnable实现类
Thread类的有关方法(2) static void yield():线程让步 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程 若队列中没有同优先级的线程,忽略此方法 join() :当某个程序执行流中调用其他线程的 join() 方法时,调用线程将 被阻塞,直到 join() 方法加入的 join 线程执行完为止 低优先级的线程也可以获得执行 static void sleep(long millis):(指定时间:毫秒) 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后 重排队。 抛出InterruptedException异常 stop(): 强制线程生命期结束,不推荐使用 boolean isAlive():返回boolean,判断线程是否还活着
在这里插入图片描述
在这里插入图片描述
补充:线程的分类
Java中的线程分为两类:一种是守护线程,一种是用户线程。  它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。  守护线程是用来服务用户线程的,通过在start()方法前调用 thread.setDaemon(true)可以把一个用户线程变成一个守护线程。  Java垃圾回收就是一个典型的守护线程。  若JVM中都是守护线程,当前JVM将退出。  形象理解:兔死狗烹,鸟尽弓藏
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.4 线程的同步

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
同步机制中的锁
 同步锁机制: 在《Thinking in Java》中,是这么说的:对于并发工作,你需要某种方式来防 止两个任务访问相同的资源(其实就是共享资源竞争)。 防止这种冲突的方法 就是当资源被一个任务使用时,在其上加锁。第一个访问某项资源的任务必须 锁定这项资源,使其他任务在其被解锁之前,就无法访问它了,而在其被解锁 之时,另一个任务就可以锁定并使用它了。  synchronized的锁是什么?  任意对象都可以作为同步锁。所有对象都自动含有单一的锁(监视器)。  同步方法的锁:静态方法(类名.class)、非静态方法(this)  同步代码块:自己指定,很多时候也是指定为this或类名.class  注意:  必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就 无法保证共享资源的安全  一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方 法共用同一把锁(this),同步代码块(指定需谨慎)
同步的范围
1、如何找问题,即代码是否存在线程安全?(非常重要) (1)明确哪些代码是多线程运行的代码 (2)明确多个线程是否有共享数据 (3)明确多线程运行代码中是否有多条语句操作共享数据
2、如何解决呢?(非常重要) 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其 他线程不可以参与执行。 即所有操作共享数据的这些语句都要放在同步范围中
3、切记:  范围太小:没锁住所有有安全问题的代码  范围太大:没发挥多线程的功能。
释放锁的操作
 当前线程的同步方法、同步代码块执行结束。  当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、 该方法的继续执行。  当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导 致异常结束。  当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线 程暂停,并释放锁。
不会释放锁的操作
线程执行同步代码块或同步方法时,程序调用Thread.sleep()、 Thread.yield()方法暂停当前线程的执行
线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程 挂起,该线程不会释放锁(同步监视器)。 应尽量避免使用suspend()和resume()来控制线程
单例设计模式之懒汉式(线程安全) class Singleton { private static Singleton instance = null; private Singleton(){} public static Singleton getInstance(){ if(instancenull){ synchronized(Singleton.class){ if(instance == null){ instance=new Singleton(); } } } return instance; } } public class SingletonTest{ public static void main(String[] args){ Singleton s1=Singleton.getInstance(); Singleton s2=Singleton.getInstance(); System.out.println(s1s2); } }
线程的死锁问题
死锁 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃 自己需要的同步资源,就形成了线程的死锁 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于 阻塞状态,无法继续 解决方法 专门的算法、原则 尽量减少同步资源的定义 尽量避免嵌套同步
在这里插入图片描述
3. Lock(锁)
 从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同 步锁对象来实现同步。同步锁使用Lock对象充当。
 java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的 工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象 加锁,线程开始访问共享资源之前应先获得Lock对象。
 ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和 内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以 显式加锁、释放锁。
3. Lock(锁) class A{ private final ReentrantLock lock = new ReenTrantLock(); public void m(){ lock.lock(); try{ //保证线程安全的代码; } finally{ lock.unlock(); } } } 注意:如果同步代码有异常,要将unlock()写入finally语句块
synchronized 与 Lock 的对比

  1. Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是 隐式锁,出了作用域自动释放
  2. Lock只有代码块锁,synchronized有代码块锁和方法锁
  3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有 更好的扩展性(提供更多的子类)
    优先使用顺序: Lock  同步代码块(已经进入了方法体,分配了相应资源)  同步方法 (在方法体之外)

8.5 线程的通信

使用两个线程打印 1-100。线程1, 线程2 交替打印
在这里插入图片描述
 wait() 与 notify() 和 notifyAll()
wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当 前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有 权后才能继续执行。
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待 notifyAll ():唤醒正在排队等待资源的所有线程结束等待.
 这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报 java.lang.IllegalMonitorStateException异常。
 因为这三个方法必须有锁对象调用,而任意对象都可以作为synchronized的同步锁, 因此这三个方法只能在Object类中声明。
wait() 方法
在当前线程中调用方法: 对象名.wait() 使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify (或notifyAll) 为止。 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁) 调用此方法后,当前线程将释放对象监控权 ,然后进入等待 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。
notify()/notifyAll()
在当前线程中调用方法: 对象名.notify()
功能:唤醒等待该对象监控权的一个/所有线程。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
经典例题:生产者/消费者问题
生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处 取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图 生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通 知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如 果店中有产品了再通知消费者来取走产品。
这里可能出现两个问题: 生产者比消费者快时,消费者会漏掉一些数据没有取到。 消费者比生产者快时,消费者会取相同的数据。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.6 JDK5.0 新增线程创建方式

新增方式一:实现Callable接口
 与使用Runnable相比, Callable功能更强大些  相比run()方法,可以有返回值  方法可以抛出异常  支持泛型的返回值  需要借助FutureTask类,比如获取返回结果
新增方式一:实现Callable接口
 Future接口  可以对具体Runnable、Callable任务的执行结果进行取消、查询是
否完成、获取结果等。  FutrueTask是Futrue接口的唯一的实现类  FutureTask 同时实现了Runnable, Future接口。它既可以作为 Runnable被线程执行,又可以作为Future得到Callable的返回值
新增方式二:使用线程池
背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程, 对性能影响很大。  思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完 放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交 通工具。  好处:  提高响应速度(减少了创建新线程的时间)  降低资源消耗(重复利用线程池中线程,不需要每次都创建)  便于线程管理  corePoolSize:核心池的大小  maximumPoolSize:最大线程数  keepAliveTime:线程没有任务时最多保持多长时间后会终止  …

线程池相关API
JDK 5.0起提供了线程池相关API:ExecutorService 和 Executors  ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor  void execute(Runnable command) :执行任务/命令,没有返回值,一般用来执行 Runnable  Future submit(Callable task):执行任务,有返回值,一般又来执行 Callable  void shutdown() :关闭连接池  Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池  Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池  Executors.newFixedThreadPool(n); 创建一个可重用固定线程数的线程池  Executors.newSingleThreadExecutor() :创建一个只有一个线程的线程池  Executors.newScheduledThreadPool(n):创建一个线程池,它可安排在给定延迟后运 行命令或者定期地执行。

9-1 字符串相关的类

String的特性
 String类:代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作 为此类的实例实现。  String是一个final类,代表不可变的字符序列。  字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。  String对象的字符内容是存储在一个字符数组value[]中的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.1 字符串相关的类:String常用方法1

在这里插入图片描述

9.1 字符串相关的类:String常用方法2

在这里插入图片描述

9.1 字符串相关的类:String常用方法3

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.1 字符串相关的类:String与基本数据类型转换

在这里插入图片描述

9.1 字符串相关的类:String与字符数组转换

 字符数组  字符串 String 类的构造器:String(char[]) 和 String(char[],int offset,int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
 字符串  字符数组 public char[] toCharArray():将字符串中的全部字符存放在一个字符数组 中的方法。 public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
9.1 字符串相关的类:String与字节数组转换
 字节数组  字符串 String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构 造一个新的 String。 String(byte[],int offset,int length) :用指定的字节数组的一部分, 即从数组起始位置offset开始取length个字节构造一个字符串对象。
 字符串  字节数组 public byte[] getBytes() :使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 public byte[] getBytes(String charsetName) :使用指定的字符集将 此 String 编码到 byte 序列,并将结果存储到新的 byte 数组
在这里插入图片描述

9.1 字符串相关的类:StringBuffer

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.1 字符串相关的类:StringBuilder

在这里插入图片描述

9.2 JDK8之前日期时间API

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
新日期时间API出现的背景
如果我们可以跟别人说:“我们在1502643933071见面,别晚了!”那么就再简单不 过了。但是我们希望时间与昼夜和四季有关,于是事情就变复杂了。JDK 1.0中包含了 一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用 了。而Calendar并不比Date好多少。它们面临的问题是: 可变性:像日期和时间这样的类应该是不可变的。 偏移性:Date中的年份是从1900开始的,而月份都从0开始。 格式化:格式化只对Date有用,Calendar则不行。 此外,它们也不是线程安全的;不能处理闰秒等。
总结:对日期和时间的操作一直是Java程序员最痛苦的地方之一

 第三次引入的API是成功的,并且Java 8中引入的java.time API 已经纠正了 过去的缺陷,将来很长一段时间内它都会为我们服务。
 Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。 新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间 (LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime) 和持续时间(Duration)的类。历史悠久的 Date 类新增了 toInstant() 方法, 用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简 化了日期时间和本地化的管理。
在这里插入图片描述

9.3.1 LocalDate、LocalTime、LocalDateTime

 LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例 是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。 它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区 相关的信息。 LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。 LocalTime表示一个时间,而不是日期。 LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示 法,也就是公历。
在这里插入图片描述

9.3.2 瞬时:Instant

 Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间 戳。  在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是 时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连 续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机 处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中, 也是从1970年开始,但以毫秒为单位。  java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间 单位。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。 概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒 数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。  (1 ns = 10-9 s) 1秒 = 1000毫秒 =106微秒=109纳秒

在这里插入图片描述

9.3 JDK8中新日期时间API

在这里插入图片描述

9.3.4 其它API

 ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris  ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如 2007-1203T10:15:30+01:00 Europe/Paris。  其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如: Asia/Shanghai等  Clock:使用时区提供对当前即时、日期和时间的访问的时钟。  持续时间:Duration,用于计算两个“时间”间隔  日期间隔:Period,用于计算两个“日期”间隔  TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整 到“下一个工作日”等操作。  TemporalAdjusters : 该类通过静态方法 (firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用 TemporalAdjuster 的实现。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.4 Java比较器

 在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间 的比较问题。
 Java实现对象排序的方式有两种:  自然排序:java.lang.Comparable  定制排序:java.util.Comparator
方式一:自然排序:java.lang.Comparable
 Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称 为类的自然排序。  实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即 通过 compareTo(Object obj) 方法的返回值来比较大小。如果当前对象this大 于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回 负整数,如果当前对象this等于形参对象obj,则返回零。  实现Comparable接口的对象列表(和数组)可以通过 Collections.sort 或 Arrays.sort进行自动排序。实现此接口的对象可以用作有序映射中的键或有 序集合中的元素,无需指定比较器。  对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与 e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals 一致。建议(虽然不是必需的)最好使自然排序与 equals 一致
方式一:自然排序:java.lang.Comparable
Comparable 的典型实现:(默认都是从小到大排列的) String:按照字符串中字符的Unicode值进行比较 Character:按照字符的Unicode值来进行比较 数值类型对应的包装类以及BigInteger、BigDecimal:按照它们对应的数值 大小进行比较 Boolean:true 对应的包装类实例大于 false 对应的包装类实例 Date、Time等:后面的日期时间比前面的日期时间大
在这里插入图片描述
在这里插入图片描述
方式二:定制排序:java.util.Comparator
 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码, 或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那 么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排 序的比较。  重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返 回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示 o1小于o2。  可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort), 从而允许在排序顺序上实现精确控制。  还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的 顺序,或者为那些没有自然顺序的对象 collection 提供排序。
在这里插入图片描述

9.5 System类

 System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。 该类位于java.lang包。  由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实 例化该类。其内部的成员变量和成员方法都是static的,所以也可以很方便 的进行调用。  成员变量  System类内部包含in、out和err三个成员变量,分别代表标准输入流 (键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。  成员方法  native long currentTimeMillis(): 该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时 间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。  void exit(int status): 该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表 异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等。
在这里插入图片描述
在这里插入图片描述

9.6 Math类

9.6 Math类 java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回 值类型一般为double型。 abs 绝对值 acos,asin,atan,cos,sin,tan 三角函数 sqrt 平方根 pow(double a,doble b) a的b次幂 log 自然对数 exp e为底指数 max(double a,double b) min(double a,double b) random() 返回0.0到1.0的随机数 long round(double a) double型数据a转换为long型(四舍五入) toDegrees(double angrad) 弧度—>角度 toRadians(double angdeg) 角度—>弧度
9.7 BigInteger类
 Integer类作为int的包装类,能存储的最大整型值为231-1,Long类也是有限的, 最大为263-1。如果要表示再大的整数,不管是基本数据类型还是他们的包装类 都无能为力,更不用说进行运算了。
 java.math包的BigInteger可以表示不可变的任意精度的整数。BigInteger 提供 所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。 另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、 位操作以及一些其他操作。
 构造器  BigInteger(String val):根据字符串构建BigInteger对象
在这里插入图片描述
 一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中, 要求数字精度比较高,故用到java.math.BigDecimal类。  BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
 构造器  public BigDecimal(double val)  public BigDecimal(String val)
 常用方法  public BigDecimal add(BigDecimal augend)  public BigDecimal subtract(BigDecimal subtrahend)  public BigDecimal multiply(BigDecimal multiplicand)  public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
在这里插入图片描述

10.1 枚举类的使用

主要内容:
 如何自定义枚举类  如何使用关键字enum定义枚举类  Enum类的主要方法  实现接口的枚举类
 类的对象只有有限个,确定的。举例如下:  星期:Monday(星期一)、…、Sunday(星期天)  性别:Man(男)、Woman(女)  季节:Spring(春节)…Winter(冬天)  支付方式:Cash(现金)、WeChatPay(微信)、Alipay(支付宝)、BankCard(银 行卡)、CreditCard(信用卡)  就职状态:Busy、Free、Vocation、Dimission  订单状态:Nonpayment(未付款)、Paid(已付款)、Delivered(已发货)、 Return(退货)、Checked(已确认)Fulfilled(已配货)、  线程状态:创建、就绪、运行、阻塞、死亡
 当需要定义一组常量时,强烈建议使用枚举类
枚举类的实现 JDK1.5之前需要自定义枚举类 JDK 1.5 新增的 enum 关键字用于定义枚举类 若枚举只有一个对象, 则可以作为一种单例模式的实现方 式。  枚举类的属性 枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰 枚举类的使用 private final 修饰的属性应该在构造器中为其赋值 若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的 传入参数

10.1.2 自定义枚举类

  1. 私有化类的构造器,保证不能在类的外部创建其对象 2. 在类的内部创建枚举类的实例。声明为:public static final 3. 对象如果有实例变量,应该声明为private final,并在构造器中初始化

在这里插入图片描述
使用说明
使用 enum 定义的枚举类默认继承了 java.lang.Enum类,因此不能再 继承其他类 枚举类的构造器只能使用 private 权限修饰符 枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)。列出的 实例系统会自动添加 public static final 修饰 必须在枚举类的第一行声明枚举类对象
JDK 1.5 中可以在 switch 表达式中使用Enum定义的枚举类的对象 作为表达式, case 子句可以直接使用枚举值的名字, 无需添加枚举 类作为限定。
在这里插入图片描述
在这里插入图片描述
Enum类的主要方法:  values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的 枚举值。  valueOf(String str):可以把一个字符串转为对应的枚举类对象。要求字符 串必须是枚举类对象的“名字”。如不是,会有运行时异常: IllegalArgumentException。  toString():返回当前枚举类对象常量的名称

10.1.5 实现接口的枚举类

和普通 Java 类一样,枚举类可以实现一个或多个接口
若每个枚举值在调用实现的接口方法呈现相同的行为方式,则只 要统一实现该方法即可。
若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式, 则可以让每个枚举值分别来实现该方法

10.2 注解(Annotation)

主要内容:  注解(Annotation)概述  常见的Annotation示例  自定义Annotation  JDK中的元注解  利用反射获取注解信息(在反射部分涉及)  JDK 8中注解的新特性
从 JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是 Annotation(注解) Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加 载, 运行时被读取, 并执行相应的处理。通过使用Annotation, 程序员 可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。代 码分析工具、开发工具和部署工具可以通过这些补充信息进行验证 或者进行部署。 Annotation 可以像修饰符一样被使用, 可用于修饰包,类, 构造器, 方 法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在Annotation 的 “name=value” 对中。
在JavaSE中,注解的使用目的比较简单,例如标记过时的功能, 忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如 用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗 代码和XML配置等。 未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以 上都是基于注解的,Hibernate3.x以后也是基于注解的,现在的 Struts2有一部分也是基于注解的了,注解是一种趋势,一定程度上 可以说:框架 = 注解 + 反射 + 设计模式。
使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成 一个修饰符使用。用于修饰它支持的程序元素 示例一:生成文档相关的注解 @author 标明开发该类模块的作者,多个作者之间使用,分割 @version 标明该类模块的版本 @see 参考转向,也就是相关主题 @since 从哪个版本开始增加的 @param 对方法中某参数的说明,如果没有参数就不能写 @return 对方法返回值的说明,如果方法的返回值类型是void就不能写 @exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写 其中 @param @return 和 @exception 这三个标记都是只用于方法的。 @param的格式要求:@param 形参名 形参类型 形参说明 @return 的格式要求:@return 返回值类型 返回值说明 @exception的格式要求:@exception 异常类型 异常说明 @param和@exception可以并列多个
在这里插入图片描述
示例二:在编译时进行格式检查(JDK内置的三个基本注解)
@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为
所修饰的结构危险或存在更好的选择
@SuppressWarnings: 抑制编译器警告
在这里插入图片描述
 示例三:跟踪代码依赖性,实现替代配置文件功能  Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
 定义新的 Annotation 类型使用 @interface 关键字  自定义注解自动继承了java.lang.annotation.Annotation接口  Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明。其 方法名和返回值定义了该成员的名字和类型。我们称为配置参数。类型只能 是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、 以上所有类型的数组。  可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始 值可使用 default 关键字  如果只有一个参数成员,建议使用参数名为value  如果定义的注解含有配置参数,那么使用时必须指定参数值,除非它有默认 值。格式是“参数名 = 参数值”,如果只有一个参数成员,且名称为value, 可以省略“value=”  没有成员定义的 Annotation 称为标记; 包含成员变量的 Annotation 称为元数 据 Annotation 注意:自定义注解必须配上注解的信息处理流程才有意义。
JDK 的元Annotation 用于修饰其他Annotation 定义
JDK5.0提供了4个标准的meta-annotation类型,分别是: Retention Target Documented Inherited
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 的生命 周期, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值: RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的 注释 RetentionPolicy.CLASS:在class文件中有效(即class保留) , 当运行 Java 程序时, JVM 不会保留注解。 这是默认值 RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行 Java 程序时, JVM 会 保留注释。程序可以通过反射获取该注释。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档。默认情况下,javadoc是不包括注解的。 定义为Documented的注解必须设置Retention值为RUNTIME。
@Inherited: 被它修饰的 Annotation 将具有继承性。如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解。 比如:如果把标有@Inherited注解的自定义的注解标注在类级别上,子类则可以 继承父类类级别的注解 实际应用中,使用较少

10.2.5 利用反射获取注解信息

JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement 接口, 该接口代 表程序中可以接受注解的程序元素 当一个 Annotation 类型被定义为运行时 Annotation 后, 该注解才是运行时 可见, 当 class 文件被载入时保存在 class 文件中的 Annotation 才会被虚拟 机读取 程序可以调用 AnnotatedElement对象的如下方法来访问 Annotation 信息
在这里插入图片描述
在这里插入图片描述
类型注解:  JDK1.8之后,关于元注解@Target的参数类型ElementType枚举值多了两个: TYPE_PARAMETER,TYPE_USE。  在Java 8之前,注解只能是在声明的地方所使用,Java8开始,注解可以应用 在任何地方。  ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语 句中(如:泛型声明)。  ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。
在这里插入图片描述
在这里插入图片描述

11.1 Java 集合框架概述

一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象 的操作,就要对对象进行存储。另一方面,使用Array存储对象方面具有一些弊 端,而Java 集合就像一种容器,可以动态地把多个对象的引用放入容器中。 数组在内存存储方面的特点: 数组初始化以后,长度就确定了。 数组声明的类型,就决定了进行元素初始化时的类型 数组在存储数据方面的弊端: 数组初始化以后,长度就不可变了,不便于扩展 数组中提供的属性和方法少,不便于进行添加、删除、插入等操作,且效率不高。 同时无法直接获取存储元素的个数 数组存储的数据是有序的、可以重复的。---->存储数据的特点单一 Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的 关联数组。
11.1 Java 集合框架概述:集合的使用场景
在这里插入图片描述
Java 集合可分为 Collection 和 Map 两种体系
Collection接口:单列数据,定义了存取一组对象的方法的集合
List:元素有序、可重复的集合
Set:元素无序、不可重复的集合
 Map接口:双列数据,保存具有映射关系“key-value对”的集合

11.1 Java 集合框架概述:Collection接口继承树

在这里插入图片描述
在这里插入图片描述

11.2 Collection 接口方法

Collection 接口
Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法 既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List)
实现。
在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都 当成 Object 类型处理;从 JDK 5.0 增加了泛型以后,Java 集合可以记住容
器中对象的数据类型。
1、添加  add(Object obj)  addAll(Collection coll) 2、获取有效元素的个数  int size() 3、清空集合  void clear() 4、是否是空集合  boolean isEmpty() 5、是否包含某个元素  boolean contains(Object obj):是通过元素的equals方法来判断是否 是同一个对象  boolean containsAll(Collection c):也是调用元素的equals方法来比 较的。拿两个集合的元素挨个比较。
6、删除  boolean remove(Object obj) :通过元素的equals方法判断是否是 要删除的那个元素。只会删除找到的第一个元素  boolean removeAll(Collection coll):取当前集合的差集 7、取两个集合的交集  boolean retainAll(Collection c):把交集的结果存在当前集合中,不 影响c 8、集合是否相等  boolean equals(Object obj) 9、转成对象数组  Object[] toArray() 10、获取集合对象的哈希值  hashCode() 11、遍历  iterator():返回迭代器对象,用于集合遍历

11-3 Iterator迭代器接口

使用 Iterator 接口遍历集合元素
 Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。  GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元 素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。类似于“公 交车上的售票员”、“火车上的乘务员”、“空姐”。  Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所 有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了 Iterator接口的对象。  Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。  集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合 的第一个元素之前。
在这里插入图片描述
在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且 下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常
在这里插入图片描述
在这里插入图片描述
使用 foreach 循环遍历集合元素
 Java 5.0 提供了 foreach 循环迭代访问 Collection和数组。  遍历操作不需获取Collection或数组的长度,无需使用索引访问元素。  遍历集合的底层调用Iterator完成操作。  foreach还可以用来遍历数组。
在这里插入图片描述

11-4 Collection子接口之一: List接口

鉴于Java中数组用来存储数据的局限性,我们通常使用List替代数组  List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。  List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据 序号存取容器中的元素。
 JDK API中List接口的实现类常用的有:ArrayList、LinkedList和Vector
在这里插入图片描述

List实现类之一:ArrayList

ArrayList 是 List 接口的典型实现类、主要实现类 本质上,ArrayList是对象引用的一个”变长”数组 ArrayList的JDK1.8之前与之后的实现区别?  JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组  JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加第一个元 素时再创建一个始容量为10的数组 Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11.5 Collection子接口之二:Set接口

 Set接口是Collection的子接口,set接口没有提供额外的方法
 Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
 Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals() 方法
Set实现类之一:HashSet
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。 HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除 性能。 HashSet 具有以下特点: 不能保证元素的排列顺序 HashSet 不是线程安全的 集合元素可以是 null HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相 等,并且两个对象的 equals() 方法返回值也相等。 对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。
向HashSet中添加元素的过程:  当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法 来得到该对象的 hashCode 值,然后根据 hashCode 值,通过某种散列函数决定该对象 在 HashSet 底层数组中的存储位置。(这个散列函数会与底层数组的长度相计算得到在 数组中的下标,并且这种散列函数计算还尽可能保证能均匀存储元素,越是散列分布, 该散列函数设计的越好)  如果两个元素的hashCode()值相等,会再继续调用equals方法,如果equals方法结果 为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了, 那么会通过链表的方式继续链接。 如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相 等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
排 序—自然排序 自然排序:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元 素之间的大小关系,然后将集合元素按升序(默认情况)排列 如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。 实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。  Comparable 的典型实现: BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小 进行比较 Character:按字符的 unicode值来进行比较 Boolean:true 对应的包装类实例大于 false 对应的包装类实例 String:按字符串中字符的 unicode 值进行比较 Date、Time:后边的时间、日期比前面的时间、日期大

向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添 加的所有元素都会调用compareTo()方法进行比较。 因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同 一个类的对象。 对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通 过 compareTo(Object obj) 方法比较返回值。 当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保 证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0。 否则,让人难以理解。

排 序—定制排序
TreeSet的自然排序要求元素所属的类实现Comparable接口,如果元素所属的类没 有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照 其它属性大小进行排序,则考虑使用定制排序。定制排序,通过Comparator接口来 实现。需要重写compare(T o1,T o2)方法。 利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表 示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。 要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构 造器。 此时,仍然只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异 常。 使用定制排序判断两个元素相等的标准是:通过Comparator比较两个元素返回了0。

11.6 Map接口

在这里插入图片描述
Map接口概述
 Map与Collection并列存在。用于保存具有映射关系的数据:key-value  Map 中的 key 和 value 都可以是任何引用类型的数据  Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应 的类,须重写hashCode()和equals()方法  常用String类作为Map的“键”  key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到 唯一的、确定的 value  Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用频率最高的实现类
在这里插入图片描述

11.6 Map接口:常用方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
HashMap源码中的重要常量
DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16 MAXIMUM_CAPACITY : HashMap的最大支持容量,2^30 DEFAULT_LOAD_FACTOR:HashMap的默认加载因子 TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树 UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表 MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。(当桶中Node的 数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行 resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4 倍。) table:存储元素的数组,总是2的n次幂 entrySet:存储具体元素的集 size:HashMap中存储的键值对的数量 modCount:HashMap扩容和结构改变的次数。 threshold:扩容的临界值,=容量*填充因子 loadFactor:填充因子

HashMap的存储结构:JDK 1.8之前
 HashMap的内部存储结构其实是数组和链表的结合。当实例化一个HashMap时, 系统会创建一个长度为Capacity的Entry数组,这个长度在哈希表中被称为容量 (Capacity),在这个数组中可以存放元素的位置我们称之为“桶”(bucket),每个 bucket都有自己的索引,系统可以根据索引快速的查找bucket中的元素。  每个bucket中存储一个元素,即一个Entry对象,但每一个Entry对象可以带一个引 用变量,用于指向下一个元素,因此,在一个桶中,就有可能生成一个Entry链。 而且新添加的元素作为链表的head。  添加元素的过程: 向HashMap中添加entry1(key,value),需要首先计算entry1中key的哈希值(根据 key所在类的hashCode()计算得到),此哈希值经过处理以后,得到在底层Entry[]数 组中要存储的位置i。如果位置i上没有元素,则entry1直接添加成功。如果位置i上 已经存在entry2(或还有链表存在的entry3,entry4),则需要通过循环的方法,依次 比较entry1中key和其他的entry。如果彼此hash值不同,则直接添加成功。如果 hash值不同,继续比较二者是否equals。如果返回值为true,则使用entry1的value 去替换equals为true的entry的value。如果遍历一遍以后,发现所有的equals返回都 为false,则entry1仍可添加成功。entry1指向原有的entry元素
HashMap的扩容 当HashMap中的元素越来越多的时候,hash冲突的几率也就越来越高,因为数组的 长度是固定的。所以为了提高查询的效率,就要对HashMap的数组进行扩容,而在 HashMap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算 其在新数组中的位置,并放进去,这就是resize。 那么HashMap什么时候进行扩容呢? 当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数 size)loadFactor 时 , 就 会 进 行 数 组 扩 容 , loadFactor 的默认值 (DEFAULT_LOAD_FACTOR)为0.75,这是一个折中的取值。也就是说,默认情况 下,数组大小(DEFAULT_INITIAL_CAPACITY)为16,那么当HashMap中元素个数 超过160.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把 数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置, 而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数, 那么预设元素的个数能够有效的提高HashMap的性能。

HashMap的存储结构:JDK 1.8

 HashMap的内部存储结构其实是数组+链表+树的结合。当实例化一个 HashMap时,会初始化initialCapacity和loadFactor,在put第一对映射关系 时,系统会创建一个长度为initialCapacity的Node数组,这个长度在哈希表 中被称为容量(Capacity),在这个数组中可以存放元素的位置我们称之为 “桶”(bucket),每个bucket都有自己的索引,系统可以根据索引快速的查 找bucket中的元素。
 每个bucket中存储一个元素,即一个Node对象,但每一个Node对象可以带 一个引用变量next,用于指向下一个元素,因此,在一个桶中,就有可能 生成一个Node链。也可能是一个一个TreeNode对象,每一个TreeNode对象 可以有两个叶子结点left和right,因此,在一个桶中,就有可能生成一个 TreeNode树。而新添加的元素作为链表的last,或树的叶子结点。
那么HashMap什么时候进行扩容和树形化呢? 当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数 size)loadFactor 时 , 就会进行数组扩容, loadFactor 的默认值 (DEFAULT_LOAD_FACTOR)为0.75,这是一个折中的取值。也就是说,默认 情况下,数组大小(DEFAULT_INITIAL_CAPACITY)为16,那么当HashMap中 元素个数超过160.75=12(这个值就是代码中的threshold值,也叫做临界值) 的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元 素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知 HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。
当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有 达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成 树,结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后, 下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。
关于映射关系的key是否可以修改?answer:不要修改 映射关系存储到HashMap中会存储key的hash值,这样就不用在每次查找时重新计算 每一个Entry或Node(TreeNode)的hash值了,因此如果已经put到Map中的映射关 系,再修改key的属性,而这个属性又参与hashcode值的计算,那么会导致匹配不上。
总结:JDK1.8相较于之前的变化:
1.HashMap map = new HashMap();//默认情况下,先不创建长度为16的数组 2.当首次调用map.put()时,再创建长度为16的数组 3.数组为Node类型,在jdk7中称为Entry类型 4.形成链表结构时,新添加的key-value对在链表的尾部(七上八下) 5.当数组指定索引位置的链表长度>8时,且map中的数组的长度> 64时,此索引位置 上的所有key-value对使用红黑树进行存储
在这里插入图片描述
在这里插入图片描述
Map实现类之三:TreeMap TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。 TreeMap 可以保证所有的 Key-Value 对处于有序状态。 TreeSet底层使用红黑树结构存储数据 TreeMap 的 Key 的排序: 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有 的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口  TreeMap判断两个key相等的标准:两个key通过compareTo()方法或 者compare()方法返回0。

Map实现类之四:Hashtable
Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap, Hashtable是线程安全的。 Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询 速度快,很多情况下可以互用。 与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value 与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序 Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。

Map实现类之五:Properties Properties 类是 Hashtable 的子类,该对象用于处理属性文件 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型 存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法

在这里插入图片描述
Collections 是一个操作 Set、List 和 Map 等集合的工具类 Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作, 还提供了对集合对象设置不可变、对集合对象实现同步控制等方法 排序操作:(均为static方法) reverse(List):反转 List 中元素的顺序 shuffle(List):对 List 集合元素进行随机排序 sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序 sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序 swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

Collections常用方法

查找、替换
Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素 Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回 给定集合中的最大元素 Object min(Collection) Object min(Collection,Comparator) int frequency(Collection,Object):返回指定集合中指定元素的出现次数 void copy(List dest,List src):将src中的内容复制到dest中 boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值

在这里插入图片描述
在这里插入图片描述

12-1 为什么要有泛型

 泛型:标签
 举例:  中药店,每个抽屉外面贴着标签  超市购物架上很多瓶子,每个瓶子装的是什么,有标签  泛型的设计背景 集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的 对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来 解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于 这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个 参数,这个类型参数叫做泛型。Collection,List,ArrayList 这个就 是类型参数,即泛型。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

12.2 在集合中使用泛型

在这里插入图片描述
在这里插入图片描述

12.3 自定义泛型结构

1.泛型的声明 interface List 和 class GenTest<K,V> 其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。 常用T表示,是Type的缩写。
2.泛型的实例化: 一定要在类名后面指定类型参数的值(类型)。如: List strList = new ArrayList(); Iterator iterator = customers.iterator();  T只能是类,不能用基本数据类型填充。但可以使用包装类填充  把一个集合中的内容限制为一个特定的数据类型,这就是generics背后 的核心思想
在这里插入图片描述
12.3 自定义泛型结构:泛型类、泛型接口

  1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如: <E1,E2,E3> 2. 泛型类的构造器如下:public GenericClass(){}。 而下面是错误的:public GenericClass(){} 3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。 4. 泛型不同的引用不能相互赋值。 >尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有 一个ArrayList被加载到JVM中。 5. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价 于Object。经验:泛型要使用一路都用。要不用,一路都不要用。 6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。 7. jdk1.7,泛型的简化操作:ArrayList flist = new ArrayList<>(); 8. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
    在这里插入图片描述
  2. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态 属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法 中不能使用类的泛型。 10. 异常类不能是泛型的 11. 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]; 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。 12.父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:  子类不保留父类的泛型:按需实现  没有类型 擦除  具体类型  子类保留父类的泛型:泛型子类  全部保留  部分保留 结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自 己的泛型
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
     方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型 方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。  泛型方法的格式: [访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常  泛型方法声明泛型时也可以指定上限
    在这里插入图片描述
    在这里插入图片描述

12-4 泛型在继承上的体现

在这里插入图片描述
在这里插入图片描述

12.5 通配符的使用

1.使用类型通配符:? 比如:List<?> ,Map<?,?> List<?>是List、List等各种泛型List的父类。
2.读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型 是什么,它包含的都是Object。
3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中 添加对象。  唯一的例外是null,它是所有类型的成员。
 将任意元素加入到其中不是类型安全的: Collection<?> c = new ArrayList(); c.add(new Object()); // 编译时错误 因为我们不知道c的元素类型,我们不能向其中添加对象。add方法有类型参数E作为集 合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知 道那是什么类型,所以我们无法传任何东西进去。
 唯一的例外的是null,它是所有类型的成员。
 另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的 类型,但是我们知道,它总是一个Object。
在这里插入图片描述
在这里插入图片描述
 <?> 允许所有泛型的引用调用  通配符指定上限 上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=  通配符指定下限 下限super:使用时指定的类型不能小于操作的类,即>=  举例:  <? extends Number> (无穷小 , Number] 只允许泛型为Number及Number子类的引用调用
 <? super Number> [Number , 无穷大) 只允许泛型为Number及Number父类的引用调用
 <? extends Comparable> 只允许泛型为实现Comparable接口的实现类的引用调用

12.5 通配符的使用:有限制的通配符

在这里插入图片描述

12.6 泛型应用举例:泛型嵌套

在这里插入图片描述

13-1 File类的使用

 java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关
 File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。 如果需要访问文件内容本身,则需要使用输入/输出流。  想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对 象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。
 File对象可以作为参数传递给流的构造器

13.1 File 类的使用:常用构造器

 public File(String pathname) 以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果 pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。  绝对路径:是一个固定的路径,从盘符开始  相对路径:是相对于某个位置开始  public File(String parent,String child) 以parent为父路径,child为子路径创建File对象。  public File(File parent,String child) 根据一个父File对象和子文件路径创建File对象

13.1 File 类的使用:路径分隔符

 路径中的每级目录之间用一个路径分隔符隔开。  路径分隔符和系统有关:  windows和DOS系统默认使用“\”来表示  UNIX和URL使用“/”来表示  Java程序支持跨平台运行,因此路径分隔符要慎用。  为了解决这个隐患,File类提供了一个常量: public static final String separator。根据操作系统,动态的提供分隔符。  举例:
在这里插入图片描述

13.1 File 类的使用:常用方法

 File类的获取功能  public String getAbsolutePath():获取绝对路径  public String getPath() :获取路径  public String getName() :获取名称  public String getParent():获取上层文件目录路径。若无,返回null  public long length() :获取文件长度(即:字节数)。不能获取目录的长度。  public long lastModified() :获取最后一次的修改时间,毫秒值
 public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组  public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组  File类的重命名功能  public boolean renameTo(File dest):把文件重命名为指定的文件路径
 File类的判断功能
 public boolean isDirectory():判断是否是文件目录  public boolean isFile() :判断是否是文件  public boolean exists() :判断是否存在  public boolean canRead() :判断是否可读  public boolean canWrite() :判断是否可写  public boolean isHidden() :判断是否隐藏
 File类的创建功能  public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false  public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。 如果此文件目录的上层目录不存在,也不创建。  public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建
注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目 路径下。
 File类的删除功能  public boolean delete():删除文件或者文件夹 删除注意事项: Java中的删除不走回收站。 要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录

13.1 File 类的使用
在这里插入图片描述

在这里插入图片描述

13-2 IO流原理及流的分类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
 int read() 从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因 为已经到达流末尾而没有可用的字节,则返回值 -1。  int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已 经到达流末尾而没有可用的字节,则返回值 -1。否则以整数形式返回实际读取 的字节数。
 int read(byte[] b, int off,int len) 将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取 的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于 文件末尾而没有可用的字节,则返回值 -1。  public void close() throws IOException 关闭此输入流并释放与该流关联的所有系统在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
关闭此输出流并释放与该流关联的所有系统资源
在这里插入图片描述
关闭此输出流并释放与该流关联的所有系统资源。

13-3 节点流(或文件流)

读取文件
1.建立一个流对象,将已存在的一个文件加载进流。  FileReader fr = new FileReader(new File(“Test.txt”));
2.创建一个临时存放数据的数组。  char[] ch = new char[1024];
3.调用流对象的读取方法将流中的数据读入到数组中。  fr.read(ch);
4. 关闭资源。  fr.close();
在这里插入图片描述
写入文件
1.创建流对象,建立数据存放文件  FileWriter fw = new FileWriter(new File(“Test.txt”));
2.调用流对象的写入方法,将数据写入流  fw.write(“atguigu-songhongkang”);
3.关闭流资源,并将流中的数据清空到文件中。  fw.close();
在这里插入图片描述
 定义文件路径时,注意:可以用“/”或者“\”。
 在写入一个文件时,如果使用构造器FileOutputStream(file),则目录下有同名文 件将被覆盖。  如果使用构造器FileOutputStream(file,true),则目录下的同名文件不会被覆盖, 在文件内容末尾追加内容。
 在读取文件时,必须保证该文件已存在,否则报异常。
 字节流操作字节,比如:.mp3,.avi,.rmvb,mp4,.jpg,.doc,.ppt
 字符流操作字符,只能操作普通文本文件。最常见的文本文 件:.txt,.java,.c,.cpp 等语言的源代码。尤其注意.doc,excel,ppt这些不是文 本文件。

13-4 缓冲流

 为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类 时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区。
 缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为: BufferedInputStream 和 BufferedOutputStream BufferedReader 和 BufferedWriter
在这里插入图片描述
 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区  当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性从 文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中 读取下一个8192个字节数组。  向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法 flush()可以强制将缓冲区的内容全部写入输出流  关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也 会相应关闭内层节点流  flush()方法的使用:手动将buffer中内容写入文件  如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷 新缓冲区,关闭后不能再写出
在这里插入图片描述
在这里插入图片描述

13.5 处理流之二:转换流

转换流提供了在字节流和字符流之间的转换
Java API提供了两个转换流:  InputStreamReader:将InputStream转换为Reader  OutputStreamWriter:将Writer转换为OutputStream
 字节流中的数据都是字符时,转成字符流操作更高效。
 很多时候我们使用转换流来处理文件乱码问题。实现编码和 解码的功能。
InputStreamReader
 实现将字节的输入流按指定字符集转换为字符的输入流。  需要和InputStream“套接”。
 构造器  public InputStreamReader(InputStream in)  public InputSreamReader(InputStream in,String charsetName) 如: Reader isr = new InputStreamReader(System.in,”gbk”);
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

13-6 标准输入、输出流

 System.in和System.out分别代表了系统标准的输入和输出设备  默认输入设备是:键盘,输出设备是:显示器  System.in的类型是InputStream  System.out的类型是PrintStream,其是OutputStream的子类 FilterOutputStream 的子类  重定向:通过System类的setIn,setOut方法对默认设备进行改变。  public static void setIn(InputStream in)  public static void setOut(PrintStream out)
在这里插入图片描述

13.7 处理流之四:打印流(了解)

实现将基本数据类型的数据格式转化为字符串输出
打印流:PrintStream和PrintWriter  提供了一系列重载的print()和println()方法,用于多种数据类型的输出  PrintStream和PrintWriter的输出不会抛出IOException异常  PrintStream和PrintWriter有自动flush功能  PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。 在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。  System.out返回的是PrintStream的实例
在这里插入图片描述

13-8 数据流

为了方便地操作Java语言的基本数据类型和String的数据,可以使用数据流。 数据流有两个类:(用于读取和写出基本数据类型、String类的数据)  DataInputStream 和 DataOutputStream  分别“套接”在 InputStream 和 OutputStream 子类的流上 DataInputStream中的方法 boolean readBoolean() byte readByte() char readChar() float readFloat() double readDouble() short readShort() long readLong() int readInt() String readUTF() void readFully(byte[] b) DataOutputStream中的方法  将上述的方法的read改为相应的write即可
在这里插入图片描述
在这里插入图片描述

13-9 对象流

在这里插入图片描述
对象的序列化 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从 而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传 输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原 来的Java对象 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据, 使其在保存和传输时可被还原 序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返 回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是 JavaEE 平台的基础 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可 序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。 否则,会抛出NotSerializableException异常 Serializable Externalizable
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量: private static final long serialVersionUID; serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象 进行版本控制,有关各版本反序列化时是否兼容。 如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自 动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议, 显式声明。
 简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验 证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的 serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同 就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异 常。(InvalidCastException)
在这里插入图片描述
在这里插入图片描述

13-10 随机存取文件流

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

13-11 NIO.2中Path、 Paths、Files类的使用

在这里插入图片描述
在这里插入图片描述
Path、Paths和Files核心API  早期的Java只提供了一个File类来访问文件系统,但File类的功能比较有限,所 提供的方法性能也不高。而且,大多数方法在出错时仅返回失败,并不会提供异 常信息。  NIO. 2为了弥补这种不足,引入了Path接口,代表一个平台无关的平台路径,描 述了目录结构中文件的位置。Path可以看成是File类的升级版本,实际引用的资 源也可以不存在。  在以前IO操作都是这样写的: import java.io.File; File file = new File(“index.html”);  但在Java7 中,我们可以这样写: import java.nio.file.Path; import java.nio.file.Paths; Path path = Paths.get(“index.html”);
Path、Paths和Files核心API
 同时,NIO.2在java.nio.file包下还提供了Files、Paths工具类,Files包含 了大量静态的工具方法来操作文件;Paths则包含了两个返回Path的静态 工厂方法。
 Paths 类提供的静态 get() 方法用来获取 Path 对象: static Path get(String first, String … more) : 用于将多个字符串串连成路径 static Path get(URI uri): 返回指定uri对应的Path路径

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

14.1 网络编程概述

Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序。
Java提供的网络类库,可以实现无痛的网络连接,联网的底层 细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并 且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一 的网络编程环境。
网络基础
计算机网络:
把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规 模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、 共享硬件、软件、数据信息等资源。 网络编程的目的:
直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。 网络编程中有两个主要的问题: 如何准确地定位网络上一台或多台主机;定位主机上的特定的应用 找到主机后如何可靠高效地进行数据传输

14-2 网络通信要素概述

 IP和端口号  网络通信协议
 通信双方地址  IP  端口号  一定的规则(即:网络通信协议。有两套参考模型)  OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广  TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
14.2 网络通信要素概述
在这里插入图片描述
在这里插入图片描述

14-3 通信要素1: IP和端口号

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
InetAddress类
Internet上的主机有两种方式表示地址:
域名(hostName):www.atguigu.com
IP 地址(hostAddress):202.108.35.210 InetAddress类主要表示IP地址,两个子类:Inet4Address、Inet6Address。 InetAddress 类对象含有一个 Internet 主机地址的域名和IP地址: www.atguigu.com 和 202.108.35.210。 域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS) 负责将域名转化成IP地址,这样才能和主机建立连接。 -------域名解析
在这里插入图片描述
在这里插入图片描述

14.4 通信要素2:网络通信协议

网络通信协议 计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代 码结构、传输控制步骤、出错控制等制定标准。  问题:网络协议太复杂 计算机网络通信涉及内容很多,比如指定源地址和目标地址,加密解密,压缩 解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢? 通信协议分层的思想 在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常 用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与 再下一层不发生关系。各层互不影响,利于系统的开发和扩展。
TCP/IP协议簇
传输层协议中有两个非常重要的协议:
 传输控制协议TCP(Transmission Control Protocol)
 用户数据报协议UDP(User Datagram Protocol)。 TCP/IP 以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得 名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。 IP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信。 TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即 物理链路层、IP层、传输层和应用层。
TCP 和 UDP
 TCP协议:  使用TCP协议前,须先建立TCP连接,形成传输数据通道  传输前,采用“三次握手”方式,点对点通信,是可靠的  TCP协议进行通信的两个应用进程:客户端、服务端。  在连接中可进行大数据量的传输  传输完毕,需释放已建立的连接,效率低  UDP协议:  将数据、源、目的封装成数据包,不需要建立连接  每个数据报的大小限制在64K内  发送不管对方是否准备好,接收方收到也不确认,故是不可靠的  可以广播发送  发送数据结束时无需释放资源,开销小,速度快
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

14-5 TCP网络编程

在这里插入图片描述
基于Socket的TCP编程
 客户端Socket的工作过程包含以下四个基本的步骤:
 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端
响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。  打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输  按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息
(但不能读取自己放入线路的信息),通过输出流将信息写入线程。  关闭 Socket:断开客户端到服务器的连接,释放线路
客户端创建Socket对象 客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连 接。Socket的构造器是: Socket(String host,int port)throws UnknownHostException,IOException:向服务器(域名是 host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。 Socket(InetAddress address,int port)throws IOException:根据InetAddress对象所表示的 IP地址以及端口号port发起连接。 客户端建立socketAtClient对象的过程就是向服务器发出套接字连接请求
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

14-6 UDP网络编程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

14-7 URL编程

URL类 URL(Uniform Resource Locator):统一资源定位符,它表示 Internet 上某一 资源的地址。 它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate 这个资源。 通过 URL 我们可以访问 Internet 上的各种网络资源,比如最常见的 www,ftp 站点。浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源。
 URL的基本结构由5部分组成: <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表 例如: http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123 #片段名:即锚点,例如看小说,直接定位到章节 参数列表格式:参数名=参数值&参数名=参数值…
为了表示URL,java.net 中实现了类 URL。我们可以通过下面的构造器来初 始化一个 URL 对象:
public URL (String spec):通过一个表示URL地址的字符串可以构造一个URL对象。例 如:URL url = new URL (“http://www. atguigu.com/”);
public URL(URL context, String spec):通过基 URL 和相对 URL 构造一个 URL 对象。 例如:URL downloadUrl = new URL(url, “download.html")
public URL(String protocol, String host, String file); 例如:new URL(“http”, “www.atguigu.com”, “download. html");
public URL(String protocol, String host, int port, String file); 例如: URL gamelan = new URL(“http”, “www.atguigu.com”, 80, “download.html");  URL类的构造器都声明抛出非运行时异常,必须要对这一异常进行处理,通 常是用 try-catch 语句进行捕获。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

15-1 Java反射机制概述

Java Reflection
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可 以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看 到类的结构,所以,我们形象的称之为:反射。
在这里插入图片描述
在这里插入图片描述
 Java反射机制提供的功能 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时获取泛型信息 在运行时调用任意一个对象的成员变量和方法 在运行时处理注解 生成动态代理
在这里插入图片描述

15-2 理解Class类并 获取Class的实例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

15-3 类的加载 与ClassLoader的理解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

15-5 获取运行时类的完 整结构

在这里插入图片描述
使用反射可以取得: 1.实现的全部接口 public Class<?>[] getInterfaces() 确定此对象所表示的类或接口实现的接口。
2.所继承的父类 public Class<? Super T> getSuperclass() 返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。
3.全部的构造器  public Constructor[] getConstructors() 返回此 Class 对象所表示的类的所有public构造方法。  public Constructor[] getDeclaredConstructors() 返回此 Class 对象表示的类声明的所有构造方法。
 Constructor类中:  取得修饰符: public int getModifiers();  取得方法名称: public String getName();  取得参数的类型:public Class<?>[] getParameterTypes();
4.全部的方法  public Method[] getDeclaredMethods() 返回此Class对象所表示的类或接口的全部方法  public Method[] getMethods() 返回此Class对象所表示的类或接口的public的方法
 Method类中:  public Class<?> getReturnType()取得全部的返回值  public Class<?>[] getParameterTypes()取得全部的参数  public int getModifiers()取得修饰符  public Class<?>[] getExceptionTypes()取得异常信息
5.全部的Field public Field[] getFields() 返回此Class对象所表示的类或接口的public的Field。 public Field[] getDeclaredFields() 返回此Class对象所表示的类或接口的全部Field。
 Field方法中:  public int getModifiers() 以整数形式返回此Field的修饰符  public Class<?> getType() 得到Field的属性类型  public String getName() 返回Field的名称。
6. Annotation相关
 get Annotation(Class annotationClass)  getDeclaredAnnotations() 7.泛型相关 获取父类泛型类型:Type getGenericSuperclass() 泛型类型:ParameterizedType 获取实际的泛型类型参数数组:getActualTypeArguments()
8.类所在的包 Package getPackage()

小 结:
1.在实际的操作中,取得类的信息的操作代码,并不会经常开发。 2.一定要熟悉java.lang.reflect包的作用,反射机制。 3.如何取得属性、方法、构造器的名称,修饰符等。
15.6 调用运行时类的指定结构
在这里插入图片描述
在这里插入图片描述
2.调用指定属性
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和 get()方法就可以完成设置和取得属性内容的操作。  public Field getField(String name) 返回此Class对象表示的类或接口的指定的 public的Field。  public Field getDeclaredField(String name)返回此Class对象表示的类或接口的 指定的Field。
 在Field中:  public Object get(Object obj) 取得指定对象obj上此Field的属性内容  public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
关于setAccessible方法的使用
 Method和Field、Constructor对象都有setAccessible()方法。  setAccessible启动和禁用访问安全检查的开关。  参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。  提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被 调用,那么请设置为true。  使得原本无法访问的私有成员也可以访问  参数值为false则指示反射的对象应该实施Java语言访问检查
15-7 反射的应用:动态代理
代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原 始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原 始对象上。
 之前为大家讲解过代理机制的操作,属于静态代理,特征是代理类和目标 对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代 理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最 好可以通过一个代理类完成全部的代理功能。
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时 根据需要动态创建目标类的代理对象。 动态代理使用场合: 调试 远程方法调用 动态代理相比于静态代理的优点:
抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中 处理,这样,我们可以更加灵活和统一的处理众多的方法。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有 太大的意义。通常都是为指定的目标对象生成动态代理
 这种动态代理在AOP中被称为AOP代理,AOP代理可代替目标对象,AOP代理 包含了目标对象的全部方法。但AOP代理中的方法与目标对象的方法存在差异: AOP代理里的方法可以在执行目标方法之前、之后插入一些通用处理
在这里插入图片描述

Java 8新特性简介

Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以 来最具革命性的版本。Java 8为Java语言、编译器、类库、开发 工具与JVM带来了大量新特性
在这里插入图片描述
速度更快
 代码更少(增加了新的语法:Lambda 表达式)
 强大的 Stream API
 便于并行
 最大化减少空指针异常:Optional
 Nashorn引擎,允许在JVM上运行JS应用
并行流与串行流
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数 据块的流。相比较串行的流,并行的流可以很大程度上提高程序的执行效率。
Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。 Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流 之间进行切换。
16-1 Lambda表达式
为什么使用 Lambda 表达式
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以
传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了
提升。
在这里插入图片描述
在这里插入图片描述
Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操 作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符 或箭头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的参数列表 右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16-2 函数式(Functional)接口

什么是函数式(Functional)接口
 只包含一个抽象方法的接口,称为函数式接口。  你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式 抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽 象方法上进行声明)。  我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检 查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个 接口是一个函数式接口。  在java.util.function包下定义了Java 8 的丰富的函数式接口
如何理解函数式接口  Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)
 在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的 编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在 Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的 对象类型——函数式接口。  简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口 的实例,那么该对象就可以用Lambda表达式来表示。  所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
16-3 方法引用与构造器引用
方法引用(Method References)  当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!  方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就 是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向 一个方法,可以认为是Lambda表达式的一个语法糖。
 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的 方法的参数列表和返回值类型保持一致!
 格式:使用操作符 “::” 将类(或对象) 与 方法名分隔开来。  如下三种主要使用情况:  对象::实例方法名  类::静态方法名  类::实例方法名
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16-4 强大的Stream API

Stream API说明  Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则 是 Stream API。
 Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这 是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程 序员的生产力,让程序员写出高效率、干净、简洁的代码。
 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进 行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。 也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种 高效且易于使用的处理数据的方式
为什么要使用Stream API
 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数 据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要 Java层面去处理。
 Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据 结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中, 后者主要是面向 CPU,通过 CPU 实现计算。
什么是 Stream
Stream到底是什么呢? 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 “集合讲的是数据,Stream讲的是计算!”
注意: ①Stream 自己不会存储元素。 ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。 ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
在这里插入图片描述
创建 Stream方式一:通过集合
Java8 中的 Collection 接口被扩展,提供了两个获取流 的方法:  default Stream stream() : 返回一个顺序流  default Stream parallelStream() : 返回一个并行流
创建 Stream方式二:通过数组
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
 static Stream stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:  public static IntStream stream(int[] array)  public static LongStream stream(long[] array)  public static DoubleStream stream(double[] array)
创建 Stream方式三:通过Stream的of()
可以调用Stream类静态方法 of(), 通过显示值创建一个 流。它可以接收任意数量的参数。
 public static Stream of(T… values) : 返回一个流

创建 Stream方式四:创建无限流
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
 迭代 public static Stream iterate(final T seed, final UnaryOperator f)  生成 public static Stream generate(Supplier s)

// 方式四:创建无限流 @Test public void test4() { // 迭代 // public static Stream iterate(final T seed, final // UnaryOperator f) Stream stream = Stream.iterate(0, x -> x + 2); stream.limit(10).forEach(System.out::println);
// 生成 // public static Stream generate(Supplier s) Stream stream1 = Stream.generate(Math::random); stream1.limit(10).forEach(System.out::println);
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16-5 Optional类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Java 9

经过4次跳票,历经曲折的java 9 终于终于在2017年9月21日发布(距离
上个版本足足3年半时间)java 9 提供了超过 150 项新功能特性,包括备受
期待的模块化系统、可交互的 REPL 工具:jshell,JDK 编译工具,Java 公共
API 和私有代码,以及安全增强、扩展提升、性能管理改善等。可以说 Java 9 是
一个庞大的系统工程,完全做了一个整体改变。但本博文只介绍最重要的十大新
特性
特性列表
 平台级modularity(原名:Jigsaw) 模块化系统
 Java 的 REPL 工具: jShell 命令
 多版本兼容 jar 包(这个在处理向下兼容方面,非常好用)
 语法改进:接口的私有方法
 语法改进:UnderScore(下划线)使用的限制
 底层结构:String 存储结构变更(这个很重要)
 集合工厂方法:快速创建只读集合
 增强的 Stream API
 全新的 HTTP 客户端 API
 其它特性
 它的新特性来自于100于项JEP和40于项JSR

Java 10

2018年3月20日,Java 10 正式发布,这一次没有跳票。它号称有109项新
特性,包含12个JEP。需要注意的是,本次Java10并不是Oracle的官方LTS
版本,还是坐等java11的发布再考虑在生产中使用
特性列表
 局部变量的类型推断 var关键字
 GC改进和内存管理 并行全垃圾回收器 G1
 垃圾回收器接口
 线程-局部变量管控
 合并 JDK 多个代码仓库到一个单独的储存库中
 新增API:ByteArrayOutputStream
 新增API:List、Map、Set
 新增API:java.util.Properties
 新增API: Collectors收集器
 其它特性
1、局部变量的类型推断 var 关键字
这个新功能将为Java增加一些语法糖 - 简化它并改善开发者体验。新的语法将
减少与编写Java相关的冗长度,同时保持对静态类型安全性的承诺。
这可能是Java10给开发者带来的最大的一个新特性。下面主要看例子:
public static void main(String[] args) { var list = new ArrayList(); list.add(“hello,world!”); System.out.println(list); }
这是最平常的使用。注意赋值语句右边,最好写上泛型类型,否则会有如下情况:
public static void main(String[] args) { var list = new ArrayList<>(); list.add(“hello,world!”); list.add(1); list.add(1.01); System.out.println(list); }
list什么都可以装,非常的不安全了。和js等语言不同的是,毕竟Java还是强
类型的语言,所以下面语句是编译报错的:
public static void main(String[] args) { var list = new ArrayList(); list.add(“hello,world!”); System.out.println(list);
list = new ArrayList(); //编译报错 }
注意:下面几点使用限制
局部变量初始化
for循环内部索引变量
传统的for循环声明变量
public static void main(String[] args) { //局部变量初始化 var list = new ArrayList(); //for 循环内部索引变量 for (var s : list) { System.out.println(s); } //传统的 for 循环声明变量 for (var i = 0; i < list.size(); i++) { System.out.println(i); } }

下面这几种情况,都是不能使用var的
方法参数全局变量
public static var list = new ArrayList(); //编译报错
public static List list = new ArrayList<>(); //正常编译通过
构造函数参数方法返回类型字段捕获表达式(或任何其他类型的变量声明)
2、GC 改进和内存管理 并行全垃圾回收器 G1
JDK 10中有2个JEP专门用于改进当前的垃圾收集元素。
Java 10的第二个JEP是针对G1的并行完全GC(JEP 307),其重点在于通过
完全GC并行来改善G1最坏情况的等待时间。G1是Java 9中的默认GC,并
且此JEP的目标是使G1平行。
3、垃圾回收器接口

这不是让开发者用来控制垃圾回收的接口;而是一个在 JVM 源代码中的允许另
外的垃圾回收器快速方便的集成的接口。
4、线程-局部变量管控
这是在 JVM 内部相当低级别的更改,现在将允许在不运行全局虚拟机安全点的
情况下实现线程回调。这将使得停止单个线程变得可能和便宜,而不是只能启用
或停止所有线程。
5、合并 JDK 多个代码仓库到一个单独的储存库中
在 JDK9 中,有 8 个仓库: root、corba、hotspot、jaxp、jaxws、jdk、langtools
和 nashorn 。在 JDK10 中这些将被合并为一个,使得跨相互依赖的变更集的
存储库运行 atomic commit (原子提交)成为可能。
6、新增 API:ByteArrayOutputStream
String toString(Charset): 重载 toString(),通过使用指定的字符集解码字节,
将缓冲区的内容转换为字符串。
7、新增 API:List、Map、Set
这3个接口都增加了一个新的静态方法,copyOf(Collection)。这些函数按照
其迭代顺序返回一个不可修改的列表、映射或包含给定集合的元素的集合。
8、新增 API:java.util.Properties
增加了一个新的构造函数,它接受一个 int 参数。这将创建一个没有默认值的
空属性列表,并且指定初始大小以容纳指定的元素数量,而无需动态调整大小。
还有一个新的重载的 replace 方法,接受三个 Object 参数并返回一个布尔值。
只有在当前映射到指定值时,才会替换指定键的条目。
9、新增 API: Collectors 收集器
toUnmodifiableList():
toUnmodifiableSet():
toUnmodifiableMap(Function, Function):
toUnmodifiableMap(Function, Function, BinaryOperator):
这四个新方法都返回 Collectors ,将输入元素聚集到适当的不可修改的集合中。
线程本地握手(JEP 312)
其他Unicode语言 - 标记扩展(JEP 314)
基于Java的实验性JIT编译器
根证书颁发认证(CA)
删除工具javah(JEP 313)
从JDK中移除了javah工具,这个很简单并且很重要。
最后
JDK10的升级幅度其实主要还是以优化为主,并没有带来太多对使用者惊喜的
特性。所以建议广大开发者还是坐等Java11吧,预计2018年9月份就会到来,
最重要的是它是LTS版本哦,所以是可以运用在生产上的。

标签:Java,对象,基础,线程,数组,方法,public
来源: https://blog.csdn.net/weixin_44163647/article/details/111604010

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有