JAVA基本知识点梳理
标识符
定义
用于表示变量、方法、属性或类等的名称。(命名时见名知义)
标识符命名规则
只能用数字、英文字母、下划线_ 美元符号$;
不能以数字开头;
严格区分大小写;
不能使用关键字或保留字作为标识符。
一般默认:
类名称:单词首字母均大写;
方法和变量名称:第一个单词首字母小写,第二个单词开始首字母大写。
变量
定义
程序运行过程中可以改变的。常量:不可改变的。(命名时标识符全大写)
变量分类
1.局部变量:在方法中声明,作用域仅限于相邻的大括号内部;使用前必须进行初 始化赋值。
2.全局变量:在公共类中声明,作用域为当前类全局范围。全局变量在声明时即有 默认值。
数据类型
分类
分类 |
关键字 |
所占字节数 |
取值范围 |
默认值 |
|||
数据类型 |
基本数据类型 |
整型 |
字节型 |
byte |
1 |
-27-27-1 |
0 |
短整型 |
short |
2 |
-215-215-1 |
0 |
|||
整型 |
int |
4 |
-231-231-1 |
0 |
|||
长整型 |
long |
8 |
-263-263-1 |
0 |
|||
浮点型 |
单精度浮点数 |
float |
4 |
精确到小数点后6-7位 |
0.0 |
||
双精度浮点数 |
double |
8 |
精确到小数点后15位 |
0.0 |
|||
字符型 |
—— |
char |
2 |
—— |
\u0000 |
||
布尔型 |
—— |
boolean |
—— |
true/false |
false |
||
引用(复合)数据类型 |
类 |
☆除了基本数据类型以外,其他的数据类型都是引用类型 |
null |
||||
接口 |
|||||||
数组 |
|||||||
其他 |
注意事项
【☆float和long数据类型在声明时需在变量值后面添加F和L,不区分大小 写☆Char 类型在赋值时可以直接赋对应的ASCII码值,会自动转换成对 应的字符。】
数据类型转换
基本数据类型的强制转换:数据从大范围的数据类型转换到小范围的数据类 型时,需要 用到强制类型转换。
基本格式:目标数据类型 变量名称 = (目标数据类型)变量名称或变量值;
long-->int-->short-->byte【需强制转换】
char-->byte/short【需强制转换】
long/int/short/byte-->char【需强制转换】
double-->float【需强制转换,转换时可能会损失精度】
float/double-->byte/short/int/long【需强制转换,转换时直接取整数部分,会 有精度损失】
☆进行强制转换时,目标数据类型的取值范围会影响转换后的变量值,若原先的变量值 超出目标类型的取值范围,会对目标类型取值范围进行取余操作再进行赋值
☆布尔类型不能发生强制类型转换
运算符
分类
1. 算术运算符
+、-、*、/、%、
2. 赋值运算符
=、+=、-=、*=、/=、%=、
3. 比较运算符
>、<、>=、<=、
4. 逻辑运算符
&&且、||或、!取反
【&也表示且,与&&的区别在于:使用&&时,若符号前的表达式已经可以确定最终结 果,则不进行符号后的表达式判断,直接输出结果,具有截断功能,可以节省一些不必 要的运算;而&不管结果如何,都一定会进行前后表达式的判断,再输出最终结果。| 与||同理。】
5.条件运算符(三目运算符)
基本格式:变量类型 变量名称=布尔类型的表达式?结果1:结果2;
当表达式为true时,返回结果1;否则范围结果2。
条件运算符的结果必须被使用,否则会报错。
6.位运算符(二进制运算)
&:同为1时为1;否则为0;
|:有一个为1时即为1,都为0时才是0;
~:取反,1变成0;0变成1;
^:相同时为0;不同时为1。
>>num:向右平移num个单位;高位补1;
<<num:向左平移num个单位,低位补0.
>>>num:无符号右移,向右平移num个单位;高位补0;
流程控制语句
分类
分支结构 |
if(布尔表达式){ 方法体; }else if(布尔表达式){ 方法体; }... Else{ 方法体; } |
Switch(变量值){ case 值1:方法体1;break; case 值2:方法体2;break; case 值3:方法体3;break; ... default:方法体;(break); } 【default中的break可以省略不写,若default不是最底层,则必须加上break】 【switch中的变量值基本数据类型仅支持byte/short/int/char,引用数据类型支持String和eNum】 |
循环结构 |
For(初始化语句;条件判断语句;步进语句){ 方法体; } |
初始化语句; While(条件判断语句){ 方法体; 步进语句; } |
For(数据类型 变量名:遍历对象){ 方法体; } 【变量名表示遍历对象中的元素,这是for-each方法】 |
初始化语句; do{方法体; 步进语句;//可以在方法体前,根据需要确定 }while(条件判断语句); 【注意有一个分号】 【与while的区别在于while是先判断后执行,do-while是先执行,后判断】 |
数组
定义
数组:用于存放一组相同类型的数据。
数组特点
1. 只能存储同一种数据类型的数据。
2. 一旦初始化,长度固定。
3.数组的元素在内存中的地址是连续的
4.指向数组的变量的值为数组首元素的地址
一维数组
声明格式
数据类型[] 数组名称 = new 数据类型[]{元素1,元素2...};
数据类型[] 数组名称 ={元素1,元素2,...};
数据类型[] 数组名称 = new 数据类型[数组长度];
注意事项
【等号前后数据类型要保持一致;1和2为静态数组,声明时直接确定元素内容;3为 非静态数组;声明时只定义了数组的长度,未添加任何元素,数组内为默认值】
二维数组
定义
和一维数组相同,只是它里面存的元素是数组
声明格式
. 数据类型[][] 数组名称=new 数据类型[元素数组长度][元素数组长度];
数据类型[][] 数组名称={{元素1,元素2...},{元素1,元素2},{元素1,元素2,元素3},...};
注意事项
声明时可以不定义元素数组的长度,如果声明长度,则表明所有元素数组的长度相同。
数组名称[i]=new 数据类型[元素数组的长度];
未声明数组长度时对每个元素数组单独创建
对象数组
定义
对象数组中存放的是一个类的实例对象。其他与普通数组一样。
类
定义
类是对现实世界中具体事物的抽象描述,一般用符号class表示。
类是一个模板,它描述一类对象的行为和状态。
类可以定义为数据和方法的集合。
数据为成员变量,用来保存状态。
方法为成员方法,是对类的状态的控制。
注意:
1.一个java文件中只能有一个public类 public类的名称和.java文件的名 称一致
2.类的首字母大写 每个单词的首字母都大写
3.名称见名知意
基本特性
- 封装:类中的细节不对外公开,当需要使用类的方法时,只会表明如何使用,不会 表明具体的实现过程。
- 继承:子类继承父类的属性和方法。
- 多态:不同的对象调用同一个方法会产生不同的响应。
属性
也称之为成员变量为类的基本单位,用来保存对象的状态。
属性语法
权限 类型 名称;
【一般定义属性时用private关键字修饰,然后用getter/setter方法来获取或者设置属性 值;这样做可以避免其他程序的直接访问】
属性赋值方式
* 1.初始化会赋给默认值
* 2.自己在属性后面赋值 private String name="lisi";
* 3.set方法赋值 public void setName(String name){this.name=name;}
* 4.构造方法赋值(有参数的构造方法)
【一般setter方法传入的参数名称与属性名称一致,这样可以见名知义;通过setter方 法进行属性赋值时,一般使用this.属性名称来接收传入的参数。因为名称同名时,调用 时会根据就近原则调用,无法给属性进行赋值。举例:
public void setPrice(double price) {
//price=price; //注意:参数名字和属性的名称一样的时候不能给属性赋值,这样 的结果相当于参数自己给自己赋值。解决上面的注释的问题那么加上this关键字就可以 this.price=price;//this关键字用来表示当前对象。谁调用的方法,this就是指 谁。}】
命名规则
名称是可以自定义的;
遵循java的标识符定义规则;
属性名称首字母必须小写
常量全部大写
注意事项
属性可赋给初始值 属性也可以不给初始值 不给初始值 程序会给这个属性默认值 引用数据类型的默认值是null
方法
定义
是一段可以重复调用的代码块(在类中用来表示对象的行为)。可以实现某项特定的功 能。当程序中需要实现该功能时,只需要调用方法,无需重复编写代码。用来描述该类 对象的行为。
分类
普通方法
构造方法
普通方法定义格式
权限修饰符(public static)返回值类型 方法名称(数据类型 参数1,...){
方法体;
(return 返回值)
}
【当返回值类型不是void时,可以省略return。其他情况下必须有return来结束方法,return后的返回值类型与方法中定义的返回值类型必须一致。】
构造方法定义格式
public 类名称(属性 属性值,...){
this.属性=属性值;
..
}
方法的重载
方法名称相同,参数列表不同(个数不同、类型不同、顺序不同)
注意事项
1.构造函数没有返回值类型,仅在对象创建的时候使用,重载构造方法,可以通过不同的方法来初始化对象的属性。构造函数的名称与当前公共类名称完全一致。没有进行构造方法重载时,系统默认赠送无参数的构造方法
类初始化
初始化顺序
1.先静态后非静态
2.先属性后方法
3.先声明后赋值
4.先父类后子类
详细顺序
类加载时
1.静态属性声明===》静态属性赋默认值===》静态属性赋具体值
2.静态代码块执行
创建对象时
3.非静态属性声明===》非静态属性赋默认值===》非静态属性赋具体值
4.非静态代码块执行
5.构造方法执行
注意事项
1.属性与代码块的执行顺序与所处位置有关,两者为同级关系,按照代码的先后顺序 自上往下执行。
2.初始化中所提及的方法指的是代码块或者构造方法,普通的成员方法并不执行
3.静态的属性和代码块只在类加载时执行一次。
抽象类
定义
抽象类是用来描述类的,指的类的抽象,其中包含的内容与普通类相同。用abstract来声明
抽象方法
成员方法用abstract修饰,且不包含方法体。
举例:public abstract void method();
注意事项
- 抽象类不能创建对象
- 抽象方法一定存在于抽象类中,但抽象类不一定有抽象方法
- 子类继承抽象类时要重写所有的抽象方法,除非子类也是抽象类
- 不能用final修饰抽象类
- 不能用static或者final修饰抽象方法。
内部类(Inner Class)
分类
1. 匿名内部类
定义
匿名内部类即不知道类名字的内部类,这种内部类的创建必须借助于其他的 类或接口:
借助于普通类,只要重写其中的一个或多个方法即可
借助于抽象类需要实现其中的抽象方法
借助于接口必须实现所有声明的方法
注意事项
匿名内部类只能创建唯一的对象,如需创建多个对象,需要用具体的 实现类。
拓展
匿名内部类与匿名对象的区别:匿名内部类省略了实现类/子类,所创建 的对象唯一且有名称;匿名对象省略了对象的名称。
2. 常规内部类
定义
即成员内部类,定义在一个类中,但不包含在任意的方法体中。
使用方式
- 直接方式:
非静态内部类:
外部类名称.内部类名称 对象名称 = new 外部类名称().new 内部类名称();
静态内部类:
外部类名称.内部类名称 对象名称 = new 外部类名称.内部类名称();
- 间接方式:在外部类的方法中使用内部类(局部内部类)
3. 静态内部类
定义
static修饰的成员内部类。
注意事项
1.静态内部类不能访问外部类的非静态变量和方法。
2.static不可用于修饰局部内部类
4. 局部内部类
定义
定义在方法体中的内部类,其作用域为当前方法,出了这个方法就不能进行 使用,和局部变量相似。
注意事项
局部内部类只能使用方法中不会发生改变的局部变量(如final修饰的局 部 变量或者事实不变的),因此局部内部类不能对方法中的局部变 量进行 修 改。【理由:局部变量随方法结束而消失,但局部内部类创建的对 象存在 于堆内存中,直到被回收时才会消失,因此需要保证局部变量不会发 生 变化,才能被局部内部类使用】
接口
定义
当创建一个接口时,是在定义一个合约,说明类能做什么,而不是说明该类将怎样实现它。接口是一个合约。通常以interface来声明。
接口与抽象类的区别
共同点
- 都可以有抽象方法
- 都不能创建对象
- 都可以实现多态
不同点
- 接口中的方法全部是抽象方法,抽象类中可以有具体的方法,也可以有抽象方法
- 接口可以多继承,抽象类只能单继承(所有的类都只能单继承)
- 接口中没有构造方法,抽象类中有构造方法
- 接口中声明的所有属性都为常量,默认用public static final修饰
- 接口中所有的属性都是常量,默认且只能用public static final修饰。
- 接口中所有的方法都是抽象方法,默认且只能用public abstract修饰。
- 接口中没有构造方法,不能创建对象,但是可以声明。可以创建内部类。
- 接口是多继承,一个接口可以继承多个接口【接口不能实现接口】
- 一个类可以同时实现多个接口,如果该类不是抽象类,那么实现接口时 要重写其中所有的抽象方法。
接口的特点
标记接口
不含任何属性或者方法,仅用来表示某种特定的类型。
注意事项
- 如果接口和抽象类都能实现目的,尽量使用接口。
- 如果一个类同时继承了父类,又实现了接口,将继承写在前,实现接口 写在后。
继承与多态
概念
继承:子类继承父类的属性和方法,用extends关键字。【object是所有类的父类】
多态:不同的对象调用同一个方法,产生不同的响应。
方法的重写
定义
子类中定义了与父类相同的方法, 则父类的方法被重写。
重写原则
- 重写的方法和父类中被重写的方法要具有相同的名字,相同的参数表和相同的返回类型。【返回类型可以是父类方法中返回类型的子类】
- 重写后的方法不能抛出比父类方法更大的异常
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
- 声明为final的方法不能被重写。
- 声明为static的方法不能被重写,但是能够被再次声明。若子类重写了 父类的静态方法,在调用时声明是谁,就用谁的方法。
- 构造方法不能被重写。
- 如果不能继承一个方法,则不能重写这个方法。
- 子类继承父类或者实现接口
- 子类重写父类或者接口中的方法
- 父类或接口声明指向子类的对象
- 调用重写的方法
实现多态的必要条件
实现多态的根本原因
Java的动态绑定机制
Object类方法介绍
equals
判断是否为同一个对象。String重写了该方法,在String中该方法用于比较内容。
hashCode()
返回该对象的hash值
getClass()
获得对象的类型,返回值为Class类型
toString()
返回对象的字符串形式,一般格式为包路径+类名@哈希值,打印时默认调用该方法
finalize()
垃圾回收
Clone()
返回当前对象的副本
notify()
随机唤醒一个等待当前对象的线程
notifyAll()
唤醒所有等待当前对象的线程
wait()
使线程进入等待状态
注意事项
1.子类可以继承父类中public和protected的成员。当子类和父类在同一个包内时,子 类能够继承父类中默认包权限(没有写权限)的成员。
2.子类不能够继承父类中private成员和方法。
3.子类不能继承父类中构造方法,只是子类的构造方法中默认调用父类的无参构造方 法,用于初始化继承自父类对象。
【1.如果父类中没有无参构造,则会报错;2.构造方法调用必须在第一行】
4.子类中声明了和父类同名的成员变量,父类的成员变量被隐藏,即子类中默认使用自己的成员,要想使用父类的同名成员,必须通过super调用
5.属性看声明,方法看对象。
访问权限
分包的作用
- 便于工程管理
- 可以避免类名冲突
- 限制访问权限
访问权限分级
1. 私有权限
用private关键字表示。用private关键字修饰的属性或者方法只能在本类中进行使用。
2. 默认权限
即包权限。属性或者方法没有使用其他权限修饰符进行修饰时,即为默认权限。默认权限的属性和方法可以在同包下进行使用,不能跨包使用。
3. 继承权限
用protected关键字表示。用protected关键字修饰的属性或者方法,除了可以在同包下使用,还可以在跨包的继承子类中使用,跨包的情况下,对应的属性和方法只能在子类内部使用。
4. 公共权限
用public关键字表示。public关键字修饰的属性或者方法在当前工程下都可以进行使用。
注意事项
- 如果需要使用其他包的类,必须要进行导包的操作。Import 类的路径
- 对于不同包的概念,只要包的路径不一样,就是不同包。即使是子目录也是不同包。
异常处理
异常的定义
程序运行过程中意外导致正常指令流中断的一种事件。继承Throwable接口。
异常的分类
Error
由Java虚拟机生成并抛出,Java程序不做处理,只能通过重写代码或者其他 方式进行处理,不能通过程序进行处理。
Exception
编译期异常
(程序中的问题,可预知的): Java编译器要求Java程序必须捕获或声明所有的非运行时异常。对于方法中有throws/throw关键字抛出异常的,该异常即为编译期异常,在调用该方法时需要对其进行处理才能使编译通过。
运行期异常
RuntimeException:编译能正常通过,但程序在运行过程中会出现的异常。如空指针异常,数组越界异常。由系统检测, 用户的Java 程序可不做处理,系统将它们交给缺省的异常处理程序。
异常处理
Try---catch---finally(异常捕获)
格式
try{可能出异常的代码
}catch(异常类型 异常名称){
处理方式
}finally{
始终会执行的代码
}
注意事项
- finally中的代码无论是否有异常产生,都会执行。
- Catch可以写多个,但是只会捕获第一个产生的异常
- 当有多个catch时,异常的范围应自上而下逐步增大或者同级。
- 异常一旦发生,try中的代码就会停止执行。
- 当try代码块中有return返回结果,而finally中没有return返回结果时, 即使finally对try中返回的变量做了修改,不会对实际的返回结果产生影响。 【知识点来源于考试错题】
throw/throws(异常抛出)
格式
方法(参数) throws 异常{
方法体;
}
其中异常为方法体中需要进行处理的异常。
注意事项
throws并未对异常进行处理,而是将异常抛给了上一级,谁调用了该方法, 谁来进行处理。当主方法中抛出异常时,由JVM缺省处理机制进行处理。
自定义异常
创建方式
自定义一个类,继承异常类。
使用方式
throw 自定义异常对象
反射
反射的优缺点
优点
- RTTI:run-time type identification,运行期类型确定
- 反射机制:在程序运行过程中发现和使用类的信息。反射主要是指程序 可以访问,检测和修改它本身状态或行为的一种能力。
- 判断对象所属的类
- 构造类的对象(抽象类除外)
- 调用方法
- 判断和使用类的成员变量和方法
- 生成动态代理
- 提高程序的灵活性和可拓展性
- 降低耦合性
- 允许程序创建和控制任何类的对象
缺点
- 降低性能
- 模糊内部逻辑
类对象(Class对象)
定义
用来描述类的相关信息,当类被加载时即产生,一个类只有一个Class对象。
获取类对象(Class对象)
- 类名称.Class;
- 对象名称.getClass();===》该方法继承自Object类
- Class.forName(“类所在的路径”);该方法会产生编译异常
- Class.newInstance();//该方法已弃用
- Class.getConstructor(“参数类型的列表”).newInstance(参数值);
获取实例对象
说明: 1.参数类型的列表中传入的是构造方法中参数的Class对象,有多个 参数则传多个Class对象,无参构造的话则为空
2.参数值为各个参数类型所对应的具体的值,无参构造则为空。
获取属性(Field)
获取属性方式
- 获得public权限的属性(包括本类中的和继承自父类的属性)
Field f = Class对象.getField(“属性名称”);//获得对应属性名称的属性对象
Field[] fs = Class对象.getFields();//获得所有public权限的属性,返回集合2获得本类中所有权限的属性(不包括继承自父类的属性)
2..Field f = Class对象.getDeclaredField(“属性名称”)//获得对应名称的属性对象
Fields fs = Class对象.getDeclaredField()//获得本类中所有权限的属性,返回集合
注意:通过getDeclaredField获取属性时,一般需要setAccessible(true);这样拿到private修饰的属性时可以获取操作的权限。
属性的操作
获得属性名称:getName();
设置属性值:set(要赋值的对象,属性值);
获得属性值:get(对象名称);//获得指定对象该属性的属性值
获取方法(Method)
获得方法的方式
- 获得public权限的方法(本类中的方法和继承自父类的public权限的方法)
Method m = 类对象.getMethod(“方法名称”,参数1类型,参数2类型...);
Method[] ms = 类对象.getMethods();//获得全部public方法
2.获得本类中的方法(所有权限)
Method m = 类对象.getDeclaredMethod(“方法名称”,参数1类型,参数2类型...);
Method[] ms = 类对象.getDeclaredMethods();//获得全部本类中全部的方法
注意:通过getDeclaredMethod获取属性时,一般需要setAccessible(true);这样拿到private修饰的方法时可以获取操作的权限。
方法的使用
方法名称.invoke(“调用该方法的对象”,“方法的参数值”);
//静态方法调用时可以以类对象作为参数传入,无需实例对象。
获取构造方法(Constructor)
获得构造方法的方式
1.获得public权限的构造方法
Constructor c = 类对象.getConstructor(参数类型...);//无参构造时参数类型为空
Constructor[] cs = 类对象.getConstructors();//获得全部构造方法
2.获得本类中的构造方法(任意权限)
Constructor c = 类对象.getDeclaredConstructor(参数类型...);//无参构造时参数类型为空
Constructor[] cs = 类对象.getDeclaredConstructors();//获得全部public方法
一般需要setAccessible(true);这样拿到private修饰的方法时可以获取操作的权限。
构造方法的使用
创建对象:getConstructor(参数类型...).newInstance(参数值...);
类型判断
- 类对象.isInstance(对象的引用);//类对象指Class对象
- 对象的引用 instanceof (类名称);//instanceof为关键字,不是方法调用
集合
定义
用来存放对象的容器,实际是存放对象的引用,没有规定泛型时可以存放不同的对象,但是不能存放基本数据类型,只能存对应的包装类。
Collection(集合)
List
按照插入的顺序存放元素,元素可以重复。
ArrayList
可变数组,底层实现过程:原数组长度为N,添加元素时新建了一个长度为N+1的数组,将原数组的元素依次放入新数组中,再将新增元素放置在新数组的末尾,将原数组的引用重新指向新的数组,删除同理。
该数组添加和删除较为麻烦,但是查找元素时可以直接根据索引进行定位,查找更方便。
常用方法
- add(元素):尾部添加元素;
- add(索引,元素):向指定位置添加元素;
- addAll(集合):将集合内的所有元素添加到当前集合的尾部;
- addAll(索引,集合):将集合内的所有元素从当前集合指定索引处添加
- remove(索引):移除指定位置的元素
- remove(元素):移除第一个匹配的元素
- removeAll(集合):移除所有与集合中元素匹配的元素
- toArray():将集合转换成对象数组
- clear():清空集合
- set(索引,元素):替换指定位置的元素
- sort(比较器):根据比较器对当前集合中的元素进行排序
- size():元素个数
- isEmpty():当前集合是否为空,为空时返回true
- contains(元素):当前集合是否包含指定元素,包含则返回true
- get(索引):获得指定位置的元素
- indexOf(元素):返回元素第一次在集合中出现的位置,没有则返回-1
- iterator():获得迭代器,可以利用迭代器进行遍历输出
hasNext():迭代器是否有下一个元素
next():获得下一个元素
LinkedList
链表集合,通过Node节点对象链接,每个节点包含两个参数,分别指向与其相邻的两个元素,在实现添加时,只需要对最后一个节点设置新节点的导向即可,无需对前面的元素进行操作,因此链表集合对比与可变数组而言添加和删除的操作更加快捷,但是查找时需要从头开始查找,较为复杂。
常用方法
- add(元素):尾部添加元素;
- add(索引,元素):向指定位置添加元素;
- addAll(集合):将集合内的所有元素添加到当前集合的尾部;
- addAll(索引,集合):将集合内的所有元素从当前集合指定索引处添加
- remove(索引):移除指定位置的元素
- remove(元素):移除第一个匹配的元素
- removeAll(集合):移除所有与集合中元素匹配的元素
- toArray():将集合转换成对象数组
- clear():清空集合
- sort(比较器):根据比较器对当前集合中的元素进行排序
- size():元素个数
- set(索引,元素):替换指定位置的元素
- isEmpty():当前集合是否为空,为空时返回true
- contains(元素):当前集合是否包含指定元素,包含则返回true
- get(索引):获得指定位置的元素
- indexOf(元素):返回元素第一次在集合中出现的位置,没有则返回-1
- iterator():获得迭代器,可以利用迭代器进行遍历输出
hasNext():迭代器是否有下一个元素
next():获得下一个元素
Stack
堆栈。该集合添加元素时,按照叠加的方法进行,最新添加的元素置于顶部,索引值从1开始自上而下。
常用方法
- peek():返回顶部元素,但不删除。
- Pop():删除顶部元素,将该元素作为返回值返回
- Push(元素):将指定元素推到堆栈顶部。
注意:上述方法为stack特有方法,同时父类(Vector)中的方法也可 以进行使用。
Vector
实现了可拓展的对象数组,增加或减少元素时数组的大小会相应的发生变化,是同步的。【如果没有同步的要求,建议用ArrayList代替,常用方法同ArrayList】
Set
按照其内部的排序规则进行排序,元素不可重复。Set的实现基于Map,区别在于Set内部定义了Value的值,固定指向Object常量对象。
HashSet
HashSet实际为HashMap的一个实例,允许存放null元素。
如何比较元素是否相同
1.比较hash值;
2.如果hash值相同,用equals方法进行比较
可以通过重写对象的hashcode()方法和equals()方法进行自定义。
TreeSet
存放的元素必须实现comparable接口,按照指定的比较方法进行排序。
注意:存放的顺序和方法有关,与存放的先后顺序无直接联系。
Map(映射)
以key-Value的形式存放对象,根据其内部的规则进行排序。Key不能重复,一个key只有一个value与之对应,当key相同时,添加操作会覆盖原有value值
常用方法
put(key,value);添加元素
get(key);获得指定key的value值
clear():清空map
remove(key);清除指定key-value(key和value一起删除)
containsKey(key);是否存在对应的key
containValue(value):是否存在对应的value
isEmpty():是否为空
size():键-值对数量
遍历方式
遍历方式一:for-each循环遍历
Set<String> set = map.keySet(); //获得集合中所有的键,放在Set集合中
for (String s : set) {
System.out.println(s+"-->"+map.get(s)); //遍历的key map.get的值value
}
遍历方式二
Set<Entry<String, String>> temp = map.entrySet();
Entry<String,String>用来存放单个键值对。
for (Entry<String, String> entry : temp) {
System.out.print(entry.getKey()); //获得键key
System.out.println(entry.getValue()); //获得值 value
}
HashMap
Key和value都可以为null
HashTable
Key和value都不可以为null
TreeMap
Key不可以为null,key要求基本有序(必须继承comparable接口)
JDBC与数据库
数据库操作
增
Insert into 表格名称(列名1,2,3...) values(值1,2,3...)不写列名默认为全部
删
Delete from 表格名称 where 列名=值;根据where条件删除,不写则默认全部删除
改
Update 表格名称 set 列名1=值1,列名2=值2,...where 列名=值 and/or 列名=值;
根据where条件对指定的列进行修改。
查
Select 列名1,列名2...from 表格名称 where 列名=值 and/or 列名=值...;
根据where条件查找内容,返回一个结果集,其中包含指定列的信息。不限制条件时返回对应表格中所有的记录。
【*表示全部列】
组函数
Count(*):所有的信息条数,若属性全为null,不计入统计
Count(列名):统计该列数据不为空的信息条数
Avg(列名):指定列的平均值(不包含null的)
Sum(列名):指定列值的总和(不包含null的)
Min(列名):指定列的最小值(不包含null的)
Max(列名):指定列的最大值(不包含null的)
concat(a,b,c):字符串拼接(可以在statement中进行应用)
Tips
1. where条件
1.常规格式:where 列名称 = 值 and/or 列名称 = 值...and/or表示并且和或者
2.范围查询
where 列名称 between 值1 and 值2 对应列的值在值1和值2之间(包含)
where 列名称 not between 值1 and 值2 对应列的值不在值1和值2之间
where 列名称 in (值1,值2,值3...) 匹配对应列值与括号内容相同的记录
3.模糊查询
关键字 like 举例:name like “%z%” 名字中含有z
%:表示任意个字符,_:下划线表示单个字符。只能用于查找字符,不 能查找数字。
4.分组查询
group by 列名。为避免数据异常,返回的结果集中保存的字段应与分组的字段保持一致。举例:如根据年龄进行分组,结果集中保存年龄的字段和组函数的字段。
Sql语句:SELECT sex,count(*)FROM `person`group by sex
2. 排序
顺序:order by 字段 (asc) 默认为顺序,故asc可省略(ascend)
反序:order by 字段 desc 不可省略(descend)
JDBC(Java DataBase Connection)
1. JDBC四大组件
1. DriverManager
获得连接对象
2. Connection
连接对象,与数据库所有相关操作都基于此对象
3. Statement
作用是向数据库中传入sql命令执行,并获得返回的结果。
Tip1:执行通过调用对应的execute方法。若设置了AutoCommit()为false;则需 要通过Connection对象手动提交Commit(),数据库的内容才会发生改变。
若没有手动提交,此时execute操作仍会有返回值,返回值与正常提交结果一致,但是数据库内无变化。
Tip2:对于增、删、改操作,返回值为受影响的行数
Tip3:对于查操作,返回值会结果集。
4. ResultSet
用于保存查询结果的结果集。
类型是Set类型,可以通过next()方法获取内部元素
2. JDBC连接数据库基本步骤
1. 导包
导入对应数据库的jar包文件。Build path-->add to build path
2. 加载驱动
通过Class.forName(“驱动类的路径”)加载驱动
对于高版本的数据库,这一步可以进行省略。
3. 获得Connection对象
通过DriverManager获得驱动对象。
DriverManager.getConnection(“要连接的数据库地址”,”用户名”,”密码”);
举例:
DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
地址组成:数据库://主机地址:端口号/表格名称
注意:Connection对象是由驱动Driver创建,DriverManager只是获取对象
4. 通过Statement传入sql指令并执行
Statement
Statement statement = connection.createStatement();通过连接对象创建
statement.executeUpdate(sql语句);传入sql语句并执行
这种传入方式要求sql语句不能修改。
PreparedStatement
PreparedStatement statement2 = connection.prepareStatement("insert into student values(?,?,?)");通过连接对象创建,同时传入sql语句
statement2.setInt(1, student.getId());//补全未定的信息
statement2.setString(2, student.getName());
statement2.setInt(3, student.getAge());
statement2.executeUpdate();//执行
这种传入方式可以用?代替sql语句中需要变更的内容,通过相应的set方法进行单独赋值,set方法的参数为(第几个问号【从1开始】,要传入的内容)。
需要注意的是,传入的内容默认为字符串,会加上单引号拼接到sql语句中。
事务
批量处理时,为了保证所有的数据保持一致,一起成功或者一起失败,这种情况下要用到事务。
Connection.setAutoCommit(false);设置数据提交方式为手动提交
数据处理;
Connection.commit();手动提交
中间放statement对象的相关操作,只有commit()正常执行,数据库中的内容才会做相应的改动。
5. 获得和使用返回的结果
结果集的使用:ResultSet rs;
- rs.next():光标移动至下一行,该方法第一次调用时,光标置于第一行记录。
- rs.getString(参数):参数可以为列名,也可以为索引(从1开始)。如果以 列名作为参数,若已知该列创建时定义的数据类型,可以通过对应的数据类 型进行获取。
- rs.previous();光标回滚一行。
6. 关闭连接
关闭结果集,关闭statement,关闭connection
I/O流输入输出
概念
输入只将外部文件导入java程序中
输出指将java程序写入外部文件中
File类
概念
文件和目录路径的抽象表示。
常用方法
File file = new File(“文件路径”);
file.create();创建文件
file.getName();获得文件名称
file.getPath():获得文件路径的字符串
file.lastModifide():返回文件最后修改时间(毫秒数)
file.length():返回文件的长度
file.listFiles():当前文件为目录文件时,返回该目录下所有文件,否则返回null
I/O分类
字节流(Stream)
1. File流
1. File输出流
FileOutputStream() out=new FileOutputStream(参数);
参数可以是:1.文件路径的String对象;2.File对象
out.write(参数);
参数可以是:1.int类型2.byte[]数组
out.flush();
刷新输出流,如果不刷新会导致数据无法正确传输
out.close();
关闭流对象
2. File输入流
FileInputStream in = new FileInputStream(参数);
参数可以是:1.文件路径的String对象;2.File对象
n.read(参数);
//参数为空时,返回int类型,表示读取字符的ASCII码值,每次只能读取单 字符,可以通过循环获取全部的内容。
参数为byte[]数组时,将读取的内容放入该byte[]数组中,读取数据的长度 由数组长度决定
in.close();
关闭流
2. Data流
属于包装流,参数只能为对应的字节流对象。
数据输入流
FileInputStream in=new FileInputStream(参数);
DataInputStream dis=new DataInputStream参数);
参数必须为输出流InputStream对象
String str = dis.readLine();//不同的数据类型有对应的read方法
in.close();
dis.close();//关闭流对象
数据输出流
File file=new File(“文件路径”);
FileOutputStream out=new FileOutputStream(参数);
DataOutputStream dos=new DataOutputStream(参数);
参数必须为输出流OutputStream对象
dos.writeDouble(90.899);//支持各种基本数据类型和String类型的写入
dos.flush();刷新输出流
dos.close();关闭流
3. 缓冲流
因为缓冲流自带缓冲区,所以可以减少硬盘访问次数,提高读取或写入效率,属于包装流,参数只能为对应的流对象。
输入:BufferedInputStream(参数)
输出:BufferedOutputStream(参数)
创建和使用同Data流
4. 打印流
打印只有输出流。通过print(“输出内容”)方法进行输出。
New PrintStream(参数);
参数可以是:1.文件路径2.file对象3.OutputStream对象
5. 重导向
System.in:在控制台输入
System.out:在控制台输出
System.err:在控制台输出,与out不同线程
使用方式:1.作为包装流的参数 2.包装流的声明指向重导向流对象。
6. 对象流
ObjectOutputStream:对象输出流
ObjectInputStream:对象输入流
- 要进行输出的对象需要实现Serializable接口(可序列化)才能进行序列化,否则无法进行正常的输出。
- Transient关键字修饰的属性值不会输出,重新导入时为默认值
字符流
1. File流
FileWriter:输出流
FileReader:输入流
2. 缓冲流
BufferReader:输入流//readLine()可以读取一行String信息
BufferWriter:输出流
3. 打印流
PrintWriter:打印输出流
字节流转为字符流
new InputStreamReader(字节输入流对象)://将指定对象转换为字符流
new OutputStreamWriter(字节输出流对象)://将指定对象转换为字符流
XML
概念
可拓展标记语言。与HTML相似,不同之处在于XML可以自定义标签
特点:
- 唯一根节点
- 双标签
- 区分大小写
- 树状结构
- 标签属性要加单引号或者双引号
XML解析器
1. DOM
文件写入
1.定义工厂API,使应用程序能够从XML文档获取生成DOM对象树的解析器
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
2.定义从XML文档获取DOM文档实例的API。 使用这个类,应用程序员可以从XML获得一个Document 。
DocumentBuilder builder = factory.newDocumentBuilder();
3.获得指定位置的XML文件
Document doc = builder.parse(new File("写入的文件路径"));
(1)获得XML文档中指定标签的信息
NodeList ns = doc.getElementsByTagName("student");//通过节点名称获取节点
for(int i=0;i<ns.getLength();i++) {//getLength()获得元素的个数
Node e = ns.item(0); //获得指定位置的节点对象
System.out.println(e.getNodeName());//获得节点的名称
}
//(2)根节点开始遍历文件
Element root = doc.getDocumentElement();//获得根节点
String v = root.getAttribute("id");//获得标签属性值
NodeList cs = root.getChildNodes();//获得子节点的集合
for(int i=0;i<cs.getLength();i++) {
Node n = cs.item(i);
System.out.println(n.getNodeName()+"-->"+n.getTextContent());
}//获得节点名称和节点内容
文件输出
1.定义工厂API,使应用程序能够从XML文档获取生成DOM对象树的解析器
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
2.定义从XML文档获取DOM文档实例的DocumentBuilder
DocumentBuilder builder = factory.newDocumentBuilder();
3.//创建文档
Document doc = builder.newDocument();
4.//创建元素
Element studentNode = doc.createElement("节点名称");//参数为节点名称
Element nameNode=doc.createElement("name");
Element ageNode = doc.createElement("age");
studentNode.setAttribute("id", "1001"); //设置节点的属性和属性值
nameNode.setTextContent("内容");//设置节点中的内容
ageNode.setTextContent("10");
//确定节点的关系,根据需要调用appendChild方法添加子节点。
doc.appendChild(studentNode);
studentNode.appendChild(nameNode);
studentNode.appendChild(ageNode);
//将文档输出
Transformer trans = TransformerFactory.newInstance().new-transformer();
DOMSource xmlSource=new DOMSource(doc);
参数为创建的Document对象
StreamResult outputTarget=new StreamResult(new File("src/test.xml"));
//参数为要保存的文件对象
trans.transform(xmlSource, outputTarget);
2.DOM4J
XML文件输入
SAXReader reader=new SAXReader();//文件输入解析器
Document doc = reader.read(new File("文件路径"));read方法获得文档对象
Element root = doc.getRootElement();获得根节点
获取文件数据方式一:for-each循环
List<Element> list = root.elements();//获得所有的子节点对象
for (Element element : list) {
System.out.print(element.getName()); //获得节点的名称
System.out.println(element.getText()); //获得节点中的内容
}
获取文件数据方式二:迭代器遍历
Iterator<Element> it = root.elementIterator();//获得节点的迭代器
while(it.hasNext()) {
System.out.println(it.next().getText());
}
}
XML文件输出
//文档对象的获得
Document document = DocumentHelper.createDocument();获得文档对象
//文档中节点和节点的关系
Element student = document.addElement("student");添加节点
student.addElement("name").setText("zhangsan");添加子节点和赋值
student.addElement("age").setText("10");
输出方式一
XMLWriter writer=new XMLWriter(new FileOutputStream(new File("文档路径")));
writer.write(document);
writer.flush();
writer.close();
输出方式二
OutputFormat format=new OutputFormat().createPrettyPrint();
XMLWriter x=new XMLWriter(new FileWriter(new File("文档路径")),format);
x.write(document);
x.close();
输出方式三
BufferedWriter bw=new BufferedWriter(new FileWriter(new File("文档路径")));
document.write(bw);
bw.flush();
bw.close();
3. JDOM
4. SAX
多线程
概念
多个任务同时进行,目的是为了充分利用CPU的资源。CPU同一时间只能执行一个任务,多线程的作用在于当任务出现停滞或者阻塞无法继续运行时,切换到另一个任务进行,保证CPU资源的有效利用。
线程的创建
1. 继承Thread类
- 自定义类继承Thread类
- 重写其中的run()方法
- 通过start()方法启动线程对象
优点:使用方便
缺点:灵活性较差,无法继承其他的父类
2. 实现Runnable接口
- 自定义类实现Runnable接口
- 重写其中的run()方法
- 新建Thread对象,将实现接口的对象作为参数传入。
- 通过Thread对象的start()方法启动线程。
优点:1.灵活性较好,在实现接口时可以同时继承其他父类
2.多个线程可以使用同一个对象作为参数,实现资源共享
缺点:使用较复杂,需要借助Thread对象。
注意事项
- 一个线程对象start()只能调用一次
- start()方法调用时,run()方法在其内部被调用
线程相关方法
Sleep(毫秒数):线程方法,使当前的线程休眠指定的时间在继续执行
Join():线程方法,调用该线程的方法会优先执行。
举例:三个线程对象Thread1、Thread2、Thread3;Thread1的run方法中,
Thread2调用了join方法,此时Thread1会等到Thread2线程运行结束之后才 会开始执行,Thread3不受影响。
getName():线程方法,获得线程名称(默认名称为Thread+编号);
setName(“”):线程方法,自定义线程的名称
Thread.currentThread():该方法为Thread的静态方法。获得当前线程对象,在实现Runnable接口的对象方法中使用,可以获得以该对象为参数的线程对象。
setPriority(int类型):设置线程优先级1-10;线程优先级高的有更高的几率强占CPU资源,但不是绝对的。【Thread有常量用来表示优先级】
yield():线程方法,当前线程让出CPU资源,所有线程重新开始抢占。。【可能当前线程会重新抢到线程,因此不是绝对的】
Object类中线程相关方法
Wait():同步方法中使用,当前锁对象调用该方法时,使当前线程进行休眠状态,等待唤醒。在被唤醒之前,不会继续运行。
Notify():锁对象调用该方法时,使等待该锁对象的线程继续执行,若有多个等待的线程,则随机唤醒其中一个。
notifyAll():同notify,唤醒全部等待的线程。
线程生命周期
- 新建状态:线程对象创建时处于新建状态
- 就绪状态:线程对象调用start方法后,进入就绪状态
- 运行状态:就绪状态的线程对象抢到CPU资源就进入运行状态
- 阻塞状态:线程出现阻塞或失去资源时进入阻塞状态。阻塞消失后重新 进入就绪状态。
阻塞分类
- 等待阻塞:wait方法
- 同步阻塞:同步锁在被其他线程占用时
- 其他阻塞:I/O输入阻塞、sleep方法、join方法
- 死亡状态:线程运行结束或者调用stop方法,进入死亡状态
线程同步
概念
当多个线程对同一个对象进行操作时,由于线程之间相互独立,在数据读取和存储时会产生偏差,导致数据异常。
举例说明:Thread1和Thread2同时对一个对象中的静态属性进行取值和赋值的操作,要求每次赋值该属性值进行累加。当Thread1完成取值操作但未进行赋值时,Thread2在这时进行了取值的操作,此时Thread2取到了和Thread1相同的值,当两者进行赋值操作时,会存在赋值相同的情况,此时该属性值并没有按照要求进行累加,这时就出现了数据异常。
同步的作用在于当Thread1对该对象进行操作时,保证其他线程不能使用该对象。当Thread1完成了全部的取值-赋值操作后,其他线程才能对该对象进行操作,这样保证了数据的正确性。
作用
避免数据异常
Synchronized关键字
1. 同步代码块
obj为同步锁,当且仅当多个同步代码块使用同一个Object对象作为同步锁 时,才能实现同步的效果。
Synchronized(Object obj){
执行的代码;
}
2. 同步方法
当多个线程调用同一个对象的同步方法时,同一时间内只有一个方法在运 行。
public synchronized void method(){
方法体;
}
3. 同步静态方法
当synchronized关键字修饰静态方法时,此时锁对象为该方法所处的类对象。
public synchronized static void method(){
方法体;
}
死锁
多个同步线程在互相等待对方释放锁对象时,这样的状态称为死锁。
举例如下:左边的线程获得了S1锁对象,若要继续向下执行,需要再获得 S2锁对象;右边的线程获得了S2锁对象,若要继续向下执行,需要再获得 S1锁对象;此时左右两边的线程都处于同步阻塞状态,无法继续执行。
【这种形式的死锁不是一定发生,当左边的线程比右边线程先拿到S2锁对象,此时不会发生死锁。但是存在死锁的几率,这也是不被允许的】
synchronized (s1) { System.out.println("thread one get s1"); synchronized (s2) { System.out.println("thread one get s2"); } } |
synchronized (s2) { System.out.println("thread two get s2"); synchronized (s1) { System.out.println("thread two get s1"); } } |
避免死锁的方式:
- 一次性分配全部的锁
- 按照指定的顺序获取锁对象
- 按照相反的顺序释放锁对象
拓展
String、StringBuffer、StringBuilder的区别:
String是字符串常量,被定义后不能进行修改
StringBuilder是可变字符串,存在于字符串缓存区中,处理字符串的效率较 高。其中的方法多数为非同步方法,线程不安全。
StringBuffer为可变字符串,存在于字符串缓存区中,其中的方法多数为同步 方法,因此相比于StringBuilder而言,执行效率较低,但是保证了线程安全。
Swing布局和事件
1. 基本组件
窗口主件JFrame
JFrame frame=new JFrame("参数"); //参数是窗体上的内容
frame.setSize(500, 500);//设置窗体的大小 单位是像素
frame.setLayout(new FlowLayout()); //设置窗体的布局方式
底层容器Container
用来存放组件的一个容器。可以将各个组件添加到底层容器中,再将底层容器添加进窗口,该组件不是必须的。
轻量容器JPanel
可以用来存放组件。在页面布局时,可以将组件添加进不同的JPanel对象中,设置不同的布局方式(默认为流式布局),再将JPanel添加进窗口或底层容器,进行整体布局,这样可以实现更多形式的布局。
按钮JButton
JButton btn=new JButton("参数");参数是按钮上的文字
frame.add(btn);//创建组件后添加到窗口主件
文本标签JLabel
JLabel lable=new JLabel("名称");标签内容
frame.add(lable);
文本框JTextField
JTextField f=new JTextField(“默认内容”,文本框长度); 可以只定义长度
frame.add(f);创建组件后添加到窗口主件
密码框JPasswordField
JPasswordField password=new JPasswordField(10);参数为长度
frame.add(password);创建组件后添加到窗口主件
文本域JTextArea
JTextArea area=new JTextArea(10, 5);//第一个参数行 第二个列
Area.setLineWrap(true);文本遇到边界时自动换行。
添加滚动条
area.setEditable(false);//不可以编辑
frame.add(area);创建组件后添加到窗口主件
复选框JCheckBox
JCheckBox checkBox=new JCheckBox("文本内容");
frame.add(checkBox);
单选框JRadioButton
JRadioButton radio1=new JRadioButton("男");
JRadioButton radio2=new JRadioButton("女");
ButtonGroup bg=new ButtonGroup();
bg.add(radio1);
bg.add(radio2);
frame.add(radio1);
frame.add(radio2);
单选功能的实现必须将单选框放在ButtonGroup,同时窗口对象也要添加单选框
列表框JList
Object[] ds= {"zs","lisi"};
JList list=new JList<>(ds);
frame.add(list);
下拉列表框JComboBox
JComboBox bpx=new JComboBox<>(参数);
参数为列表框对象或者Object[]数组。
frame.add(bpx);
菜单
JMenuBar bar=new JMenuBar(); //菜单
JMenu m1=new JMenu("File");//菜单项
JMenu m2=new JMenu("Edit");
JMenuItem i=new JMenuItem("open");//下拉项
JMenuItem i2=new JMenuItem("close");
m1.add(i); //下拉项添加到菜单项中
m1.add(i2);
bar.add(m1);//菜单项添加到菜单中
bar.add(m2);
frame.setJMenuBar(bar);//菜单放入窗体中
模式对话框JOptionPane
它提供了很多现成的对话框样式,可以供用户直接使用。
有三个值 是返回0 否返回1 取消返回2
确认框:int r = JOptionPane.showConfirmDialog(frame, "你好");
信息提示框:int r = JOptionPane.showConfirmDialog(frame, "修改成功", "title", JOptionPane.CLOSED_OPTION); //确定
文件选择JFileChooser
JFileChooser choose=new JFileChooser();
choose.showOpenDialog(frame);//打开文件
choose.showSaveDialog(frame); 保存文件
File file = choose.getSelectedFile();
表格table
Object[] columnNames= {"编号","名字","工资","性别","年龄"};
DefaultTableModel dm=new DefaultTableModel(columnNames,0); //表格模型
JTable table=new JTable(dm);//表格组件
JScrollPane p=new JScrollPane(table); //给表格加滚动条
对表格中数据的操作全部通过表格模型来完成
//给表格添加数据
for(int j=0;j<10;j++) {
Object[] rowData= {"1001"+j,"欧阳锋","2000000","男","不详"};
dm.addRow(rowData);//参数为Object对象数组
}
//删除数据
//dm.removeRow(7); //删除指定行的数据
//清空表格
1.dm.setRowCount(0);//设置行数为0
2.循环调用remove方法
int c=dm.getRowCount(); //获得表格的行数
int cc=dm.getColumnCount();获得表格的列数
dm.insertRow(c, rowData);//在指定位置插入行
frame.add(p);//添加表格组件到窗口
frame.setVisible(true); //设置窗体可见
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //窗体关闭程序结束
2. 布局方式
1. 流式布局
组件按照指定的对齐方式,以类似于文字输入的方式进行布局,当组件占满一行的位置后,则自动换行。
FlowLayout l=new FlowLayout(FlowLayout.LEFT,30,100);
第一个参数设置流式布局的对齐方式
第二个参数设置的每个组件之间的水平间距
第三参数设置行间距
2. 边界布局
Java默认将窗口分隔成五个部分(north、south、west、east、center);创建边界布局对象时,可以设置参数调整不同部分之间的间隔。如果有那个部分没有添加任何组件,那么其他部分会自动调整边界进行合并。
BorderLayout b=new BorderLayout(10,20);
参数:第一个为水平间距;第二个是垂直间距
3. 格子布局
将窗口按照指定的行数和列数进行分隔,创建布局对象时可以设置行间距和 水平间距。
注意事项:
- 若组件的数量不够填满所有格子,那么剩余的格子会空着,布局保持不变。
- 若组件的数量超出定义的格子数,那么会自动添加列,保持行数不变。
GridLayout mgr=new GridLayout(行数,列数,水平间距,垂直间距);
监听事件
概念
当用户对表格中的组件进行例如点击、鼠标移动或者点击、键盘输入等外部操作时,实际产生了对应的事件对象,监听中有actionPerformed()方法可以捕获到该事件对象,并执行自定义的代码。
创建监听
- 写匿名内部类,重写抽象方法
- 自定义监听类实现监听(Listener)接口,重写抽象方法
- 自定义监听类继承适配器类(MouseAdapter、KeyAdapter),重写抽象方法
对于鼠标和键盘监听来说,我们可能只需要监听某一种事件,如果实现接口则需要对所有的方法进行重写,比较麻烦,通过继承适配器,我们可以根据需要重写其中的某个方法即可。
常用监听
1. 点击事件监听ActionListener
重写actionPerformed()方法,其中写相应要执行的代码
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
要执行的代码;
}
}
2. 鼠标事件监听MouseListener
鼠标左键、滚轮、右键点击时产生的值不同,鼠标的左键是1 中间2 右边是3,可以通过e.getButton()来获取值,都可以用于触发事件。
public class MyMouserListener implements MouseListener{
//鼠标点击这个方法会被执行
@Override
public void mouseClicked(MouseEvent e) {
方法体;
}
//鼠标按下这个方法会被执行
@Override
public void mousePressed(MouseEvent e) {
方法体;
}
//鼠标松开这个方法会被执行
@Override
public void mouseReleased(MouseEvent e) {
方法体;
}
//鼠标进入组件中执行的方法(鼠标悬浮在组件区域)
@Override
public void mouseEntered(MouseEvent e) {
方法体;
}
//鼠标离开组件执行的方法
@Override
public void mouseExited(MouseEvent e) {
方法体;
}
}
3. 键盘事件监听KeyListener
对于键盘事件而言,以下三种方式基本上是同时触发的。
public class MyKeyListener implements KeyListener{
@Override//键盘输入时触发
public void keyTyped(KeyEvent e) {
}
@Override//当键盘按键按下时触发
public void keyPressed(KeyEvent e) {
System.out.println(e.getKeyChar()); // 获得键盘的字符
System.out.println(e.getKeyCode()==KeyEvent.VK_0); //获得按键的内容的值 KeyEvent下提供可一些值的常量属性,用来表示不同的按键
//System.out.println("key press");
}
@Override//当键盘按键松开时触发
public void keyReleased(KeyEvent e) {
//System.out.println("key Released");
}
}
正则表达式
概念
根据某种规则去匹配相应的字符串,正则表达式则用来定义这种规则。
正则表达式由普通字符和元字符组成
普通字符:如字母、数字、汉字等
元字符:可以匹配某些字符形式的具有特殊含义的字符,其作用类似于通配符
具体使用
1.数量的匹配
* 指定匹配0个或者多个
+ 指定匹配1个或者多个
? 指定匹配0个或者1个
{m} 指定匹配恰好m个
{m,n} 指定匹配至少m个,至多n个
{m,} 指定匹配至少m个
2.匹配字符集
\d 匹配单个数字字符(0-9)
\D 匹配单个非数字字符
\w 匹配单词(单个数字、字母、下划线字符)
\W 匹配非单词(单个非数字字母下划线字符)
\s 匹配单个空白符(空格、换行符)
\S 匹配单个非空白符
3.特殊字符
\:转义符,只能成对出现。后面的符号表示特殊的意义
. :点表示匹配任意一个字符
4.特殊集合
[0-9]:匹配一个数字
[a-z]:匹配一个a到z的小写字母
[A-Z]:匹配一个A到Z的大写字母
A-C || [F-H]:匹配ABCFGH
A-G && [C-H]:(ABCDEFG,CDEFGH)取相同的字符, 匹配CDEFG
注意:[] 匹配一个字符,控制数量要用{}表示
5.边界匹配
^:表示以开头的字符
$:表示以结尾的字符
[^指定字符]:表示不能包含的字符
6. 分组匹配
(内容1)数量:表示内容1重复指定的数量次
String temp="192.168.1.233";
f=temp.matches("(\\d{1,3}\\.){3}\\d{1,3}");
7.String类方法
String.match(“正则表达式”);//返回与正则匹配的子字符串
String.split(“正则表达式”);//用正则匹配子字符串,以此作为字符串的分隔
8.匹配中文
String c="中国人民万岁";
f=c.matches("[\\u4e00-\\u9fa5]{4,}");
9.java提供的正则表达式的类
方式1:
Pattern p = Pattern.compile("a*b");//定义表达式
Matcher m = p.matcher("aaaaab");//括号内为需要匹配的字符串
boolean b = m.matches();//返回匹配的结果,true或者false
方式2:
Pattern p2=Pattern.compile("\\d{11}");
Matcher m2=p2.matcher("13455556666zhangsan13666666666");
类似于结果集,find方法查看是否有值,group方法从中取值。
while(m2.find()) { //
System.out.println(m2.group());
}
方式3:
Boolean b =Pattern.matches(“正则表达式”,”匹配字符串”);
该方法只能匹配一次,不能被Matcher重复使用。
JUnit测试
JUnit3测试
- 导包Junit3
- 选择要测试的类,右键新建Junit Test Case类,自定义类名称。
要求:1.该类必须是TestCase的子类
2.测试的方法必须以test开头,无参数
- Next选择要测试的方法
- Run-run as -Junit Test。
SetUp()方法:测试方法开始执行时调用
TearDown()方法:测试方法执行结束时调用
Assert.assertEquals()方法用于被测试的方法内部,可以将期望值和方法的返回值作为参数传入,若不相同,表明方法与预期不符,会在Junit窗口红色报错。
JUnit4测试
- 导包Junit4
- 选择要测试的类,右键新建Junit Test Case类,自定义类名称。
要求:1.该类不要求是TestCase的子类
2.测试的方法不要求以test开头,方法是无参数的
- Next选择要测试的方法
- Run-run as -Junit Test。
SetUp()方法:测试方法开始执行时调用
TearDown()方法:测试方法执行结束时调用
Assert.assertEquals()方法用于被测试的方法内部,可以将期望值和方法的返回值作为参数传入,若不相同,表明方法与预期不符,会在Junit窗口红色报错。
注解的使用:
@before:测试方法执行前调用
@after:测试方法执行结束后调用
@test:测试方法
@test(timeout=1000):测试方法,限制运行时间为1000毫秒,超出则报错
@test(expected=ArithmeticException.class):测试方法中预计会产生对应的异常,若没有产生对应的异常则报错。
@Ignore:该注解的方法不进行测试。
网络编程
InetAddress
表示Internet协议的地址。
获得方式
- 获取本地地址对象:InetAddress.getLocalHost();
- 通过主机名称获取对象:InetAddress.getByName(“hostname”);
- 获取该名称的所有地址对象:InetAddress.getAllByName(“hostname”);
对象使用
getHostAddress();返回对象的IP地址(xxx.xxx.xxx.xxx格式)
getAddress();返回当前对象的地址(地址值)
URL对象
统一资源定位符,指向万维网资源的指针。
对象创建
- new URL(“url地址”);
- New URL(协议String,地址String,端口int,文件File);
- new URL(域名,文件名);
- ...
对象使用
public String getProtocol() 获取该URL的协议名。
public String getHost() 获取该URL的主机名。
public int getPort() 获取该URL的端口号,如果没有设置端口,返回-1。
public String getFile() 获取该URL的文件名。
public String getRef() 获取该URL在文件中的相对位置。
public String getQuery() 获取该URL的查询信息。
public String getPath() 获取该URL的路径
public String getAuthority() 获取该URL的权限信息
public String getUserInfo() 获得使用者的信息
public String getRef() 获得该URL的锚
Public URLConnection openConnection();获得URLConnection对象
URLConnection对象
用来和指定的URL地址进行数据的获取和输出。
URLConnection c ;
c.getOutputStream();获取输出流
c.getInputStream();获取输入流
Socket对象
用于实现服务器和客户端之间双向的数据传输。如实时通信。
对象创建
服务端:ServerSocket s = new ServerSocket(端口号);
//设置端口号,端口号不可重复
Socket socket = s.accept();//返回值为对应用户的socket对象
//服务器接收与端口相应的接口,当有该端口的socket对象创建时才会继 续执行之后的代码
客户端:Socket socket = new Socket(地址,端口号);
可以理解为和指定的服务器主机端口进行连接,之后可以通过该接口的输入 流对象和输出流对象与服务器进行数据的交互。
对象使用
- socket对象.getOutputStream();//可以向对应的套接口传输数据
- socket对象.getInputStream();//可以从对应的套接口获取数据
不论是服务器还是客户端,对象的使用是一致的
UDP协议(如邮件传输)
无连接的传输。安全性较低,且不能保证传输的正确性。
对象
DatagramSocket:用来保存端口信息
DatagramPacket:用来保存传输的数据内容、发送和接收数据的端口信息
服务器
DatagramSocket socket=new DatagramSocket(9999);//创建服务器的接收端口
byte[] buf=new byte[1024];//用字节数组接收数据
DatagramPacket packet=new DatagramPacket(buf, buf.length);
//参数1为存放接收数据的字节数组,参数2为接收数据的长度
socket.receive(packet); //接收数据,此时字节数组中有接收到的数据
String str=new String(buf).trim(); //将接收的字节数组转换成字符串
System.out.println("[server]收到的数据是"+str);
//2.服务器发送数据
byte[] b="你好客户端".getBytes();//字节数组用于存放要发送的数据
DatagramPacket p=new DatagramPacket(b, b.length, packet.getAddress(), 8888);参数为:存放数据的字节数组,要发送的数据长度,接收数据的地址,端口号
socket.send(p);//完成发送
客户端
DatagramSocket socket=new DatagramSocket(8888);//创建客户端的端口
//1.向服务器发送信息
byte[] buf="zhangsan".getBytes();//字节数组用于存放要发送的数据
InetAddress address=InetAddress.getByName("localhost");//获得接收数据的地址
DatagramPacket p=new DatagramPacket(buf, buf.length, address, 9999);
参数为:存放数据的字节数组,要发送的数据长度,接收数据的地址,端口号
socket.send(p);//完成发送
//2.接收服务器的信息
byte[] b=new byte[1024];用字节数组接收数据
DatagramPacket packet=new DatagramPacket(b, b.length);
参数1为存放接收数据的字节数组,参数2为接收数据的长度
socket.receive(packet);接收数据,此时字节数组中有接收到的数据
String str=new String(b).trim();将接收的字节数组转换成字符串
System.out.println("【client】收到"+str);
数据结构
分类
逻辑结构
程序运行的数据之间的逻辑关系,就是算法。
描述方式
- 二元组 {D,S}
D为数据集合。
S为关系集合。如<x,y>表示x指向y
- 图形
结构分类
1. 集合
只考虑数据元素而不考虑它们间的关系。即S集合为空
2. 线性结构
数据元素之间是 1对 1 的联系。如线性表、栈、队列
3. 树形结构
属于非线性结构。数据元素之间是 1 对 N 的联系。
4. 图状结构
属于非线性结构。数据元素之间是 M 对 N 的联系。
存储结构
物理上的,数据在计算机上的存储方式。
结构分类
1. 顺序存储结构
特点:数据元素的存储对应于一块连续的存储空间,数据元素之间的前驱和后续关系通过数据元素在存储器中的相对位置来反映。如数组。
2. 链式存储结构
特点:数据元素的存储对应的是连续或不连续的存储空间,每个存储节点对应一个需要存储的数据元素。元素之间的逻辑关系通过存储节点之间的链接关系反映出来。如链表。
二叉树
遍历方式
- 中序遍历(左子树、根节点、右子树)
- 先序遍历(根节点、左子树、右子树)
- 后序遍历(左子树、右子树、根节点)
重点:二叉树的遍历是通过递归实现的。
栈(堆栈)
概念
栈(stack)又称堆栈,它是运算受限的线性表,其限制是仅允许在表的一端进行插入和删除操作,不允许在其他任何位置进行插入、查找、删除等操作。表中进行插入、删除操 作的一端称为栈顶(top),栈顶保存的元素称为栈顶元素。相对的,表的另一端称为栈底(bottom)。 当栈中没有数据元素时称为空栈;向一个栈插入元素又称为进栈或入栈;从一个栈中删除元素又称为出栈或退栈。由于栈的插入和删除操作仅在栈顶进行,后进栈的元素必定先出栈,所以又把堆栈称为后进先出表(Last In First Out,简称 LIFO)。
操作方法见数组中Stack的相关方法。
队列
队列(queue)简称队,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。在队列中把插入数据元素的一端称为队尾(rear),删除数据元素的一端称为队首(front)。向队尾插入元素称为进队或入队,新元素 入队后成为新的队尾元素;从队列中删除元素称为离队或出队,元素出队后,其后续元素成 为新的队首元素。
由于队列的插入和删除操作分别在队尾和队首进行,每个元素必然按照进入的次序离队,也就是说先进队的元素必然先离队,所以称队列为先进先出表(First In First Out,简称 FIFO)。
一般采用循环链表的方式进行队列的数据存储。采用这种方式,在移除队首元素的时候,只需重新定义队尾指向新的队首即可,无需移动其他的元素。
算法
算法的特性
- 输入:需要解决的问题作为输入
- 输出:问题处理之后的结果作为输出
- 可行性:算法中的每一条指令都是可以实现的,均能在有限的时间内完成。
- 有穷性:指令是有限的,在执行一定时间后可以结束
- 确定性:一个输入对应唯一的输出
- 正确性。首先算法要保证功能正常实现。
- 时间复杂度和空间复杂度的平衡。(两者都很小是最佳状态)
- 简单明了,易于编译。
好算法的要求
递归算法
Java方法中自己调用自己,也就是方法中嵌套使用了自身的方法。在这种情况下,必须给方法添加结束条件,使其能正常结束,否则会陷入死循环。另外,递归的次数不能过多,否则容易发生栈溢出。
递归算法在代码量上看上去可能很少,但实际消耗内存巨大。
排序
排序就是将一组杂乱无章的数据按一定的规律排列起来(递增或递减)。选择排序方式主要考虑1.比较次数2.交换次数
Java提供的排序方法
- 利用TreeSet进行排序。(要求元素本身实现Comparable接口)
- Collections下的sort方法。可以对集合排序。默认为升序,可以自定义比较器。
- Arrays下的sort方法,默认为升序,可以对数组进行排序。
常见排序算法
1. 冒泡排序
从数组的索引0的位置开始,与索引1的元素进行比较,若索引0的元素比索引1的元素要大,升序排列的话则交换两个数,降序则保持不变。交换(或者保持不变)之后处于索引1的元素再于索引2进行比较,依次向下进行,直到数组的最后一位。一轮结束之后,数组中的最大或者最小值就置于数组末端。此时再从索引0开始进行比较,抛开数组中最后一位数的比较,将数组中剩余数字的最大值或最小值置于倒数第二位,如此循环直到数组第二位的数字确定,此时数组按照升序或降序排列完成。
特点:比较次数与交换次数都较多。
2. 选择排序
定义一个临时变量用来保存数组中的最大或者最小值的索引。初始值可以设置为数组的第一个元素索引0。将它与数组中其他元素进行比较,若发现新的元素值更大或更小,则用变量记录新元素的索引,全部比较完之后,临时变量保存的是整个数组中最大或者最小值的索引,此时将该索引的元素与数组的末尾或者首位进行交换。之后再重复上述步骤,直到确定全部的元素位置。
特点:与冒泡排序相比,元素之间比较的次数并未减少,不过元素之间的交换次数有明显的降低,效率有所提升。
3. 插入排序
假设按照升序进行排列。从数组的第二个元素开始,用临时变量储存当前的元素。与在其前面的元素进行比较。前面的元素较大,则将该元素后移一位,若前面元素较小,则说明临时变量存储的元素应排列在该元素之后,那么将临时变量存储的元素插入到该元素之后的索引位置。如此循环,直到数组的最后一个元素确定位置,即完成排序。
特点:比较的次数较多,排序过程中主要是元素的移动,对于混乱程度较高的数组,该排序方式显得较为繁琐。若数组本身基本有序,那么采用该方法进行排序,实际的移动次数就很少,实现更快捷。
4. 快速排序
首先记录一个数组的最小索引i和最大索引j。
定义一个临时变量存储数组的第一个元素,用key表示。
数组从最大索引j开始,取值与key进行比较,若key较小,则j--;往前推进一位继续比较,若key较大,则将该元素与key所在的位置进行交换,此时比key小的这一个元素置于key前面;之后从索引i开始取值与key进行比较,若key较大,则i++;向后推进一位继续比较,若key比较小时,则将两个值的位置进行交换。再重复上述步骤,直到i>=j,此时数组中所有比key大的元素都处于key的右侧,比key小的元素都处于key的左侧。这样第一次排序完成。
之后保持key的位置不动,将key前后两组数据按照前面的方式分别进行交换,直到i和j的初始值相同,则排序结束。
对于数组中元素个数较多的情况,快速排序的效率是比较高的,当元素数量少的时候,效率就比较低。
关键字
static关键字
使用场景
修饰成员变量(属性)
该属性被该类的所有实例对象共享,对该属性进行修改时,所有对象都会受影响
修饰成员方法
该方法可以通过对象调用,也可以直接通过类名来进行调用。静态方法调用看声明。
修饰内部类
能直接使用外部类静态的属性和静态方法
包的静态导入
在Import导包的时候,用static修饰导入的类时,类当中的静态方法可以直接进行调用,不需要再加类名。
注意事项
- static不能用来修饰构造方法。【理由:static修饰的方法依赖于类存在,为类服务,而构造方法的作用是对新建对象的初始化,为对象服务】
- Static不能和this关键字一起使用。
- 用static修饰的成员方法不能直接使用非static修饰的成员变量(属性)。
【解释:static修饰的方法不依赖于对象,非静态的属性依赖于对象存在;当static方 法中存在非静态属性时,在使用的时候必须要确定该属性属于哪个具体的对象才可以进 行使用,因此不能直接进行使用,如需使用必须要指明对象】
this关键字
定义
表示当前的,在使用时用来表示当前对象。在方法内部使用this关键字,谁调用该方法, this就指谁。在构造方法中this表示当前创建的对象。
super关键字
定义
用来表示父类。在使用父类的属性或者方法时会使用。
final关键字
使用场景
修饰成员变量(属性)
该属性为常量,只能赋值一次,不能进行修改,通常在声明常量时会加上static。
修饰方法
该方法可以被子类继承,但是不能被子类重写。
修饰类
该类不能被继承。如String,Math