Java入门环境搭建
什么是程序
像一个汉字(设计语言)写的红烧肉菜谱(程序),用于指导懂汉字的人来做菜
Win10常用dos操作命令
- md(make directory): 创建目录
- rd(remove directory): 删除目录
- cd空格(change directory): 进入指定目录
- cd… : 退回到上一级目录
- cd \ : 退回到根目录
- exit : 退出dos 命令行
- Shift+右键->在此处打开命令行窗口**
java的发展历史
- 1991年,高司令green Oak(橡树)跨平台
- 1995年,推出了java测试版
- 1996年.Jdk1.0
- 1997年jdk 1.1
- 1998年jdk1.2,被大量的人所使用
- 2004年,jdk1.5
- 2006年,jdk1.6
- 2011年,jdk1.7
- 2014年jdk1.8企业用的比较多
- 2018年3月java 10
- 2018年9月java11
- 2019年3月java12
- 2019年9月java13
- 2020年3月java14
java分支
- JavaMe:已经被淘汰,主要去做移动端
- JavaSe:java基础,JavaEE的基石,控制台项目,桌面应用程序
- JavaEE:企业级应用项目
java语言的特点:
- 简单易用
- 跨平台性 引入了虚拟机(JVM)的概念,通过JVM可以实现在不同操作系统上运行java程序,每个操作系统都有自己的虚拟机
- 面向对象性
- 支持多线程
java两大核心机制
- java虚拟机
- JVM是一个虚拟的计算机,具有指令集并使用不同的存储区 域。负责执行指令、管理数据、内存、寄存器
- JVM用于运行java应用程序
- 对于不同的操作系统,有不同的虚拟机
- java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行” - 垃圾回收机制
- java不需要程序员负责回收无用的内存
JDK
- JDK:java开发工具包,就相当于一个电工的工具包
- JRE:java运行环境,开发好的java程序需要通过JRE去运行,包含java程序的API(核心类库)
java编写规则
- 类名必须与文件名一致
- 一个Java文件中可以定义多个类,但是只能有一个public类
- JAVA语言严格区分大小写
- 大括号是成对出现的,缺一不可
- main方法是java程序的入口,需要执行的代码必须放到main方法里面
- 每个语句以分号结束
注释:单行注释(//) 多行注释(/***/)
java基础语法
关键字
java语言定义的特殊的单词,每个关键字都有自己独有的功能,全是小写
标识符
自己定义的类、方法名、包名、变量名、接口名、、、这些都是标识符
注意事项:
- 必须由字母、数字、$组成
- 不能以数字开头,不能是关键字,中间不能有空格
- 不能包含特殊字符
- 定义方法名和变量名首字母小写,如果定义常量,全部大写
变量
定义:在内容中的一块区域,变量的值可以在某一个范围内发生改变
变量的类型:
- 按被声明的位置:
- 成员变量:方法外部、类内部
- 局部变量:方法内部 - 按所属的数据类型:
- 基本数据类型
- 引用数据类型
基本数据类型
八种基本数据类型:byte、short、int、long、float、double、boolean、char
类型转换
- 自动类型转换,把小的放到大的里面
- 强制类型转换,把大的放到小的里面
- 把字符串类型转换成其他类型
每个基本数据类型都有自己对应的包装类,每个包装类中都封装了对应的转换方法,转成什么类型就去到其对应的类里面的方法
运算符
逻辑运算符、算术运算符、位运算符、比较运算符、条件运算符、赋值运算符
顺序结构及条件结构
顺序结构
按照代码的书写顺序,从上往下依次执行
键盘输入数据:
- 导入java.util.Scanner包
- 创建对象
- 接受数据
分支语句
分类:if语句和switch语句
if语句分类
if语句:满足if里面的条件表达式就执行代码块里的代码
if…else语句:如果满足if里面的条件表达式就执行if代码块里的代码,否则执行else里面的代码
if…else,if…else语句:多重判断,先对if语句里的条件表达式进行判断,如果不满足,之后对下面的条件表达式进行判断,直到能够满足条件的,然后去执行其代码里的代码,这一组语句,只能有一个语句执行
switch语句
- case后面都是常量
- break:可以选、如果case里面没有break,会继续执行下一个case,直到遇到break停止
- case 后面的常量是可选的
- default 可选,如果添加,没有条件表达式中对应的case,则执行default
switch和if的区别
- if会一步一步执行表达式的判断,switch根据表达式直接去找对应的case,因为case后面的常量不能进行判断,效率高
- if:常用于区间判断;switch:常用于等值判断
while和都do…while
循环:通过循环语句返回执行同一个操作
while和do…while的区别:
- while:先判断在执行
- do…while:先执行一遍循环体里的内容再进行判断
循环由循环条件和循环操作组成
for循环
三个表达式:初始化表达式,循环条件表达式,累加器
for循环的优点:是代码更容易阅读,循环次数固定的条件
break:一旦执行,立即结束当前循环,只能用于switch语句和循环语句中
continue:跳过此次循环,继续执行下一次循环,只能用于循环语句中
数组
数组是一个容器,它可以存放多个值;数组和变量差不多,都是存放数据的,不同的变量只能保存一条数据,而数组可以保存多条数组,前提这个多条数据必须是同一类型的,数组是引用数据类型
如何定义一个数组
数组类型【】 数组名;
如果定义好数组之后,必须给数组进行初始化
数组是一个引用数据类型
数组的初始化
动态初始化
- 数组类型【】 数组名 = new 数组类型【数组长度】
- 数据类型【】 数组名;
数组名 = new 数组类型【数组长度】;
静态初始化
不是指定数组长度,在定义数组的同时对数组进行赋值
- 数组类型 【】 数组名 = new 数组类型【】{数据1,数据2…};
- 数组类型 【】 数组名;
数组名 = new 数组类型【】{数据1,数据2…};
简洁的方式:数组类型【】 数组名 = {数据1,数据2…}
数组中常见的几种异常:
- 数组越界异常(ArrayIndexOutOfBoundsException)
- 空指针异常(NullPointerException)
数组的分类
- 基本数据类型的数组
动态初始化数组以后,数组的元素都会赋予一个默认值
short byte int long double float char boolean char的默认值是空格 Boolean默认值是false - 引用数据类型的数组
java中的内存是怎么分配的
内存的申请和释放都是jvm进行管理的,java程序要运行,jvm会自动的像电脑申请一块内存
把这块内存分为5部分:
- 栈:主要存放局部变量
- 堆(Heap):凡是new出来的东西都放在堆里面,堆中的数据都有默认原则
整数0 小数0.0 布尔false char空格 应用数据类型null - 方法区(Method Area):存放的是与 class相关的信息
- 本地方法区(Native Method Area):与操作系统有关
- 寄存器(Register):与CPU有关
冒泡排序
二维数组
数组中的数组
声明二维数组
1.声明二维数组
数组类型【】【】 数组名;
第一个中括号:二维数组中有几个一维数组 行
第二个中括号:每一个二维数组中有多少元素 列
2.初始化二维数组
- 动态初始化
- 静态初始化
方法
把一些相关的语句组织在一起,用于解决特定功能的代码块
好处:提高代码的重用性,维护性,可读性号,执行效率高
含义
- 访问修饰符(权限修饰符)
public 公共的,在当前项目下的任何地方都可以访问都可以调用
private 私有的,只能在当前类下访问
protected 受保护的,在同一个包或者其他派生类(子类和父类)中可以访问
default: 缺省,只能在当前包下进行访问 - 方法的返回值类型:
方法执行完成以后,最终产生的结果是什么类型的
方法名:自己定义的名字,首字母小写,驼峰式命名法
形参列表:由多个形参组成的列表
形参:用于接收调用者实际传过来的数据 - return:
(1)把方法最终处理的结果返回给调用者
(2)结束当前方法
注意:返回数据类型必须要返回值类型一致
方法重载
方法名必须相同,参数列表不同
1.参数列表的个数不同
2.和参数名没有任何关系
3.和返回值类型无关
4.参数类型不同
5.参数类型的顺序
类和对象
面向过程
c语言 看中的是过程的开发
在开发一个程序的时候,看中的是中间的过程,每一个过程步 骤都要自己去做
面向对象
java c# js.... 看中的是类的设计
当开发一个程序的时候,不看重具体的过程,看中的是谁能帮我去完成这件事,找对象帮我去做
前期去设计类的时候比较复杂,但是后期的复用性和扩展性比较好
面向过程和面向对象的优缺点
- 面向过程:面向过程的性能比面向对象的性能高,因为面向对象在实例化时,开销比较大
缺点:维护性和扩展性没有面向对象好 - 面向对象:维护性和扩展性好
缺点:性能低,开销大
成员变量和局部变量的区别:
- 定义的位置不同
- 作用域不同:
成员变量作用于类的内部
局部变量作用在方法之内 - 默认值不同
成员变量默认值
局部变量没有默认值 - 内存中的位置不同
成员变量保存在堆里面
局部变量保存在栈里面 - 成员变量有四种访问修饰符:private public protected 缺省
- 局部变量没有访问修饰符,默认与方法的修饰符相同
封装
为何要封装
当我创建完对象之后,我如果直接通过“对象名、属性名“的方式给属性固执的话,可能会出现一些不符合实际情况的问题,
所以我们不考虑使用“对象名、属性名“的方式赋值,而是通过“对象名、方法名()”的方式进行赋值,因为我可以在方法里面
加上大量的限制,对属性值进行限制
方法:
- 将属性私有化
- 提供公用的(get和set)方法实现属性的取值和赋值
new的其实就是一个构造方法
构造方法
在我们去创建对象的时候,会用到一个特殊的方法叫做构造方法,构造器
无参构造方法:
public 构造方法名(){
}
注意:
1.构造方法没有返回值
2.构造方法名必须和你当前类的名字一致,包括大小写
作用:
1.创建对象,new的时候就是调用了构造方法
2.创建对象的同时可以调用有参构造方法对属性赋值
注意:如果没有显式的构造方法,系统会默认提供一个无参的构造方法
如果显式的定义了一个构造方法,系统不会再提供无参的构造方法,需要我们手动的创建一个无参的构造方法
this关键字
1.this代表当前使用的对象或者是正在创建的对象,通过那个对象调用了方法那个对象就是this
2.this可以修饰构造方法,方法,成员变量 直接在成员变量名或者成员方法名前面加成this
3.可以在构造方法中通过“this(形参)”的方法调用有参构造方法
继承
继承是多态的前提,没有继承就没有多态继承:共性抽取
优缺点:
提高了代码分复用性
由于继承会有多层的继承关系,会提高他们之间的依赖关系,耦合度提高
作用:
- 使用继承以后父类所有的属性和方法子类都可以获取到,除了私有的除外
- 子类除了通过继承获取父类的属性和方法外,还可以单独定义自己独有的属性和方法
- 一个子类可以派生别的子类
- .一个父类可以有多个子类,一个子类不可以有多个父类
- 方法重写,如果父类的方法满足不了子类要求时,子类可以对父类的方法进行重写
重写规则:
- 要求子类的重写的方法名,参数列表,返回值类型必须和父类一致
- 子类重写方法的访问修饰符权限不能低于父类方法修饰符权限
- 子类方法和父类方法必须同为static或非static
重载(overload)和重写(override)的区别:
- 方法重载必须在同一个类中,方法重写必须存在继承关系
- 方法重载要求方法名相同,参数列表必须不相同,和返回值无关
- 方法重写要求方法名参数列表返回值必须和父类一致
super关键字可以修饰属性、方法、构造方法
- 当子类和父类的属性出现重名时,默认会调用子类的属性,可以通过“super.属性名”的方式显式的调用父类声明的属性
- 如果子类重写父类中的方法,想重新调用父类中的此方法,可以通过“super.方法”的方式显式的调用父类声明的方法
- super可以修改构造方法,通过子类构造方法中使用“super(形参)”来显示的调用父类对应的构造方法
注意
-
super必须生命在首行
-
说明this和super只能出现一个
-
在构造方法中,不显示的通过super的方式调用父类中的构造方法
默认会调用父类无参的无参构造方法如果一个类没有显式的继承谁,默认继承object
访问修饰符:修饰类、变量、方法、接口
public:公共的,在当前项目下的任何地方都可以访问到
protected:受保护的,在同一个包下或者在其他子类中可以访问
default:缺省 在同一个包下
private:私有,在当前类下访问
多态
多态:前提必须有继承或者接口的实现
多态性
1.同一个动作与不同的对象产生不同的行为
2.多态值得是一个对象的多种形态
多态的体现方式
使用继承:不同的子类重写父类方法后,体现出来的形式不一样
接口的实现
形成多态的必要条件
- 继承:存在子类和父类的关系
- 接口实现:定义一个类实现对应的接口
- 重写:子类重写了父类的方法
- 重载:调用相同的方法名,实现的功能不同
- 子类对象的多态性:父类的应用指向子类的实例
程序分为两种状态,一个是编译状态,一个是运行状态
对于多态来说:
- 编译时看左边,你这对象定义的是什么类型就是什么类型,将Pet对象看做是Pet类型,
- 运行时看右边,真正执行的对象,也就是子类对象(Dog),执行的也是子类重写后的方法
上转型和下转型
- 上转型:将子类对象交给父类引用,可以自动转型
- 下转型:将父类转成子类,强制类型转换
instanceof运算符:在强制类型转换之前可以判断对象的真实实例类型
if(pet instanceof dog){
dog dog= (Dog) pet;
dog2.sleep();
}else if(pet instanceof penguin){
penguin pe = (Penguin) pet;
pe.swimming();
}
final关键字:代表最终的意思
可以修饰什么?
- 修饰类 最终类,没有子类了,不能别继承,他就是一个太监类,可以继承别的类
- 修饰方法 代表这个方法是一个最终方法,不能被重写
- 修饰成员变量 成员变量的值不可改变 1.成员变量不会再有默认值 2.如果使用final关键字,必须直接给成员变量赋值
- 修饰局部变量 局部变量的值不能被修改,一般修饰一个常量
static关键字:静态的
static修饰成员变量(类本身)
-
修饰成员变量,这个变量就不属于对象了,而属于类本身,我们就可以通过“类名.属性名”的方式访问
-
只要通过我这个类创建的对象,这些对象都可以共享这个属性
-
当其中一个对象对类变量进行更改以后,其他对象的这个类变量也会更改
VS实例变量(非static的变量,属于对象本身,各个对象都有各自的一套副本) -
类变量是随着类的加载而加载,类变量的生命周期大于实例变量
-
类变量放在方法区的静态域里面
static修饰方法(类方法)
- 修饰方法,这个方法就属于类本身了,可以通过“类名.方法名()”的方式调用
- 随着类而加载
- 在静态方法里面只能调用静态变量和静态方法,相反普通普方法里面可以调用静态变量和静态方法,以为静态变量和静态方法加载时机早于
实例变量和实例方法的加载时机 - 在静态方法里面不能使用this和super(因静态方法属于类本身,而this和super属于本对象)
static修饰代码块
代码块的作用完成初始化
- 非静态代码块
可以给类的属性进行初始化操作,同时还可以调用类的方法(静态或非静态都可以)
里面可以有输出语句
每创建一个对象,非静态代码块就执行一次 - 静态代码块
里面可以有输出语句
随着类加载而加载,只会执行一次
静态代码块的加载时机早于非静态代码块
静态代码块里面只能调用类变量和类方法
对属性赋值:
(1)默认初始化
(2)显式的初始化
(3)通过set方法或者构造方法
(4)代码块初始化
接口和抽象类
抽象类
1.什么是抽象类?
如果一个类表达的是一种抽象的概念,仅仅作为其他派生类的一个父类,主要有动能的定义,具体的实现交给他的子类来做
2.语法: 在class前面加上一个abstract就是一个抽象类
3.特点:
(1)抽象方法所在的类必须是抽象类
(2)抽象类不能进行实例化
(3)如果要实现一个抽象类,创建一个子类去继承这个抽象类
(4)子类继承抽象类以后,必须重写抽象类里面所有的抽象方法(前提子类不是抽象类)
(5)抽象类中可以创建普通方法
(6)抽象类可以定义构造方法
抽象方法:
在返回值前面加上abstract就是一个抽象方法
特点:
只能方法的定义,没有方法体
接口
什么是接口?
(1)九十多个类之间的公共规范
(2)接口是一个特殊的抽象类型,接口里面的方法就是抽象方法
(3)解决了java单继承的鸡肋
接口的特点:
(1)接口里面的属性都是常量
(2)接口里面的方法都是抽象方法
(3)接口不能够实例化
(4)抽象类是继承,接口是用来实现的
(5)一个类实现一个接口,必须实现这个接口里面的所有的抽象方法(前提这个类不是一个抽象类)
(6)一个类可以试想多个接口,中间用逗号隔开
(7)接口不能定义普通方法
(8)接口没有构造方法
(9)接口也可以继承接口,并且可以继承多个接口
实现类
(1)实现接口的类叫做实现类 class A implements B
(2)如果一个类继承了一个父类同时需要实现一个接口,继承重写方法一定要在接口的前面
抽象类和接口的不同点:
- 抽象类和接口定义不同:抽象类abstract,接口interface
- 接口里只能包含抽象方法,不包含已经实现的方法,抽象类则完全可以包含普通的方法
- 接口里不能定义静态方法:抽象类可以定义静态方法
- 接口里只能定义静态常量属性,不能定义普通属性;抽象类立即可以定义普通属性,也可以定义静态常量
- 接口不包含构造方法;抽象类可以包含构造函数,抽象类里的构造函数并不是用于创建对象,而是让其子类调用这些构造函数来完成
属于抽象类的初始化操作 - 接口不包含初始化块,带抽象类可以包含初始化块
- 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补java单继承的不足
java常用类
Object类
是类层次结构的根,java中所有的类都继承自这个类
特征:
- 是java中唯一没有父类的类
- 其他所有的类都继承了Object类中的方法,所以其方法的重要性不言而喻
操作符与equals比较
等号 操作符:
- 引用类型比较引用(是否指向同一个对象)
- 基本类型比较值
- 用等号进行比较是,符号两边的数据类型必须一致(可自动转换的基本数据类型除外),否则编译出错
equals方法:
- 是Object类的方法,由于所有类都继承Object类,也就继承了equals()方法
- 只能比较引用类型
- 在Object类的定义中,其作用于“==”相同,比较是否指向同一个对象。
- 注意:对类File、string、Date、封装类及很多重写equals()方法的类来说,是比较类型及内容而不考虑引用是否指向同一个对象
StringBuffer:
就是字符串缓冲区,用于存储可变字符序列的容器。
特点:可以对字符串进行修改,长度可变。
常用方法:
- 构造:
StringBuffer()
StringBuffer(int size)
StringBuffer(String str) - 添加:
StringBuffer append(data);
StringBuffer insert(index,data); - 删除:
StringBuffer delete(start,end):包含头,不包含尾。
StringBuffer deleteCharAt(int index):删除指定位置的元素 - 查找:
char charAt(index);
int indexOf(string);
int lastIndexOf(string); - 修改:
StringBuffer replace(start,end,string);
void setCharAt(index,char);
StringBuffer:可变字符序列、线程安全、效率低
StringBuilder:可变字符序列、线程不安全、效率高
Date&DateFormat类
- Date类在java.util包中。使用Date类的无参构造方法创建的对象可以获取本地当前时间。
- SimpleDateFormat可用来实现日期的格式化。
- public SimpleDateFormat(String pattern):使用参数pattern指定的格式创建一个对象。
- public String format(Date date):按照构造方法中指定的pattern格式化时间对象date。
日期类
-
java.util.Calendar(日历)类
- Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
-
获取Calendar实例的方法
- 使用Calendar.getInstance()方法
- 调用它的子类GregorianCalendar的构造器。
-
一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、MINUTE、SECOND
- public void set(int field,int value)
- public void add(int field,int amount)
- public final Date getTime()
- public final void setTime(Date date)
Java集合框架
java集合概述
- 前面存储对象,数组,弊端
- Java 集合就像一种容器,可以把多个对象的引用放入容器中。
- Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组
- Java 集合可分为 Set、List 和 Map 三种体系
- Set:无序、不可重复的集合,set又是以map为底层实现
- List:有序,可重复的集合,list接口是以数组为底层实现,是有序的
- Map:具有映射关系的集合,key-value(键值对),map接口底层是hash函数,无续(不是随机)
- 在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 Java5 增加了泛型以后,Java 集合可以记住容器中对象的数据类型
使用Iterator接口遍历集合元素
- Iterator 接口主要用于遍历 Collection 集合中的元素,Iterator 对象也被称为迭代器。
- Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection 集合元素的统一编程接口。
- Iterator 仅用于遍历集合,Iterator 本身并不提供存放对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
List
- List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
- List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。
- List 默认按元素的添加顺序设置元素的索引。
Set集合
- Set接口存储一组唯一,无序的对象。
- HashSet 是Set接口常用的实现类。
- HashSet允许集合元素值为null
- 操作数据的方法与List类似,Set接口不存在get()方法。
- Iterator接口表示对集合进行迭代的迭代器,专门实现集合的遍历。
- 方法:
- hasNext():判断是否存在另一个可访问的元素
- next():返回要访问的下一个元素
Map
- HashMap是Map接口中最常见的实现类。
- 存储一组成对的键-值对象,提供key(键)到value(值)的映射,通过key来索引
- key不允许重复
- value允许重复
- 添加的对象将转换为Object类型
HashMap&Hashtable
- HashMap 和 Hashtable 都是 Map 接口的实现类
- 区别:
- Hashtable 是一个古老的 Map 实现类,不建议使用
- Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。
- Hashtable 不允许使用 null 作为 key 和 value,而 HashMap 可以
- 与 HashSet 集合不能保证元素的顺序的顺序一样,Hashtable 、HashMap 也不能保证其中 key-value 对的顺序
- Hashtable 、HashMap 判断两个 Key 相等的标准是:两个 Key 的hashCode 值相等,并且equals 方法返回 true。
- Hashtable 、HashMap 判断两个 Value相等的标准是:两个 Value 通过 equals 方法返回 true
TreeMap
- TreeMap 存储 Key-Value 对时,需要根据 Key 对 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。
- TreeMap 的 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 处元素进行交换
- 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 对象的所有旧值
泛型
- 泛型的声明
interface List 和 class Test<K,V>
其中,T,K,V不代表值,而是表示类型。这里使
用任意字母都可以。常用T表示,是Type的缩写。 - 泛型的实例化:
一定要在类名后面指定类型参数的值(类型)。如:
List strList = new ArrayList();
Iterator iterator = customers.iterator();- T只能是类,不能用基本数据类型填充。
泛型的几个重要使用:
- 在集合中使用泛型
- 自定义泛型类
- 泛型方法
- 泛型接口
Java异常
Java程序运行过程中所发生的异常事件可分为两类:
- Error: JVM系统内部错误、资源耗尽等严重情况//无法控制,不处理
- Exception: 其它因编程错误或偶然的外在因素导致的一般性问题。比如:空指针访问、试图读取不存在的文件等。
Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。
Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。
Exception(异常):是程序本身可以处理的异常
异常分类
- Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。
- 可查的异常(编译器要求必须处置的异常)
- 不可查的异常(编译器不要求强制处置的异常)
需要异常处理:除了Error和runtimeexception
checked exceptions(检测时异常)/ 编译异常
不需要处理的:error和runtimeexceptin
unchecked exceptions(非检测时异常)/ 运行时异常
- Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。
- 运行时异常:都是RuntimeException类及其子类异常
- 非运行时异常 (编译异常):是RuntimeException以外的异常
异常处理机制
异常处理是通过try-catch-finally语句实现的。
try {
… //可能产生异常的代码
} catch( ExceptionName1 e ) {
… //当产生ExceptionName1型异常时的处置措施
} catch( ExceptionName2 e ) {
… //当产生ExceptionName2型异常时的处置措施
}
[ finally{
… //无条件执行的语句
} ]
- try:将可能出现异常的代码放在try语句块中。
- catch (Exceptiontype e):在catch语句块中是对异常对象进行处理的代码。 ()
- 如果明确知道产生的是何种异常,可以用该异常类作为catch的参数也可以用其父类作为catch的参数。
- 每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
异常处理的语法规则
- 必须在 try 之后添加 catch 或 finally 块。
- 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。
- catch 块与相应的异常类的类型相关。
- 一个 try 块可能有多个 catch 块。
- 可嵌套 try-catch-finally 结构。
- 在 try-catch-finally 结构中,可重新抛出异常。
- 除了下列情况,总将执行 finally 做为结束:JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电、失火、或遭遇病毒攻击。
Throws抛出异常的规则
- 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。
- 必须声明方法可抛出的任何可查异常(checked exception)。
- 仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。
- 调用方法必须遵循任何可查异常的处理和声明规则。
异常处理的一般原则
- 能处理就早处理,抛出不去还不能处理的就想法消化掉或者转换为RuntimeException处理。
事务异常,在持久化层,Dao层只能往上抛。 - 因为对于一个应用系统来说,抛出大量异常是有问题的,应该从程序开发角度尽可能的控制异常发生的可能。
- 对于检查异常,如果不能行之有效的处理,还不如转换为RuntimeException抛出。这样也让上层的代码有选择的余地――可处理也可不处理。
- 对于一个应用系统来说,应该有自己的一套异常处理框架,这样当异常发生时,也能得到统一的处理风格,将优雅的异常信息反馈给用户。
Java IO流
File类
- File类的常见构造方法:
- public File(String pathname)
- 以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
- public File(String parent,String child)
- 以parent为父路径,child为子路径创建File对象。
- File的静态属性String separator存储了当前系统的路径分隔符。
- 在UNIX中,此字段为‘/’,在Windows中,为‘\’
IO原理
- IO流用来处理设备之间的数据传输。
- Java程序中,对于数据的输入/输出操作以”流(stream)” 的方式进行。
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
IO流的分类
- IO流是用来处理设备与程序之间的数据传输
- 按流向(站位到程序的角度):
- 输入流
- 输出流
- 按处理的单位:
- 字节流(8bit)byte (非文本信息 视频、音频、图像)
- 字符流(16bit)char(文本文件)
- 按流的角色
- 节点流:可以从一个特定的 IO 设备读/写数据的流(访问文件相关,也叫文件流,程序直接作用在文件上)
- 处理流:对一个已存在的流进行连接和封装,通过封装后的流来实现数据读/写操作 (缓冲流)
字节流文件读写步骤
- 创建文件对象:File f = new File(“文件路径”);
- 根据文件对象创建输入输出流
FileInputStream filein = new FileInputStream(f);
FileOutputStream fileout = new FileOutputStream(f) - 实现对文件的读写
- 读:filein.read(字节数组);//将文件内容读到指定的字节数组
- 写:fileout.write(字节数组);//将指定字节数组中的数据写到文件
- 关闭流
filein.close();
fileout.close();
字符流
- 实现从指定的文件中读取字符和将字符写入指定的文件
- 抽象类:Reader和Writer
- 子类:FileReader和FileWriter
InputStream&Reader
- InputStream 和 Reader 是所有输入流的基类。
- InputStream(典型实现:FileInputStream):
- int read()
- int read(byte[] b)
- int read(byte[] b, int off, int len)
- Reader(典型实现:FileReader):
- int read()
- int read(char [] c)
- int read(char [] c, int off, int len)
- 程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件 IO 资源。
OutputStream&Writer
- OutputStream 和 Writer 也非常相似:
- void write(byte write/int c)
- void []/char[] buff)
- void write(byte[]/char[] buff, int off, int len);
- 因为字符流直接以字符作为操作单位,所以 Writer 可以用字符串来替换字符数组,即以 String 对象作为参数
- void write(String str);
- void write(String str, int off, int len)
多线程
Thread类
- 构造方法
- Thread():创建新的Thread对象
- Thread(String threadname):创建线程并指定线程实例名
- Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run方法
- Thread(Runnable target, String name):创建新的Thread对象
创建线程的两种方式
- 继承Thread类
- 定义子类继承Thread类。
- 子类中重写Thread类中的run方法。
- 创建Thread子类对象,即创建了线程对象。
- 调用线程对象start方法:启动线程,调用run方法。
- 实现Runnable接口
1)定义子类,实现Runnable接口。
2)子类中重写Runnable接口中的run方法。
3)通过Thread类含参构造器创建线程对象。
4)将Runnable接口的子类对象作为实际参数传递给
Thread类的构造方法中。
5)调用Thread类的start方法:开启线程,调用
Runnable子类接口的run方法。
线程的生命周期
Synchronized的使用方法
-
synchronized (对象){
// 需要被同步的代码;
} -
synchronized还可以放在方法声明中,表示整个方法
为同步方法。
例如:
public synchronized void show (String name){
….
}
Java反射机制
而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。这时候,我们使用 JDK 提供的反射 API 进行反射调用:
Class clz = Class.forName("com.hpe.reflect.Apple");
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, 4);
反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
通过反射调用类的完整结构
使用反射可以取得:
-
实现的全部接口
- public Class<?>[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
- public Class<?>[] getInterfaces()
-
所继承的父类
- public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。
- public Class<? Super T> getSuperclass()
-
全部的构造器
- public Constructor[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法。 - public Constructor[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。
- public Constructor[] getConstructors()
- Constructor类中:
- 取得修饰符: public int getModifiers();
- 取得方法名称: public String getName();
- 取得参数的类型:public Class<?>[] getParameterTypes();
- 全部的方法
- public Method[] getDeclaredMethods()
返回此Class对象所表示的类或接口的全部方法 - public Method[] getMethods()
返回此Class对象所表示的类或接口的public的方法
- public Method[] getDeclaredMethods()
- Method类中:
- public Class<?> getReturnType()取得全部的返回值
- public Class<?>[] getParameterTypes()取得全部的参数
- public int getModifiers()取得修饰符
- public Class<?>[] getExceptionTypes()取得异常信息
- 全部的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的名称。
通过反射调用类中的指定方法、指定属性
调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
1.通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
2.之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
Object invoke(Object obj, Object … args)
说明:
1.Object 对应原方法的返回值,若原方法无返回值,此时返回null
2.若原方法若为静态方法,此时形参Object obj可为null
3.若原方法形参列表为空,则Object[] args为null
4.若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
调用指定属性
在反射机制中,可以直接通过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的属性内容
注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。
网络编程
网络编程的目的:
直接或间接地通过网络协议与其它计算机进行通讯。
网络编程中有两个主要的问题:
如何准确地定位网络上一台或多台主机
找到主机后如何可靠高效地进行数据传输。
网络通信协议
通讯要素:IP和端口号
- IP 地址:InetAddress
唯一的标识 Internet 上的计算机
本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost
不易记忆 - 端口号标识正在计算机上运行的进程(程序)
不同的进程有不同的端口号
被规定为一个 16 位的整数 065535。其中,01023被预先定义的服务通信占用(如MySql占用端口3306,http占用端口80等)。除非我们需要访问这些特定服务,否则,就应该使用 1024~65535 这些端口中的某一个进行通信,以免发生端口冲突。 - 端口号与IP地址的组合得出一个网络套接字。
InetAdress代码示例
通讯要素2:网络通信协议
- 网络通信协议
计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。 - 通信协议分层的思想
由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。
TCP和UDP
- TCP协议:
使用TCP协议前,须先建立TCP连接,形成传输数据通道
传输前,采用“三次握手”方式,是可靠的
TCP协议进行通信的两个应用进程:客户端、服务端
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低 - UDP协议:
将数据、源、目的封装成数据包,不需要建立连接
每个数据报的大小限制在64K内
因无需连接,故是不可靠的
发送数据结束时无需释放资源,速度快
基于Socket的TCP编程
客户端Socket的工作过程包含以下四个基本的步骤:
- 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
- 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
- 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。
- 关闭 Socket:断开客户端到服务器的连接,释放线路
客户端建立socketAtClient对象的过程就是向服务器发出套接字连接请求
Socket s = new Socket(“192.168.40.165”,9999);
OutputStream out = s.getOutputStream();
out.write(“hello”.getBytes());
s.close();
服务器程序的工作过程包含以下四个基本的步骤:
- 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
- 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
- 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。
- 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept ();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int num = in.read(buf);
String str = new String(buf,0,num);
System.out.println(s.getInetAddress().toString()+”:”+str);
s.close();
ss.close();
序列化和反序列化
// 序列化
FileOutputStream fos = new FileOutputStream("temp.out");// 临时目录
ObjectOutputStream oos = new ObjectOutputStream(fos);
City jn = new City();
jn.setState("中国");
jn.setProvince("山东");
jn.setCity("济宁");
oos.writeObject(jn);
oos.flush();
oos.close();
// 反序列化
FileInputStream fis = new FileInputStream("temp.out");
ObjectInputStream oin = new ObjectInputStream(fis);
try {
Object obj = oin.readObject();
System.out.println("province=" + ((City) obj).getProvince());
System.out.println("city=" + ((City) obj).getCity());
} catch (Exception e) {
System.out.println("error");
}
oin.close();