java基础

503 阅读1小时+

java基础

基本概念、开发工具、基础语法

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社群。

简单性、面向对象、分布式处理、解释性、可靠、安全、可移植性、高性能、多线程、动态性等。

也可以说Java是一种解释性、跨平台、通用的编程语言。

只要在需要运行java应用程序的操作系统上,

先安装一个Java虚拟机(JVM Java Virtual Machine)即可。 由JVM来负责Java程序在该系统中的运行

首先编写java源代码程序,扩展名.java

在命令行模式中,输入javac命令对源代码进行编译,生成字节码文件(javac 源文件名.java ) 编译完成后,如果没有报错信息,输入java命令对class字节码文件进行解释运行,执行时不需要添加.class扩展名 (java HelloWorld) 得到结果:Hello World

1.关键字

关键字概述 被Java语言赋予特定含义的单词 关键字特点 组成关键字的字母全部小写 用于定义数据类型的关键字 class (类) interface (接口) byte (字节型) short( 短整型) int (整型) long( 长整型) float (单精度浮点型) double ( 双精度浮点型) char (字符型) boolean (布尔型) void (声明当前成员方法没有返回值) 用于定义数据类型值的关键字 true (关系运算的返回类型) false (关系运算的返回类型) null( 空) 用于定义流程控制的关键字 if (条件语句的引导词) else ( 用在条件语句中,当条件不成立时的分支) switch ( 分支语句结构的引导词) case (用在switch语句之中,表示其中的一个分支) default (默认,例如,用在switch语句中,表明一个默认的分支) while (循环语句) do (用在do-while循环结构中) for (一种循环结构的引导词) break (中断当前循环) continue( 回到一个块的开始处) return ( 从成员方法中返回数据) 用于定义访问权限修饰符的关键字 private (一种访问控制方式:私用模式) protected (一种访问控制方式:保护模式) public(一种访问控制方式:共用模式) 用于定义类,函数,变量修饰符的关键字 abstract ( 表明类或者成员方法具有抽象属性) final (用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变) static (表明具有静态属性) synchronized(表明一段代码需要同步执行) 用于定义类与类之间关系的关键字 extends ( 表明一个类型是另一个类型的子类型,这里常见的类型有类和接口) implements(表明一个类实现了给定的接口) 用于定义建立实例及引用实例,判断实例的关键字

new (用来创建新实例对象) this (指向当前实例对象的引用) super (表明当前对象的父类型的引用或者父类型的构造方法) instanceof(用来测试一个对象是否是指定类型的实例对象) 用于异常处理的关键字

try ( 尝试一个可能抛出异常的程序块) catch (用在异常处理中,用来捕捉异常) finally (用于处理异常情况,用来声明一个基本肯定会被执行到的语句块) throw ( 抛出一个异常) throws(声明在当前定义的成员方法中所有需要抛出的异常) 用于包的关键字 package (包) import(表明要访问指定的类或包) 其他修饰符关键字 native (用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的) strictfp (用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范) transient ( 声明不用序列化的成员域) volatile ( 表明两个或者多个变量必须同步地发生变化) assert(用来进行程序调试)

标识符

标识符概述 就是给类,接口,方法,变量等起名字时使用的字符序列 组成规则 英文大小写字母 数字字符 $和_ 注意事项 不能以数字开头 不能是Java中的关键字 区分大小写 标识符(常见命名规则) 包(其实就是文件夹,用于解决相同类名问题) 单级和多级 类或者接口 一个单词和多个单词 常量 一个单词和和多个单词分别举例

常量

常量概述 在程序执行的过程中其值不可以发生改变 Java中常量分类 字面值常量 自定义常量 字符串常量 用双引号括起来的内容 整数常量 所有整数 小数常量 所有小数 字符常量 用单引号括起来的内容(‘a’,’A’,’0’) 布尔常量 较为特有,只有true和false 空常量 null Java针对整数常量提供了4种表现形式 二进制 八进制 十进制 十六进制

不同进制的数据组成

二进制 由0,1组成。以0b开头 八进制 由0,1,…7组成。以0开头 十进制 由0,1,…9组成。整数默认是十进制的 十六进制 由0,1,…9,a,b,c,d,e,f(大小写均可)。以0x开头

变量概述

在程序执行的过程中,在某个范围内其值可以发生改变的量 理解:如同数学中的未知数 变量定义格式 数据类型 变量名 = 初始化值; 注意:格式是固定的,记住格式,以不变应万变

数据类型

Java语言是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存总分配了不同大小的内存空间

分类: A:基本数据类型:4类8种 整数:byte、short、int、long 浮点:float、double 字符:char 布尔:boolean B:引用数据类型:类,接口,数组。

算术运算符 +-*/ ++ --

赋值运算符 = , +=, -=, *=, /=, %= 比较运算符 == != < > <= >= instanceof 逻辑运算符 & | ^ ! && || 位运算符 << >> >>> & | ^ 三目运算符 (关系表达式)?表达式1:表达式2;

流程控制语句、跳转控制语句

流程控制语句分类

顺序结构 按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。

选择结构 if(关系表达式) { 语句体1; }else { 语句体2; }

switch(表达式) {

      case1:
        语句体1;
        break;
        case2:
        语句体2;
        break;
        …
        default:    
        语句体n+1;
        break;
}

循环语句

for(初始化语句;判断条件语句;控制条件语句) { 循环体语句; }

while(判 断条件语句) {

     循环体语句;

}

do {

     循环体语句;

}while((判 断条件语句);

跳转控制语句

break 中断 continue 继续 return 返回

方法、重载、数组、堆栈内存分配、数组遍历、获取最值、二维数组

方法

方法:就是完成特定功能的代码块 注意:在很多语言里面有函数的定义,而在Java中函数被称为方法。

方法格式:

修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2...) { 方法体语句; return 返回值; } 修饰符:目前就用 public static,后面我们再详细的讲解其他的修饰符。 返回值类型:就是功能结果的数据类型。 方法名:符合命名规则即可。方便我们的调用。 参数:

实际参数:就是实际参与运算的。 形式参数;就是方法定义上的,用于接收实际参数的。 参数类型:就是参数的数据类型 参数名:就是变量名 方法体语句:就是完成功能的代码。 return:结束方法的。 返回值:就是功能的结果,由return带给调用者。 1.方法不调用不执行 2.方法与方法是平级关系,不能嵌套定义 3.方法定义的时候参数之间用逗号隔开 4.方法调用的时候不用在传递数据类型 5.如果方法有明确的返回值,一定要有return带回一个值

重载

方法重载概述 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。 方法重载特点 与返回值类型无关,只看方法名和参数列表 在调用时,虚拟机通过参数列表的不同来区分同名方法

数组数组概念 数组是存储同一种数据类型多个元素的集合。也可以看成是一个容器。数组既可以存储基本数据类型,也可以存储引用数据类型。数组格式格式1:数据类型[] 数组名;格式2:数据类型 数组名[];注意:这两种格式中,数组中是没有元素值的。我们要对数组的元素进行初始化。数组初始化的概述:Java中的数组必须先初始化,然后才能使用。为数组中的数组元素分配内存空间,并为每个数组元素赋值。数组初始化的方式: 动态初始化:初始化时只指定数组长度,由系统为数组分配初始值。int[] arr = new int[3];静态初始化:初始化时指定每个数组元素的初始值,由系统决定数组长度。int[] arr = {1,2,3};遍历:for循环

二维数组

概述:一个元素为一维数组的数组。

格式

数据类型[][] 变量名 = 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个元素

面向对象思想、类与对象、成员/局部变量、匿名对象、封装、private、this、构造方法

面向对象思想

概述: 面向对象是基于面向过程的编程思想 特点: 更符合我们思想习惯的思想 可以将复杂的事情简单化 将我们从执行者变成了指挥者(角色发生了转换) 面向对象开发 就是不断的创建对象,使用对象,指挥对象做事情。 面向对象设计 其实就是在管理和维护对象之间的关系。 面向对象特征 封装(encapsulation) 继承(inheritance) 多态(polymorphism)

类与对象的关系

类:是一组相关的属性和行为的集合 属性——事物的基本描述,行为——事物的功能 Java语言中最基本的单位是类。所以,我们要用类来体现事物 对象:是该类事物的具体体现 举例: 类 ——学生就是类 对象 ——班长就是一个对象 三、成员变量和局部变量的区别 在类中的位置不同 成员变量——类中方法外 局部变量——方法内或者方法声明上 在内存中的位置不同 成员变量——堆内存 局部变量——栈内存 生命周期不同 成员变量——随着对象的存在而存在,随着对象的消失而消失 局部变量——随着方法的调用而存在,随着方法的调用完毕而消失 初始化值不同 成员变量——有默认的初始化值 局部变量——没有默认的初始化值,必须先定义,赋值,才能使用。 注意:成员变量和名称可以不可和局部变量一样呢? 答案当然是可以的,但是使用的时候要注意,先找小范围,再找大范围。

匿名对象

匿名对象:就是没有名字的对象。 是对象的一种简化表示形式

匿名对象的两种使用情况 对象调用方法仅仅一次的时候 作为实际参数传递

封装的概述:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

好处: 隐藏实现细节,提供公共的访问方式 提高了代码的复用性 提高安全性 原则: 将不需要对外提供的内容都隐藏起来 把属性隐藏,提供公共方法对其访问

private 关键字(意思是私有的) 是一个权限修饰符。 可以修饰成员(成员变量和成员方法) 被private修饰的成员只在本类中才能访问。 private最常见的应用: 把成员变量用private修饰 提供对应的getXxx()/setXxx()方法

this this关键字:代表所在类的对象引用。简单的说,它就代表当前类的一个对象。

注意: 方法被哪个对象调用,在该方法内部的this就代表那个对象 用法: 解决局部变量隐藏成员变量

构造方法

作用概述: 给对象的数据进行初始化 格式: 方法名与类名相同 没有返回值类型,连void都没有 没有具体的返回值

static关键字、main方法、java Api帮助文档的使用、Math类、代码块

static关键字

可以修饰成员变量和成员方法 static关键字特点 随着类的加载而加载 优先于对象存在 被类的所有对象共享 这也是我们判断是否使用静态关键字的条件 可以通过类名调用 static关键字注意事项 在静态方法中是没有this关键字的 静态方法只能访问静态的成员变量和静态的成员方法

静态变量和成员变量的区别

A:所属不同 静态变量:属于类,类变量 成员变量:属于对象,对象变量,实例变量 B:内存位置不同 静态变量:方法区的静态区 成员变量:堆内存 C:生命周期不同 静态变量:静态变量是随着类的加载而加载,随着类的消失而消失 成员变量:成员变量是随着对象的创建而存在,随着对象的消失而消失 D:调用不同 静态变量:可以通过对象名调用,也可以通过类名调用 成员变量:只能通过对象名调用

Java帮助文档的简单使用

1:打开帮助文档 2:点击显示,找到索引,看到输入框 3:知道你要找谁?以Scanner举例 4:在输入框里面输入Scanner,然后回车 5:看包 java.lang包下的类不需要导入,其他的全部需要导入。 要导入:java.util.Scanner 6:再简单的看看类的解释和说明,别忘了看看该类的版本 7:看类的结构 成员变量 字段摘要 构造方法 构造方法摘要 成员方法 方法摘要 8:学习构造方法 A:有构造方法 就创建对象 B:没有构造方法 成员可能都是静态的 9:看成员方法

A:左边 是否静态:如果静态,可以通过类名调用 返回值类型:人家返回什么,你就用什么接收。 B:右边 看方法名:方法名称不要写错 参数列表:人家要什么,你就给什么;人家要几个,你就给几个

代码块

局部代码块 在方法中出现;限定变量生命周期,及早释放,提高内存利用率

构造代码块 在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行 作用:可以把多个构造方法中的共同代码放到一起,对对象进行初始化。

静态代码块 在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。 作用:一般是对类进行初始化。

父与子的继承、super关键字、方法重写、方法重载

继承

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。 通过extends关键字可以实现类与类的继承 格式:class 子类名 extends 父类名 {} 单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。 有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。 提高了代码的复用性 多个类相同的成员可以放到同一个类中 提高了代码的维护性 如果功能的代码需要修改,修改一处即可 让类与类之间产生了关系,是多态的前提

类的耦合性很强 设计原则:高内聚低耦合。 简单的理解: 内聚就是自己完成某件事情的能力。 耦合就是类与类之间的关系。 我们在设计的时候原则是:自己能完成的就不麻烦别人,这样将来别人产生了修改,就对我的影响较小。 由此可见:在开发中使用继承其实是在使用一把双刃剑。今天我们还是以继承的好处来使用,因为继承还有很多其他的特性。

Java只支持单继承,不支持多继承。 Java支持多层继承(继承体系)

子类只能继承父类所有非私有的成员(成员方法和成员变量) 其实这也体现了继承的另一个弊端:打破了封装性 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。 不要为了部分功能而去继承 我们到底在什么时候使用继承呢? 继承中类之间体现的是:”is a”的关系。 举例:水果和苹果,苹果是一种水果。 学生和人,学生是人的一种。 所以我们总结采用假设法。如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。

继承中成员变量的关系 A:子类中的成员变量和父类中的成员变量名称不一样,这个太简单。 B:子类中的成员变量和父类中的成员变量名称一样,这个怎么玩呢? 结论在子类方法中访问一个变量的查找顺序: a:在子类方法的局部范围找,有就使用 b:在子类的成员范围找,有就使用 c:在父类的成员范围找,有就使用 d:如果还找不到,就报错。

super关键字

super的用法和this很像 this代表本类对应的引用。 super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员) 用法(this和super均可如下使用) 访问成员变量 this.成员变量 调用本类的成员变量 super.成员变量 调用父类的成员变量 访问构造方法 this(…) 调用本类的构造方法 super(…) 调用父类的构造方法 访问成员方法 this.成员方法() 调用本类的成员方法 super.成员方法() 调用父类的成员方法

继承中构造方法的关系 子类中所有的构造方法默认都会访问父类中空参数的构造方法 因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。 注意:子类每一个构造方法的第一条语句默认都是:super();

this(…)或者super(…)必须出现在第一条语句上。

继承中成员方法的关系: A:子类中的方法和父类中的方法声明不一样,这个太简单。 B:子类中的方法和父类中的方法声明一样,这个该怎么玩呢? 通过子类对象调用方法: a:先找子类中,看有没有这个方法,有就使用,没有就在父类中找 b:再看父类中,有没有这个方法,有就使用 c:如果没有就报错。

方法重写、方法重载

方法重写概述 子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。 方法重载概述 本类中出现的方法名一样,参数列表不同的方法。与返回值无关。 使用特点: 如果方法名不同,就调用对应的方法 如果方法名相同,最终使用的是子类自己的 方法重写的应用: 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。

方法重写的注意事项 A:父类中私有方法不能被重写(因为父类私有方法子类根本就无法继承) B:子类重写父类方法时(访问权限不能更低,最好就一致) C:父类静态方法,子类也必须通过静态方法进行重写 子类重写父类方法的时候,最好声明一模一样。

方法重载能改变返回值类型,因为它和返回值类型无关。

this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。 this:代表当前类的对象引用 super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员) 场景: 成员变量:this.成员变量——super.成员变量 构造方法:this(…)——super(…) 成员方法:this.成员方法——super.成员方法

final关键字、抽象类abstract、接口interface、权限修饰符、导包

final关键字

final关键字是最终的意思,可以修饰类,成员变量,成员方法。 修饰类,类不能被继承 修饰变量,变量就变成了常量,只能被赋值一次 修饰方法,方法不能被重写

抽象类(abstract)

概述: 动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。 我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。

抽象类特点 抽象类和抽象方法必须用abstract关键字修饰 格式 abstract class 类名 {} public abstract void eat(); 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类 抽象类不能实例化 因为它不是具体的。 那么,抽象类如何实例化呢? 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。 抽象类的子类 如果不想重写抽象方法,该子类是一个抽象类。 重写所有的抽象方法,这个时候子类是一个具体的类。

抽象类的成员特点: 成员变量:既可以是变量,也可以是常量。 构造方法:构造方法不能被实例化。所以构造方法的特点是:用于子类访问父类数据的初始化。 抽象类的成员方法特性: 可以有抽象方法,强制要求子类做的事情。 也可以有非抽象方法,子类继承的事情,提高代码复用性。

abstract不能和哪些关键字共存? private冲突、final冲突、static无意义

接口(interface)

接口用关键字interface表示 格式:interface 接口名 {} 类实现接口用implements表示 格式:class 类名 implements 接口名 {} 接口不能实例化 那么,接口如何实例化呢? 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态(下一节讲)。 接口的子类 可以是抽象类。但是意义不大。 可以是具体类。要重写接口中的所有抽象方法。(推荐方案)

接口成员特点 成员变量;只能是常量,并且是静态的。 默认修饰符:public static final 建议:自己手动给出。 构造方法:接口没有构造方法。因为接口主要是扩展功能的,而没有具体存在 成员方法:只能是抽象方法。 默认修饰符:public abstract 建议:自己手动给出。

类与类,类与接口以及接口与接口的关系

类与类: 继承关系,只能单继承,可以多层继承。 类与接口: 实现关系,可以单实现,也可以多实现。 并且还可以在继承一个类的同时实现多个接口。 接口与接口: 继承关系,可以单继承,也可以多继承。

抽象类和接口的区别

成员区别 抽象类: 成员变量:可以变量,也可以常量 构造方法:有 成员方法:可以抽象,也可以非抽象 接口: 成员变量:只可以常量 成员方法:只可以抽象

关系区别 类与类 继承,单继承 类与接口 实现,单实现,多实现 接口与接口 继承,单继承,多继承 设计理念区别 抽象类 被继承体现的是:”is a”的关系。 抽象类中定义的是该继承体系的共性功能。 接口 被实现体现的是:”like a”的关系。 接口中定义的是该继承体系的扩展功能。

权限修饰符

修饰符: 权限修饰符:private,默认的,protected,public 状态修饰符:static,final 抽象修饰符:abstract 类: 权限修饰符:默认修饰符,public 状态修饰符:final 抽象修饰符:abstract 用的最多的就是:public 成员变量: 权限修饰符:private,默认的,protected,public 状态修饰符:static,final 用的最多的就是:private 构造方法: 权限修饰符:private,默认的,protected,public 用的最多的就是:public 成员方法: 权限修饰符:private,默认的,protected,public 状态修饰符:static,final 抽象修饰符:abstract 用的最多的就是:public 除此以外的组合规则: 成员变量: public static final 成员方法: public static public abstract public final

导包

导包概述 不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能。 导包格式 import 包名; 注意: 我们用那个报就导那个包。

多态、(成员、局部、匿名)内部类

多态

概述:某一个事物,在不同时刻表现出来的不同状态。 前提:要有继承关系,要有方法重写,有父类引用指向子类对象。

成员变量 编译看左边,运行看左边 构造方法 子类的构造都会默认访问父类构造 成员方法 编译看左边,运行看右边 静态方法 编译看左边,运行看左边 所以静态方法不能算方法的重写

提高了代码的维护性(继承保证) 提高了代码的扩展性(由多态保证)

向上转型 从子到父 父类引用指向子类对象 Fu f = new Zi(); 向下转型 从父到子 父类引用转为子类对象 Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。

内部类

概述:把类定义在其他类的内部,这个类就被称为内部类。 举例:在类A中定义了一个类B,类B就是内部类。

内部的访问特点: 内部类可以直接访问外部类的成员,包括私有。 外部类要访问内部类的成员,必须创建对象。 内部类位置 成员位置:在成员位置定义的类,被称为成员内部类。 局部位置:在局部位置定义的类,被称为局部内部类。

外部类名.内部类名 对象名 = 外部类对象.内部类对象; Outer.Inner oi = new Outer().new Inner();

成员内部的常见修饰符 private 为了保证数据的安全性 static 为了让数据访问更方便 被静态修饰的成员内部类只能访问外部类的静态成员 内部类被静态修饰后的方法 静态方法 非静态方法

局部内部类 可以直接访问外部类的成员 在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能 局部内部类访问局部变量的注意事项:

局部内部类访问局部变量必须用final修饰 原因:局部变量是随着方法的调用而调用,随着调用完毕而消失。而堆内存的内容并不会立即消失。所以,我们加final修饰。加入final修饰后,这个变量就成了常量。既然是常量。你消失了。在内存中存储的是数据20,所以,还是有数据在使用。

匿名内部类就是内部类的简化写法。 前提:存在一个类或者接口 这里的类可以是具体类也可以是抽象类。 格式: new 类名或者接口名() {重写方法;} 本质: 是一个继承了类或者实现了接口的子类匿名对象

Object类、String类及其获取功能、转换功能、其他功能

Object类

Object类的概述

类 Object 是类层次结构的根类。 每个类都使用 Object 作为超类。 所有的类都直接或者间接的继承自Object类。

hashCode() 该对象的哈希码值。默认情况下,该方法会根据对象的地址来计算 getClass() 返回此 Object 的运行时类。 toString() equals(Object obj) finalize() 垃圾回收 clone()

String类概述及其构造方法

String类概述

字符串是由多个字符组成的一串数据(字符序列) 字符串可以看成是字符数组 通过查看API,我们可以知道

字符串字面值”abc”也可以看成是一个字符串对象。 字符串是常量,一旦被赋值,就不能被改变。 构造方法

public String() 空构造 public String(byte[] bytes) 把字节数组转成字符串 public String(byte[] bytes,int offset,int length) 把字节数组的一部分转成字符串 public String(char[] value) 把字符数组转成字符串 public String(char[] value,int offset,int count) 把字符数组的一部分转成字符串 public String(String original) 把字符串常量值转成字符串 字符串的方法:

public int length():返回此字符串的长度。 String s = new String(“hello”)和String s = “hello”;的区别 前者会创建2个对象,后者创建1个对象。我们可以用 == 和 equals来比较

String类的判断功能 boolean equals(Object obj) :比较字符串的内容是否相同,区分大小写 boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写 boolean contains(String str):判断大字符串中是否包含小字符串 boolean startsWith(String str):判断字符串是否以某个指定的字符串开头 boolean endsWith(String str):判断字符串是否以某个指定的字符串结尾 boolean isEmpty():判断字符串是否为空

String类的获取功能

int length():获取字符串的长度。 char charAt(int index):获取指定索引位置的字符 int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。 int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引。 int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引。 int indexOf(String str,int fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引。 String substring(int start):从指定位置开始截取字符串,默认到末尾。 String substring(int start,int end):从指定位置开始到指定位置结束截取字符串。

String的转换功能 byte[] getBytes():把字符串转换为字节数组 char[] toCharArray():把字符串转换为字符数组 static String valueOf(char[] chs):把字符数组转成字符串 static String valueOf(int i):把int类型的数据转成字符串 String类的valueOf方法可以把任意类型的数据转成字符串 String toLowerCase():把字符串转成小写 String toUpperCase():把字符串转成大写 String concat(String str):把字符串拼接

String类的其他功能

替换功能: String replace(char old,char new) String replace(String old,String new) 去除字符串两空格 String trim() 按字典顺序比较两个字符串 int compareTo(String str) int compareToIgnoreCase(String str)

StringBuffer类概述、添加、删除、替换、反转、截取功能、StringBuilder

StringBuffer类概述

我们如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。而StringBuffer就可以解决这个问题。 下面我们来学习 StringBuffer的构造方法:

public StringBuffer():无参构造方法 public StringBuffer(int capacity):指定容量的字符串缓冲区对象 public StringBuffer(String str):指定字符串内容的字符串缓冲区对象 StringBuffer的方法:

public int capacity():返回当前容量。 理论值(初始化默认容量是16) public int length():返回长度(字符数)。 实际值

StringBuffer类的成员方法

添加功能 public StringBuffer append(String str):可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身 public StringBuffer insert(int offset,String str):在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身 删除功能 public StringBuffer deleteCharAt(int index):删除指定位置的字符,并返回本身 public StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容,并返回本身 替换功能 public StringBuffer replace(int start,int end,String str):从start开始到end用str替换 反转功能 public StringBuffer reverse() 截取功能 public String substring(int start) public String substring(int start,int end)

String,StringBuffer,StringBuilder的区别?

String是内容不可变的,而StringBuffer,StringBuilder都是内容可变的。 StringBuffer是同步的,数据安全,效率低;StringBuilder是不同步的,数据不安全,效率高

StringBuffer和数组的区别? 二者都可以看出是一个容器,装其他的数据。 但是呢,StringBuffer的数据最终是一个字符串数据。 而数组可以放置多种数据,但必须是同一种数据类型的。

StringBuilder 在Java中,首先出现的是StringBuffer,而StringBuilder类来源于jdk1.5及以后的版本 我们查看API了解一下StringBuilder类 他的用途和StringBuffer类相同,用来进行字符串的连接、修改。 这里我们对他了解一下就可以了。

数组高级(冒泡排序和选择排序)、Arrays类、基本类型包装类、Integer类

排序

冒泡排序 相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处.同理,即可得到排好序的数组 选择排序 从0索引开始,依次和后面元素比较,小的往前放,第一次完毕,最小值出现在了最小索引处 //冒泡排序代码 public static void bubbleSort(int[] arr){ for (int x = 0; x < arr.length - 1; x++) { for (int y = 0; y < arr.length - 1 - x; y++) { if (arr[y] > arr[y + 1]) { int temp = arr[y]; arr[y] = arr[y + 1]; arr[y + 1] = temp; } } } } //数组排序之选择排序 public static void selectSort(int[] arr){ for(int x=0; x<arr.length-1; x++){ for(int y=x+1; y<arr.length; y++){ if(arr[y] <arr[x]){ int temp = arr[x]; arr[x] = arr[y]; arr[y] = temp; } } } }

Arrays类概述

针对数组进行操作的工具类。 提供了排序,查找等功能。 成员方法 public static String toString(int[] a):把数组转成字符串 public static void sort(int[] a):对数组进行排序 public static int binarySearch(int[] a,int key):二分查找

基本类型包装类概述

将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据。 常用的操作之一:用于基本数据类型与字符串之间的转换。 基本类型和包装类的对应 byte —-Byte short —- Short int —- Integer long —- Long float —- Float double —- Double char —- Character boolean —- Boolean

Integer类概述及其构造方法

Integer类概述 Integer 类在对象中包装了一个基本类型 int 的值 该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还提供了处理 int 类型时非常有用的其他一些常量和方法 构造方法 public Integer(int value) public Integer(String s) 注意:这个字符串必须是由数字字符组成 常用的基本进制转换 public static String toBinaryString(int i) public static String toOctalString(int i) public static String toHexString(int i) 十进制到其他进制 public static String toString(int i,int radix) 其他进制到十进制 public static int parseInt(String s,int radix)

Character类、Math类、Random类、System类

Character类

Character 类在对象中包装一个基本类型 char 的值,此外,该类提供了几种方法,以确定字符的类别(小写字母,数字,等等),并将字符从大写转换成小写,反之亦然 Character类成员方法 public static boolean isUpperCase(char ch):判断给定的字符是否是大写字符 public static boolean isLowerCase(char ch):判断给定的字符是否是小写字符 public static boolean isDigit(char ch):判断给定的字符是否是数字字符 public static char toUpperCase(char ch):把给定的字符转换为大写字符 public static char toLowerCase(char ch):把给定的字符转换为小写字符

Math类

Math类概述 Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。 成员变量 public static final double PI public static final double E 成员方法 public static int abs(int a):绝对值 public static double ceil(double a):向上取整 public static double floor(double a):向下取整 public static int max(int a,int b):最大值 public static double pow(double a,double b):a的b次幂 public static double random():随机数 [0.0,1.0) public static int round(float a) 四舍五入 public static double sqrt(double a):正平方根

Random类

Random类概述 此类用于产生随机数 如果用相同的种子创建两个 Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数字序列。 构造方法 public Random() public Random(long seed) 成员方法 public int nextInt():返回的是int范围内的随机数 public int nextInt(int n):返回的是[0,n)范围的内随机数

System类概述

System 类包含一些有用的类字段和方法。它不能被实例化。 成员方法 public static void gc():运行垃圾回收器。 public static void exit(int status):终止当前正在运行的 Java 虚拟机。参数用作状态码;根据惯例,非 0 的状态码表示异常终止。 public static long currentTimeMillis():返回以毫秒为单位的当前时间 public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length):从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。

BigInteger类、BigDecimal类、Date类、DateFormat类、Calendar类

BigInteger类

BigInteger类概述 可以让超过Integer范围内的数据进行运算 构造方法 public BigInteger(String val) BigInteger类成员方法 public BigInteger add(BigInteger val):加 public BigInteger subtract(BigInteger val):减 public BigInteger multiply(BigInteger val):乘 public BigInteger divide(BigInteger val):除 public BigInteger[] divideAndRemainder(BigInteger val):返回商和余数的数组

BigDecimal类

由于在运算的时候,float类型和double很容易丢失精度。所以,为了能精确的表示、计算浮点数,Java提供了BigDecimal类 BigDecimal类概述 不可变的、任意精度的有符号十进制数。 构造方法 public BigDecimal(String val) BigDecimal类成员方法 public BigDecimal add(BigDecimal augend):加 public BigDecimal subtract(BigDecimal subtrahend):减 public BigDecimal multiply(BigDecimal multiplicand):乘 public BigDecimal divide(BigDecimal divisor):除 public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode) :商,保留几位小数

下面我们来看看除法的详细说明: divide(BigDecimal divisor, int scale, introundingMode) BigDecimal的setScale方法 :BigDecimal.setScale() 方法用于格式化小数点 ,表示保留一位小数,默认用四舍五入方式

直接删除多余的小数位,如2.35会变成2.3 setScale(1,BigDecimal.ROUND_DOWN) 进位处理,2.35变成2.4 setScale(1,BigDecimal.ROUND_UP) 四舍五入,2.35变成2.4 setScale(1,BigDecimal.ROUND_HALF_UP) 四舍五入,2.35变成2.3,如果是5则向下舍setScaler(1,BigDecimal.ROUND_HALF_DOWN) BigDecimal枚举常量用法摘要 : CEILING 向正无限大方向舍入的舍入模式。 DOWN 向零方向舍入的舍入模式。 FLOOR 向负无限大方向舍入的舍入模式。 HALF_DOWN 向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。 HALF_EVEN 向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。 HALF_UP 向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。 UNNECESSARY 用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。 UP 远离零方向舍入的舍入模式。

Date类

Date类概述 类 Date 表示特定的瞬间,精确到毫秒。 构造方法 public Date():根据当前的默认毫秒值创建日期对象 public Date(long date):根据给定的毫秒值创建日期对象 成员方法 public long getTime():获取时间,以毫秒为单位(从Date得到一个毫秒值) public void setTime(long time):设置时间(把一个毫秒值转换为Date)

DateFormat类

DateFormat类概述 DateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间。 是抽象类,所以使用其子类SimpleDateFormat SimpleDateFormat构造方法 public SimpleDateFormat():默认模式 public SimpleDateFormat(String pattern):给定的模式

成员方法 public final String format(Date date):Date – String(格式化) public Date parse(String source):String – Date(解析)

Calendar类

Calendar类概述 Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。 成员方法 public static Calendar getInstance() public int get(int field):返回给定日历字段的值。日历类中的每个日历字段都是静态的成员变量,并且是int类型。 public void add(int field,int amount):根据给定的日历字段和对应的时间,来对当前的日历进行操作。 public final void set(int year,int month,int date):设置当前日历的年月日

集合框架、Collection接口、迭代器Iterator、List接口、ListIterator列表迭代器

集合框架

集合类的由来 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类。 数组和集合类同是容器,他们有何区别 数组虽然也可以存储对象,但长度是固定的。数组中可以存储基本数据类型。 集合长度是可变的。集合只能存储对象。 集合类的特点 集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

Collection接口

概述(通过查看API) Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。 Collection的功能概述: 1:添加功能 boolean add(Object obj):添加一个元素 boolean addAll(Collection c):添加一个集合的元素 2:删除功能 void clear():移除所有元素 boolean remove(Object o):移除一个元素 boolean removeAll(Collection c):移除一个集合的元素 3:判断功能 boolean contains(Object o):判断集合中是否包含指定的元素 boolean containsAll(Collection c):判断集合中是否包含指定的集合元素 boolean isEmpty():判断集合是否为空 4:获取功能 Iterator iterator() 5:长度功能 int size():元素的个数 6:交集功能 boolean retainAll(Collection c) 7:把集合转换为数组 Object[] toArray()

迭代器Iterator

Iterator接口概述 对 collection 进行迭代的迭代器 依赖于集合而存在 成员方法 boolean hasNext() next()

Iterator it = c.iterator(); while (it.hasNext()) { String s = (String) it.next(); System.out.println(s); }

List接口

List接口概述 有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。 与 set 不同,列表通常允许重复的元素。 所以我们可以看出List和Set的区别很明显

List接口:元素是有序的,元素可以重复,因为该集合体系有索引 Set接口:元素是无序,元素不可以重复,不能索引 下面我们来看List里面都有哪些成员方法

List接口成员方法

添加功能 void add(int index,Object element):在指定位置添加元素 获取功能

Object get(int index):获取指定位置的元素 删除功能

Object remove(int index):根据索引删除元素,返回被删除的元素 修改功能 Object set(int index,Object element):根据索引修改元素,返回被修饰的元素

ListIterator列表迭代器

迭代器遍历元素的时候,通过集合是不能修改元素的。 // 方式1:迭代器迭代元素,迭代器修改元素 // 而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIterator ListIterator lit = list.listIterator(); while (lit.hasNext()) { String s = (String) lit.next(); if ("world".equals(s)) { lit.add("javaee"); } } System.out.println("使用ListIterator迭代器后得到的结果:" + list); // 方式2:集合遍历元素,集合修改元素(普通for) for (int x = 0; x < list.size(); x++) { String s = (String) list.get(x); if ("world".equals(s)) { list.add("javaee"); } } System.out.println("使用集合遍历后得到的结果:" + list);

List的三个子类、ArrayList类、Vector类、LinkedList类的使用与练习

List的三个子类

ArrayList类 Vector类 LinkedList类 ArrayList: 底层数据结构是数组,查询快,增删慢。 线程不安全,效率高。 Vector: 底层数据结构是数组,查询快,增删慢。 线程安全,效率低。 LinkedList: 底层数据结构是链表,查询慢,增删快。 线程不安全,效率高。

Vector类的使用

Vector类它有特有的功能:是什么呢?

添加功能 public void addElement(Object obj) 获取功能 public Object elementAt(int index) public Enumeration elements()

LinkedList类的使用

在LinkedList类中,它也有自己特有的功能,下面我们来了解

添加功能 public void addFirst(Object e) public void addLast(Object e) 获取功能 public Object getFirst() public Obejct getLast() 删除功能 public Object removeFirst() public Object removeLast()

泛型的概述、使用、泛型类、泛型方法、泛型接口、泛型高级(通配符)

泛型

JDK1.5以后出现的机制 是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。 好处 提高了程序的安全性 把运行时期的问题提前到了编译期间 避免了强制类型转换 泛型的使用 我们使用泛型前,先来了解它的格式。

格式 <数据类型> 此处的数据类型只能是引用类型。

泛型类

把泛型定义在类上 格式:public class 类名<泛型类型1,…> 注意:泛型类型必须是引用类型

泛型方法

把泛型定义在方法上 格式:public <泛型类型> 返回类型 方法名(泛型类型 .)

泛型接口

把泛型定义在接口上 格式:public interface 接口名<泛型类型1…>

泛型高级(通配符)

泛型通配符 < ?> 任意类型,如果没有明确,那么就是Object以及任意的Java类了 ? extends E 向下限定,E及其子类 ? super E 向上限定,E及其父类

Set集合、增强for、HashSet类、LinkedHashSet类、TreeSet类、二叉树、Comparator 排序

Set

元素是无序(存储顺序和取出顺序不一致),元素是唯一的,不可重复的

增强for

增强for:是for循环的一种。

格式: for(元素数据类型 变量 : 数组或者Collection集合) { 使用变量即可,该变量就是元素 }

HashSet类

什么是HashSet? HashSet类概述 不保证 set 的迭代顺序 特别是它不保证该顺序恒久不变。 HashSet如何保证元素唯一性 底层数据结构是哈希表(元素是链表的数组) 哈希表依赖于哈希值存储 添加功能底层依赖两个方法: int hashCode() boolean equals(Object obj)

add方法的源码 步骤: 首先比较哈希值 如果相同,继续走,比较地址值或者走equals() 如果不同,就直接添加到集合中 按照方法的步骤来说: 先看hashCode()值是否相同 相同:继续走equals()方法 返回true: 说明元素重复,就不添加 返回false:说明元素不重复,就添加到集合 不同:就直接把元素添加到集合 如果类没有重写这两个方法,默认使用的Object()。一般来说不同相同。 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。

存储自定义对象要重写hashCode()和equals()这两个方法

LinkedHashSet类

概述 底层数据结构由哈希表和链表组成 由链表保证元素有序(存储和取出是一致) 由哈希表保证元素唯一性

TreeSet类

概述 使用元素的自然顺序对元素进行排序 或者根据创建 set 时提供的 Comparator 进行排序 所以排序有两种方式 自然排序 比较器排序 具体取决于使用的构造方法。

TreeSet是如何保证元素的排序和唯一性的 底层数据结构是红黑树(红黑树是一种自平衡的二叉树)

二叉树

第一个元素存储的时候,直接作为根节点存储。 从第二个元素开始,每个元素从根节点开始比较 比根节点元素大,就放在右边 比根节点元素小,就放在左边 相等的话就忽略。

TreeSet 的Comparator 排序

排序: A:自然排序(元素具备比较性) 让元素所属的类实现自然排序接口 Comparable B:比较器排序(集合具备比较性) 让集合的构造方法接收一个比较器接口的子类对象 Comparator

Map集合概述及成员方法、Map集合的三个子类、Collections类

Map集合

概述 将键映射到值的对象 一个映射不能包含重复的键 每个键最多只能映射到一个值 前面我们一直在学Collection集合,那么它和Map集合有什么区别呢?

Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的。可以把这个理解为:夫妻对 Collection集合存储元素是单独出现的,Collection的儿子Set是唯一的,List是可重复的。可以把这个理解为:光棍 注意: Map集合的数据结构值针对键有效,跟值无关 Collection集合的数据结构是针对元素有效 下面我们来了解Map集合的功能概述

添加功能 V put(K key,V value):添加元素。 删除功能 void clear():移除所有的键值对元素 V remove(Object key):根据键删除键值对元素,并把值返回

判断功能 boolean containsKey(Object key):判断集合是否包含指定的键 boolean containsValue(Object value):判断集合是否包含指定的值 boolean isEmpty():判断集合是否为空 获取功能 V get(Object key):根据键获取值 Set keySet():获取集合中所有键的集合 Collection values():获取集合中所有值的集合 Set< Map.Entry< K,V>> entrySet():返回的是键值对对象的集合 长度功能 int size():返回集合中的键值对的对数

Map子类

HashMap HashMap类概述 键是哈希表结构,可以保证键的唯一性 常用案例 HashMap< String,String> HashMap< Integer,String> HashMap< String,Student> HashMap< Student,String> 上面的也不是非要是学生对象,可以是你需求的对象 LinkedHashMap 概述 Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。 由哈希表保证键的唯一性,不可重复 由链表保证键盘的有序(存储和取出的顺序一致) TreeMap 概述 键是红黑树结构,可以保证键的排序和唯一性

Collections类概述

针对集合进行操作的工具类,都是静态方法。 Collection和Collections的区别 Collection:是单列集合的顶层接口,有子接口List和Set。 Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法 Collections成员方法 public static < T> void sort(List list):排序 默认情况下是自然顺序。 public static < T> int binarySearch(List< ?> list,T key):二分查找 public static < T> T max(Collection< ?> coll):最大值 public static void reverse(List< ?> list):反转 public static void shuffle(List< ?> list):随机置换

异常的概述、Try…Catch、多异常处理、Throws、throw、finally、自定义异常及异常的注意事项

异常的概述

异常概述 异常就是Java程序在运行过程中出现的错误。 由来 问题也是现实生活中一个具体事务,也可以通过java 的类的形式进行描述,并封装成对象。 其实就是Java对不正常情况进行描述后的对象体现。

程序的异常:Throwable 严重问题:Error 我们不处理。这种问题一般都是很严重的,比如说内存溢出。 问题:Exception 编译期问题:不是RuntimeException的异常 必须进行处理的,因为你不处理,编译就不能通过。 运行期问题:RuntimeException 这种问题我们也不处理,因为是你的问题,而且这个问题出现肯定是我们的代码不够严谨,需要修正代码的。

JVM的默认处理方案 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台 程序停止执行

Try…Catch

那么我们自己如何处理异常呢?

异常的处理方案 try…catch…finally throws

多异常处理

每一个写一个try…catch(这样有点过于麻烦) 写一个try,多个catch

Throwable中的方法

getMessage():获取异常信息,返回字符串。 toString():获取异常类名和异常信息,返回字符串。 printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。 printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。 异常声明Throws 有些时候,我们是可以对异常进行处理的,但是又有些时候,我们根本就没有权限去处理某个异常。或者说,我处理不了,我就不处理了。 为了解决出错问题,Java针对这种情况,就提供了另一种处理方案:抛出。

格式: throws 异常类名 注意:这个格式必须跟在方法的括号后面。

throw

上面讲了throws,那么throw又是什么鬼,怎么用,他们有什么区别呢,让我们带着疑问出发

先了解他的概念: throw:在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。如果出现了异常情况,我们可以把该异常抛出,这个时候的抛出的应该是异常的对象。

throws和throw的区别 throws 用在方法声明后面,跟的是异常类名 可以跟多个异常类名,用逗号隔开 表示抛出异常,由该方法的调用者来处理 throws表示出现异常的一种可能性,并不一定会发生这些异常

throw 用在方法体内,跟的是异常对象名 只能抛出一个异常对象名 表示抛出异常,由方法体内的语句处理 throw则是抛出了异常,执行throw则一定抛出了某种异常

原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws 区别: 后续程序需要继续运行就try 后续程序不需要继续运行就throws

finally

finally的特点 被finally控制的语句体一定会执行 特殊情况:在执行到finally之前jvm退出了(比如System.exit(0)) finally的作用 用于释放资源,在IO流操作和数据库操作中会见到(我们后面学习中会看到) finally的用法很简单,这里就不举例了,我们看一个关于finally典型的题

final,finally和finalize的区别? final 最终的意思,可以修饰类,成员变量,成员方法 修饰类,类不能被继承 修饰变量,变量是常量 修饰方法,方法不能被重写 finally 是异常处理的一部分,用于释放资源。 一般来说,代码肯定会执行,特殊情况:在执行到finally之前jvm退出了 finalize 是Object类的一个方法,用于垃圾回收

自定义异常

java不可能对所有的情况都考虑到,所以,在实际的开发中,我们可能需要自己定义异常。而我们自己随意的写一个类,是不能作为异常类来看的,要想你的类是一个异常类,就必须继承自Exception或者RuntimeException

异常注意事项 子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。 如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常 如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws

File类概述、创建、删除、重命名、判断、获取、文件名称过滤器

File类

File类的概述 文件和目录(文件夹)路径名的抽象表示形式 构造方法 File(String pathname):根据一个路径得到File对象 File(String parent, String child):根据一个目录和一个子文件/目录得到File对象 File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

File类的成员方法

创建功能: public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了 public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了 public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来

删除功能

public boolean delete() 重命名功能 public boolean renameTo(File dest)

判断功能 public boolean isDirectory():判断是否是目录 public boolean isFile():判断是否是文件 public boolean exists():判断是否存在 public boolean canRead():判断是否可读 public boolean canWrite():判断是否可写 public boolean isHidden():判断是否隐藏

获取功能(基本获取功能)

public String getAbsolutePath():获取绝对路径 public String getPath():获取相对路径 public String getName():获取名称 public long length():获取长度。字节数 public long lastModified():获取最后一次的修改时间,毫秒值

获取功能(高级获取功能) public String[] list():获取指定目录下的所有文件或者文件夹的名称数组 public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组

文件名称过滤器

public class FileDemo2 { public static void main(String[] args) { // 封装e判断目录 File file = new File("e:\");

    // 获取该目录下所有文件或者文件夹的String数组
    // public String[] list(FilenameFilter filter)
    String[] strArray = file.list(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            //如果是文件,输出以.jpg结尾的文件,这两个条件要同时满足
            return new File(dir, name).isFile() && name.endsWith(".jpg");
        }
    });

    // 遍历
    for (String s : strArray) {
        System.out.println(s);
    }
}

}

递归、IO流概述、字节流写数据、读取数据、复制数据、字节缓冲流

递归

递归 方法定义中调用方法本身的现象

递归解决问题的思想 做递归要写一个方法 找到出口条件 找到规律

递归的注意事项 递归一定要有出口,否则就是死递归 递归的次数不能太多,否则就内存溢出 构造方法不能递归使用

IO流概述

IO流用来处理设备之间的数据传输 上传文件和下载文件 Java对数据的操作是通过流的方式 Java用于操作流的对象都在IO包中 IO流分类 按照数据流向 输入流 读取数据 输出流 写出数据 按照数据类型 字节流 字节输入流 读取数据 InputStream 字节输出流 写出数据 OutputStream 字符流 字符输入流 读取数据 Reader 字符输出流 写出数据 Writer

IO流常用基类(这个我们上面也提到了) 字节流的抽象基类: InputStream ,OutputStream。 字符流的抽象基类: Reader , Writer。

字节流写数据

FileOutputStream的构造方法 FileOutputStream(File file) FileOutputStream(String name)

字节流写数据的方式 public void write(int b) :写一个字节 public void write(byte[] b):写一个字节数组 public void write(byte[] b,int off,int len):写一个字节数组的一部分

字节流读取数据

FileInputStream的构造方法 FileInputStream(File file) FileInputStream(String name) FileInputStream的成员方法 public int read():一次读取一个字节 public int read(byte[] b):一次读取一个字节数组 我们先来看下字节输入流操作步骤:

A:创建字节输入流对象 B:调用read()方法读取数据,并把数据显示在控制台 C:释放资源

字节流复制数据

public class CopyFileDemo { public static void main(String[] args) throws IOException { // 封装数据源 FileInputStream fis = new FileInputStream("a.txt"); // 封装目的地 FileOutputStream fos = new FileOutputStream("b.txt");

    int by = 0;
    while ((by = fis.read()) != -1) {
        fos.write(by);
    }
    // 释放资源(先关谁都行)
    fos.close();
    fis.close();
}

}

字节缓冲流

字节缓冲输出流 BufferedOutputStream 字节缓冲输入流 BufferedInputStream

转换流概述及用法、简化写法FileWriter和 FileReader、字符缓冲流及特殊用法、字节流字符流复制文件方法总结

转换流: 

 1)数据转换      InputStreamReader: 该类本身是字符(Reader)系列, 功能:能够把字节输入流转换成字符输入流      OutputStreamWriter: 该类本身是字符(Writer)系列, 功能:能够把字符输出流转换成字节输出流    2)编码转换           能够对流数据进行字符编码转换

简化写法FileWriter和 FileReader

FileWriter fileWriter = new FileWriter("test.txt"); FileReader fileReader = new FileReader("demo.txt"); // 读取单个字符,自动往下读 int cd = fileReader.read();

字符缓冲流及特殊用法

BufferedWriter FileWriter fw = new FileWriter("buffer.txt"); // 为了提高写入流的效率加入了缓冲技术 BufferedWriter bufw = new BufferedWriter(fw); //写入数据 bufw.write("hello"); //换行 bufw.newLine();

        //只要用到了缓冲区,就需要刷新
        bufw.flush();

        //缓冲区关闭的就是关联的流
        bufw.close();

BufferedReader // 创建一个读取流对象和文件相关联 FileReader fr = new FileReader("buffer.txt"); // 为了提高效率,加入缓冲技术 BufferedReader bfr = new BufferedReader(fr);

        String line = null;
        while((line = bfr.readLine()) != null){
            System.out.println(line);
        }
        bfr.close();

字节流字符流复制文件方法总结

/**
     * 缓冲区文件复制
     */
    BufferedReader bufr = null;
    BufferedWriter bufw = null;

    try {
        bufr = new BufferedReader(new FileReader("buffer.txt"));
        bufw = new BufferedWriter(new FileWriter("buffercopy.txt"));
        String line = null;
        while((line = bufr.readLine()) != null){
            bufw.write(line);
        }
        //关闭流
        bufr.close();
        bufw.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

操作基本数据类型的流、内存操作流、打印流、随机访问流、合并流、序列化流

操作基本数据类型的流

操作基本数据类型 DataInputStream DataOutputStream DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt"));

内存操作流

操作字节数组 ByteArrayInputStream ByteArrayOutputStream 操作字符数组 CharArrayReader CharArrayWrite 操作字符串 StringReader StringWriter

打印流

打印流分为两类 字节流打印流 PrintStream 字符打印流 PrintWriter

随机访问流

RandomAccessFile 概述:RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。 public RandomAccessFile(String name,String mode): 第一个参数是文件路径,第二个参数是操作文件的模式。 模式有四种,我们最常用的一种叫”rw”,这种方式表示我既可以写数据,也可以读取数据

合并流

SequenceInputStream

概述:SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。

SequenceInputStream的构造方法 SequenceInputStream(InputStream s1, InputStream s2) SequenceInputStream(Enumeration < ? extends InputStream> e) 把多个文件的内容写入到一个文本文件

序列化流

ObjectOutputStream 反序列化流 ObjectInputStream 序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 –> 流数据(ObjectOutputStream) 反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 –>对象(ObjectInputStream)

多线程的概述、实现方式、线程控制、生命周期、多线程程序练习、安全问题的解决

多线程的概述

进程 正在运行的程序,是系统进行资源分配和调用的独立单位。 每一个进程都有它自己的内存空间和系统资源。 说起线程,它又分为单线程和多线程

线程 是进程中的单个顺序控制流,是一条执行路径 一个进程如果只有一条执行路径,则称为单线程程序 一个进程如果有多条执行路径,则称为多线程程序

多线程的实现

方式1:继承Thread类 步骤 A:自定义类MyThread继承Thread类。 B:MyThread类里面重写run() C:创建对象 D:启动线程

获取和设置线程名称 Thread类的基本获取和设置方法 public final String getName():获取线程的名称。 public final void setName(String name):设置线程的名称

多线程的实现(2) 方式2:实现Runnable接口 步骤: A:自定义类MyRunnable实现Runnable接口 B:重写run()方法 C:创建MyRunnable类的对象 D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

线程控制

public static void sleep(long millis):线程休眠 public final void join():线程加入 public static void yield():线程礼让 public final void setDaemon(boolean on):后台线程 public final void stop():中断线程 public void interrupt():中断线程

线程的生命周期图

新建、就绪、运行、死亡

多线程安全问题

把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。 解决线程安全问题实现(1) 同步代码块 格式: synchronized(对象){ 需要同步的代码; } 同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。 同步的特点 同步的前提 多个线程 多个线程使用的是同一个锁对象 同步的好处 同步的出现解决了多线程的安全问题。 同步的弊端 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。 我们 还有一种方法可以解决多线程的安全问题 同步方法:就是把同步的关键字加到方法上

Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

Lock锁的使用

Lock void lock():获取锁 void unlock():释放锁 ReentrantLock:是Lock的实现类

死锁问题

同步弊端 效率低 如果出现了同步嵌套,就容易产生死锁问题 死锁问题及其代码 是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象

多线程生产者和消费者问题

什么是生产者和消费者 简单来说就是生产一个,消费一个,具体点就是

生产者 先看是否有数据,有就等待;没有就生产,生产完成之后通知消费者来消费数据 消费者 先看是否有数据,有就消费;没有就等待,通知生产者生产数据 为了处理这样的问题,java提供了一种机制,等待唤醒机制。

线程池

线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。 JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法:

public static ExecutorService newCachedThreadPool():创建一个具有缓存功能的线程池。缓存:百度浏览过的信息再次访问 public static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用的,具有固定线程数的线程池 public static ExecutorService newSingleThreadExecutor():创建一个只有单线程的线程池,相当于上个方法的参数是1 下面我们就来实现一个线程的代码,我们先来分析一波实现的步骤

创建一个线程池对象,控制要创建几个线程对象。 public static ExecutorService newFixedThreadPool(int nThreads) 这种线程池的线程可以执行: 可以执行Runnable对象或者Callable对象代表的线程 做一个类实现Runnable接口。 调用如下方法即可 Future < ?> submit(Runnable task) < T> Future < T> submit(Callable task) 可以结束该线程 shutdown();

匿名内部类使用多线程

匿名内部类方式使用多线程 new Thread(){代码…}.start(); new Thread(new Runnable(){代码…}).start();

定时器

Timer定时 public Timer() public void schedule(TimerTask task, long delay) public void schedule(TimerTask task,long delay,long period) TimerTask:任务

面试题

我们来总结一下多线程这块常见的面试题

启动一个线程是run()还是start()?它们的区别?

启动一个线程是start(); run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用 start():启动线程,并由JVM自动调用run()方法

sleep()和wait()方法的区别?

sleep():必须指时间;不释放锁。 wait():可以不指定时间,也可以指定时间;释放锁。

为什么wait(),notify(),notifyAll()等方法都定义在Object类中?

因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。 而Object代码任意的对象,所以,定义在这里面。

面向对象思想设计原则、设计模式、简单工厂模式、工厂方法模式、单例设计模式之饿汉式和懒汉式、Runtime类

面向对象思想设计原则

单一职责原则 

其实就是开发人员经常说的”高内聚,低耦合” 开闭原则 核心思想是:一个对象对扩展开放,对修改关闭。其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。 里氏替换原则 核心思想:在任何父类出现的地方都可以用它的子类来替代。其实就是说:同一个继承体系中的对象应该有共同的行为特征。 依赖注入原则 核心思想:要依赖于抽象,不要依赖于具体实现。 接口分离原则 核心思想:不应该强迫程序依赖它们不需要使用的方法。 迪米特原则 核心思想:一个对象应当对其他对象尽可能少的了解

设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式不是一种方法和技术,而是一种思想 设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用 学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成

设计模式的几个要素:

名字 必须有一个简单,有意义的名字 问题 描述在何时使用模式 解决方案 描述设计的组成部分以及如何解决问题 效果 描述模式的效果以及优缺点 设计模式的分类 创建型模式 对象的创建 结构型模式 对象的组成(结构) 行为型模式 对象的行为 创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个) 结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个) 行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)

常见的设计模式 简单工厂模式和工厂方法模式(接口) 模版设计模式(抽象类) 装饰设计模式(IO流) 单例设计模式(多线程) 适配器模式(GUI)

简单工厂模式

简单工厂模式概述 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例 /*

  • 抽象的动物类,里面有抽象的方法 */ public abstract class Animal { public abstract void eat(); }

/*

  • 具体的动物猫继承抽象动物类,重写抽象方法 */ public class Cat extends Animal {

    @Override public void eat() { System.out.println("猫吃鱼"); } }

/*

  • 具体的动物狗继承抽象动物类,重写抽象方法 */ public class Dog extends Animal {

    @Override public void eat() { System.out.println("狗吃肉"); } }

/*

  • 动物工厂类,可以造猫和狗 */ public class AnimalFactory {

    private AnimalFactory() { } public static Animal createAnimal(String type) { if ("dog".equals(type)) { return new Dog(); } else if ("cat".equals(type)) { return new Cat(); } else { return null; } } }

/*

  • 测试类 */ public class AnimalDemo { public static void main(String[] args) {

    // 工厂有了后,通过工厂给造
    Animal a = AnimalFactory.createAnimal("dog");
    a.eat();
    a = AnimalFactory.createAnimal("cat");
    a.eat();
    
    // NullPointerException
    a = AnimalFactory.createAnimal("pig");
    if (a != null) {
        a.eat();
    } else {
        System.out.println("对不起,暂时不提供这种动物");
    }
    

    } } 现在我们运用了简单工厂模式后,就不用每次用的时候去new对象,而是直接去调用这个工厂类里面的具体方法,它会给我们返回一个已经new好的对象。那么这样做有什么有缺点呢,我们来总结一下。 优点 客户端不需要在负责对象的创建,从而明确了各个类的职责 缺点 这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护

工厂方法模式

工厂方法模式概述 工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。 /*

  • 抽象的动物类,里面有抽象的方法 */ public abstract class Animal { public abstract void eat(); }

/*

  • 工厂类接口,里面有抽象的创造动物的方法 */ public interface Factory { public abstract Animal createAnimal(); }

/*

  • 具体的猫类继承抽象动物类,重写抽象方法 */ public class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } }

/*

  • 猫工厂类实现工厂类并实现它的抽象方法,返回一个猫对象 */ public class CatFactory implements Factory {

    @Override public Animal createAnimal() { return new Cat(); } }

/*

  • 具体的狗类继承抽象动物类,重写抽象方法 */ public class Dog extends Animal {

    @Override public void eat() { System.out.println("狗吃肉"); } }

/*

  • 狗工厂类实现工厂类并实现它的抽象方法,返回一个狗对象 */ public class DogFactory implements Factory {

    @Override public Animal createAnimal() { return new Dog(); } }

/*

  • 测试类 */ public class AnimalDemo { public static void main(String[] args) { // 需求:我要买只狗 Factory f = new DogFactory(); Animal a = f.createAnimal(); a.eat();

     //需求:我要买只猫
     f = new CatFactory();
     a = f.createAnimal();
     a.eat();
    

    } } 运行程序,控制台会输出,狗吃肉 猫吃鱼

我们仔细观察用工厂方法模式比比简单工厂模式多了几个类,但是当我们在需要一种动物猪时,我们就不用去修改工厂类里面的代码了,只需用创建一个猪类继承抽象动物类,重写抽象方法,再创建一个猪的工厂类实现工厂类并实现它的抽象方法,就可以了。代码具有很强的维护性和扩展性,那么我们来分析一下工厂方法模式的优缺点 优点 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性 缺点 需要额外的编写代码,增加了工作量

单例设计模式

单例设计模式概述 单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供。 如何实现类在内存中只有一个对象呢?

构造私有 本身提供一个对象 通过公共的方法让外界访问

饿汉式 public class Student { // 构造私有 private Student() { }

// 自己造一个对象
// 静态方法只能访问静态成员变量,加静态
// 为了不让外界直接访问修改这个值,加private
private static Student s = new Student();

// 提供公共的访问方式
// 为了保证外界能够直接使用该方法,加静态
public static Student getStudent() {
    return s;
}

}

public class StudentDemo { public static void main(String[] args) {

    // 通过单例得到对象
    Student s1 = Student.getStudent();
    Student s2 = Student.getStudent();
    System.out.println(s1 == s2);   //true


}

}

懒汉式 public class Teacher { private Teacher() { }

private static Teacher t = null;

public static Teacher getTeacher() {    
    if (t == null) {
        t = new Teacher();//当我们去用这个对象的时候才去创建它
    }
    return t;
}

}

public class TeacherDemo { public static void main(String[] args) {

    Teacher t1 = Teacher.getTeacher();
    Teacher t2 = Teacher.getTeacher();
    System.out.println(t1 == t2); //true

}

}

饿汉式懒汉式比较

饿汉式我们经常在开发中使用,因为饿汉式是不会出问题的单例模式 懒汉式我们在面试中回答用,因为懒汉式可能会出问题的单例模式。 面试主要面两个思想,分别是:

懒加载思想(延迟加载) 线程安全问题(就要考虑下面3个方面) 是否多线程环境 b:是否有共享数据 c:是否有多条语句操作共享数据 如果都是,就会存在线程的安全问题,我们上面的懒汉式代码是不完整的,应该给对象中的方法加上synchronized关键字,这样才算完整

public synchronized static Teacher getTeacher() {
if (t == null) { t = new Teacher(); } return t; }

Runtime类

class Runtime { private Runtime() {} private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime() { return currentRuntime; } } 每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。 应用程序不能创建自己的 Runtime 类实例。

Runtime类使用

public Process exec(String command) 这个类是用来干什么的呢,它可以帮助我们运行DOS命令,比如打开记事本、计算器之类的电脑工具,当然也有更多的功能,我们来体验一下 r.exec("notepad"); r.exec("calc");//换成calc,会帮我们打开计算机 r.exec("shutdown -s -t 1000"); r.exec("shutdown -a");

模版设计模式

模版设计模式概述 模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现 优点 使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求 缺点 如果算法骨架有修改的话,则需要修改抽象类 我们可以在计算程序的运行时间中应用模版设计模式,在代码中我们只需用改变要计算的代码就可以了,把计算的时间设计成一个模版。

装饰设计模式 装饰设计模式概述 装饰模式就是使用被装饰类的一个子类的实例,在客户端将这个子类的实例交给装饰类。是继承的替代方案 优点 使用装饰模式,可以提供比继承更灵活的扩展对象的功能,它可以动态的添加对象的功能,并且可以随意的组合这些功能 缺点 正因为可以随意组合,所以就可能出现一些不合理的逻辑 在IO流中的装饰模式应用

BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(System.out)));

JAVA中的图形化界面、GUI概述、简单的窗体创建、事件监听机制、动作事件、GUI布局、鼠标事件

GUI概述

英文全称是Graphical User Interface(图形用户接口)。用图形的方式,来显示计算机操作的界面,这样更方便更直观。

其实系统跟用户有两种交互,一种是GUI,一种叫做CLI。

CLI的英文全称是Command line User Interface (命令行用户接口)就是常见的Dos命令行操作。CLI需要我们记忆一些常用的命令,操作不直观。

Java为GUI提供的对象都存在java.Awt和javax.Swing两个包中。我们来学习一下

java.awt:Abstract Window ToolKit (抽象窗口工具包),需要调用本地系统方法实现功能。属重量级控件。 javax.swing:在AWT的基础上,建立的一套图形界面系统,其中提供了更多的组件,而且完全由Java实现。增强了移植性,属轻量级控件。

简单的窗体创建

public class FrameDemo { public static void main(String[] args) { // 创建窗体对象 Frame f = new Frame(); // 设置窗体标题 f.setTitle("GUI"); // 设置窗体大小 f.setSize(400, 300); // 单位:像素 // 设置窗体位置 f.setLocation(400, 200); // 调用一个方法,设置让窗体可见 f.setVisible(true); } }

事件监听机制

事件源 事件 事件处理 事件监听器 addWindowListener

GUI布局

FlowLayout(流式布局管理器) 从左往右的顺序排列 Panel默认的布局管理器 BorderLayout(边界布局管理器) 东南西北中 Frame默认的布局管理器 GridLayout(网格布局管理器) 规则的矩阵 CardLayout(卡片布局管理器) 选项卡 GridBagLayout(网格包布局管理器) 非规矩的矩阵

鼠标事件

addMouseListener 动作事件 addActionListener

网络编程概述、IP地址、端口号、TCP和UDP协议、Socket、UDP传输、多线程UDP聊天

网络编程概述

就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。

网络模型 OSI参考模型 TCP/IP参考模型

OSI参考模型 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层

TCP/IP参考模型 应用层 传输层 网络层 主机至网络层

网络通信三要素

IP地址:InetAddress 网络中设备的标识,不易记忆,可用主机名 端口号 用于标识进程的逻辑地址,不同进程的标识 传输协议 通讯的规则 常见协议:TCP,UDP

IP地址 说起IP地址,我们每个人都知道自己的电脑有个IP地址,它在计算机中有什么作用呢?我们就来看一下它的具体概念

要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,也就是网络中计算机的唯一标识,通过这个标识号来指定要接受数据的计算机和识别发送的计算机,在TCP/IP协议中,这个标识号就是IP地址。 java提供了一个类InetAddress 供我们使用对IP地址的获取和操作 InetAddress.getLocalHost();

端口号

每个网络程序都会至少有一个逻辑端口 用于标识进程的逻辑地址,不同进程的标识 有效端口:065535,其中01024系统使用或保留端口。

TCP和UDP协议

TCP 建立连接,形成传输数据的通道 在连接中进行大数据量传输 通过三次握手完成连接,是可靠协议 必须建立连接,效率会稍低 UDP 将数据源和目的封装成数据包中,不需要建立连接 每个数据包的大小在限制在64k 因无连接,是不可靠协议 不需要建立连接,速度快

Socket

Socket套接字: 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。 Socket原理机制: 通信的两端都有Socket。 网络通信其实就是Socket间的通信。 数据在两个Socket间通过IO传输。

UDP传输

DatagramSocket与DatagramPacket 建立发送端,接收端。 建立数据包。 调用Socket的发送接收方法。 关闭Socket。

UDP传输-发送端 /*

  • 需求:接收指定端口发送过来的数据

  • UDP协议发送数据:

  • A:创建发送端Socket对象

  • B:创建数据,并把数据打包

  • C:调用Socket对象的发送方法发送数据包

  • D:释放资源 */ public class SendDemo { public static void main(String[] args) throws IOException { // 创建发送端Socket对象 // DatagramSocket() DatagramSocket ds = new DatagramSocket();

     // 创建数据,并把数据打包
     // DatagramPacket(byte[] buf, int length, InetAddress address, int port)
     // 创建数据
     byte[] bys = "UDP过来了".getBytes();
     // 长度
     int length = bys.length;
     // IP地址对象
     InetAddress address = InetAddress.getByName("192.168.2.102");
     // 端口
     int port = 12345;
     DatagramPacket dp = new DatagramPacket(bys, length, address, port);
    
     // 调用Socket对象的发送方法发送数据包
     // public void send(DatagramPacket p)
     ds.send(dp);
    
     // 释放资源
     ds.close();
    

    } }

UDP传输-接收端 /*

  • UDP协议接收数据:

  • A:创建接收端Socket对象

  • B:创建一个数据包(接收容器)

  • C:调用Socket对象的接收方法接收数据

  • D:解析数据包,并显示在控制台

  • E:释放资源 */ public class ReceiveDemo { public static void main(String[] args) throws IOException { // 创建接收端Socket对象 // DatagramSocket(int port) DatagramSocket ds = new DatagramSocket(12345);

     // 创建一个数据包(接收容器)
     // DatagramPacket(byte[] buf, int length)
     byte[] bys = new byte[1024];
     int length = bys.length;
     DatagramPacket dp = new DatagramPacket(bys, length);
    
     // 调用Socket对象的接收方法接收数据
     // public void receive(DatagramPacket p)
     ds.receive(dp); // 阻塞式
    
     // 解析数据包,并显示在控制台
     // 获取对方的ip
     // public InetAddress getAddress()
     InetAddress address = dp.getAddress();
     String ip = address.getHostAddress();
     // public byte[] getData():获取数据缓冲区
     // public int getLength():获取数据的实际长度
     byte[] bys2 = dp.getData();
     int len = dp.getLength();
     String s = new String(bys2, 0, len);
     System.out.println(ip + "传递的数据是:" + s);
    
     // 释放资源
     ds.close();
    

    } }

多线程UDP聊天

/*

  • 通过多线程实现聊天程序,我们就要开启两个线程,一个接收数据,一个发送数据,这样我就可以实现在一个窗口发送和接收数据了 */ public class ChatRoom { public static void main(String[] args) throws IOException { DatagramSocket dsSend = new DatagramSocket(); DatagramSocket dsReceive = new DatagramSocket(12345);

     SendThread st = new SendThread(dsSend);
     ReceiveThread rt = new ReceiveThread(dsReceive);
    
     Thread t1 = new Thread(st);
     Thread t2 = new Thread(rt);
    
     t1.start();
     t2.start();
    

    } }

/*

  • 接收数据 */ public class ReceiveThread implements Runnable { private DatagramSocket ds;

    public ReceiveThread(DatagramSocket ds) { this.ds = ds; }

    @Override public void run() { try { while (true) { // 创建一个包裹 byte[] bys = new byte[1024]; DatagramPacket dp = new DatagramPacket(bys, bys.length);

             // 接收数据
             ds.receive(dp);
    
             // 解析数据
             String ip = dp.getAddress().getHostAddress();
             String s = new String(dp.getData(), 0, dp.getLength());
             System.out.println("from " + ip + " data is : " + s);
         }
     } catch (IOException e) {
         e.printStackTrace();
     }
    

    } }

/*

  • 发送数据 */ public class SendThread implements Runnable {

    private DatagramSocket ds;

    public SendThread(DatagramSocket ds) { this.ds = ds; }

    @Override public void run() { try { // 封装键盘录入数据 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = null; while ((line = br.readLine()) != null) { if ("886".equals(line)) { break; }

             // 创建数据并打包
             byte[] bys = line.getBytes();
             DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.2.102"), 12345);
    
             // 发送数据
             ds.send(dp);
         }
         // 释放资源
         ds.close();
     } catch (IOException e) {
         e.printStackTrace();
     }
    

    } }

TCP传输、上传文件、上传图片、多并发上传

TCP传输

Socket和ServerSocket 建立客户端和服务器端 建立连接后,通过Socket中的IO流进行数据的传输 关闭socket

TCP传输-客户端 /*

  • TCP协议发送数据:

  • A:创建发送端的Socket对象

  •  这一步如果成功,就说明连接已经建立成功了。
    
  • B:获取输出流,写数据

  • C:释放资源 */ public class ClientDemo { public static void main(String[] args) throws IOException { // 创建发送端的Socket对象 Socket s = new Socket("192.168.2.102", 8888);

     // 获取输出流,写数据
     OutputStream os = s.getOutputStream();
     os.write("TCP来了".getBytes());
    
     // 释放资源
     s.close();
    

    } }

TCP传输-服务器 /*

  • TCP协议接收数据:

  • A:创建接收端的Socket对象

  • B:监听客户端连接。返回一个对应的Socket对象

  • C:获取输入流,读取数据显示在控制台

  • D:释放资源 */ public class ServerDemo { public static void main(String[] args) throws IOException { // 创建接收端的Socket对象 ServerSocket ss = new ServerSocket(8888);

     // 监听客户端连接。返回一个对应的Socket对象
     Socket s = ss.accept(); // 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
    
     // 获取输入流,读取数据显示在控制台
     InputStream is = s.getInputStream();
    
     byte[] bys = new byte[1024];
     int len = is.read(bys); // 阻塞式方法
     String str = new String(bys, 0, len);
    
     String ip = s.getInetAddress().getHostAddress();
    
     System.out.println(ip + "---" + str);
    
     // 释放资源
     s.close();
     // ss.close(); //服务器一般不应该关闭
    

    } }

这样我们九建立了TCP协议传输数据的客户端和服务器,运行程序,服务器会收到客户端发来的数据,但是这样的代码,当服务器端收到客户端的数据时,客户端并不知道,所以,我们就要给客户端一个反馈了。

/*

  • 服务器端 */ public class ServerDemo { public static void main(String[] args) throws IOException { // 创建服务器Socket对象 ServerSocket ss = new ServerSocket(11111);

     // 监听客户端的连接
     Socket s = ss.accept(); // 阻塞
    
     // 获取输入流
     InputStream is = s.getInputStream();
     byte[] bys = new byte[1024];
     int len = is.read(bys); // 阻塞
     String server = new String(bys, 0, len);
     System.out.println("server:" + server);
    
     // 获取输出流
     OutputStream os = s.getOutputStream();
     os.write("数据已经收到".getBytes());
    
     // 释放资源
     s.close();
     // ss.close();
    

    } }

/*

  • 客户端 */ public class ClientDemo { public static void main(String[] args) throws IOException { // 创建客户端Socket对象 Socket s = new Socket("192.168.2.102",11111);

     // 获取输出流
     OutputStream os = s.getOutputStream();
     os.write("国庆节快乐!".getBytes());
    
     // 获取输入流
     InputStream is = s.getInputStream();
     byte[] bys = new byte[1024];
     int len = is.read(bys);// 阻塞
     String client = new String(bys, 0, len);
     System.out.println("client:" + client);
    
     // 释放资源
     s.close();
    

    } }

上传文件

/*

  • 上传文件客户端 */ public class UploadClient { public static void main(String[] args) throws IOException { // 创建客户端Socket对象 Socket s = new Socket("192.168.2.102", 12345);

     // 封装文本文件
     BufferedReader br = new BufferedReader(new FileReader("a.txt"));
     // 封装通道内流
     BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
             s.getOutputStream()));
    
     String line = null;
     while ((line = br.readLine()) != null) { // 阻塞
         bw.write(line);
         bw.newLine();
         bw.flush();
     }
    
     //Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
     s.shutdownOutput();
    
     // 接收反馈
     BufferedReader brClient = new BufferedReader(new InputStreamReader(
             s.getInputStream()));
     String client = brClient.readLine(); // 阻塞
     System.out.println(client);
    
     // 释放资源
     br.close();
     s.close();
    

    } }

/*

  • 上传文件接收端(服务器) */ public class UploadServer { public static void main(String[] args) throws IOException { // 创建服务器端的Socket对象 ServerSocket ss = new ServerSocket(12345);

     // 监听客户端连接
     Socket s = ss.accept();// 阻塞
    
     // 封装通道内的流
     BufferedReader br = new BufferedReader(new InputStreamReader(
             s.getInputStream()));
     // 封装文本文件
     BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
    
     String line = null;
     while ((line = br.readLine()) != null) { // 阻塞
         bw.write(line);
         bw.newLine();
         bw.flush();
     }
    
     // 给出反馈
     BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(
             s.getOutputStream()));
     bwServer.write("文件上传成功");
     bwServer.newLine();
     bwServer.flush();
    
     // 释放资源
     bw.close();
     s.close();
    

    } }

上传图片

上传图片我们就要考虑不能用字符流了,要用字节流。

/*

  • 上传图片客户端 */ public class UploadClient { public static void main(String[] args) throws IOException { // 创建客户端Socket对象 Socket s = new Socket("192.168.2.102", 96320);

     // 封装图片文件
     BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg"));
     // 封装通道内的流
     BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
    
     byte[] bys = new byte[1024];
     int len = 0;
     while ((len = bis.read(bys)) != -1) {
         bos.write(bys, 0, len);
         bos.flush();
     }
    
     s.shutdownOutput();
    
     // 读取反馈
     InputStream is = s.getInputStream();
     byte[] bys2 = new byte[1024];
     int len2 = is.read(bys2);
     String client = new String(bys2, 0, len2);
     System.out.println(client);
    
     // 释放资源
     bis.close();
     s.close();
    

    } }

/*

  • 上传图片接收端-服务器 */ public class UploadServer { public static void main(String[] args) throws IOException { // 创建服务器Socket对象 ServerSocket ss = new ServerSocket(96320);

     // 监听客户端连接
     Socket s = ss.accept();
    
     // 封装通道内流
     BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
     // 封装图片文件
     BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg"));
    
     byte[] bys = new byte[1024];
     int len = 0;
     while ((len = bis.read(bys)) != -1) {
         bos.write(bys, 0, len);
         bos.flush();
     }
    
     // 给一个反馈
     OutputStream os = s.getOutputStream();
     os.write("图片上传成功".getBytes());
    
     bos.close();
     s.close();
    

    } }

多并发上传

让多个客户端同时连接到服务器上传代码,我们就要运用多线程技术,把每个客户端和服务器之间的连接封装到一个线程中去,这样就可以同时处理多个客户端请求 /*

  • 服务器端 */ public class UploadServer { public static void main(String[] args) throws IOException { // 创建服务器Socket对象 ServerSocket ss = new ServerSocket(11111);

     while (true) {
         Socket s = ss.accept();
         new Thread(new UserThread(s)).start();
     }
    

    } }

/*

  • 并发的线程 */ public class UserThread implements Runnable { private Socket s;

    public UserThread(Socket s) { this.s = s; }

    @Override public void run() { try { // 封装通道内的流 BufferedReader br = new BufferedReader(new InputStreamReader( s.getInputStream()));

         // 为了防止名称冲突,每次命名为随机的
         String newName = System.currentTimeMillis() + ".java";
         BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
    
         String line = null;
         while ((line = br.readLine()) != null) { // 阻塞
             bw.write(line);
             bw.newLine();
             bw.flush();
         }
    
         // 给出反馈
         BufferedWriter bwServer = new BufferedWriter(
                 new OutputStreamWriter(s.getOutputStream()));
         bwServer.write("文件上传成功");
         bwServer.newLine();
         bwServer.flush();
    
         // 释放资源
         bw.close();
         s.close();
     } catch (IOException e) {
         e.printStackTrace();
     }
    

    }

}

XMind - Trial Version