JVM java虚拟机
1.栈区(stacksegment)存放函数的参数值,局部变量的值等,
在超过这个变量的作用域时就会被系统自动释放掉存于jvm内存中的资源。
优点:存取速度比堆快
缺点:存在栈中的数据大小 与生存期必须是确定的,无灵活性
总结:主要
for(int i=0;i<43;i++){
System.out.println(i);
}
System.out.print(i);
2.堆区(heapsegment)
存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象就回收
Scanner in=new Scenner(System.in);
in.nextInt();
优点:可以动态分配jvm内存
缺点:要在运行时分配jvm内存 速度慢
3.静态区
4.代码区
*****************************************************************************************
String 字符串 "" 用于存储一串字符
System 系统的
main 主要的
args 参数
out 输出设备
print 打印
Scanner 扫描仪
selectSort 选择排序
*****************************************************************************************
1.用于定义数据类型的关键字:
class 用于定义类,java语言的程序代码都需要定义在类中
byte 字节类型 用于存储整 (二进制8位)//128~127(十进制)
short 整型 用于存储整数 (二进制16位)
int 整型 用于存储整数 (二进制32位)
long 整型 用于存储整数 (二进制64位)
float 单精度 用于存储小数 精度7位
double 双精度 用于存储小数 精度16位
char 字符型‘’ 用于存储单个字符
boolean 布尔类型 真:true 假:false
void 无返回类型
intertace 接口
instanceof 判断其左边对象是否为其右边类的实例,返回boolean类型的数据
2.用于定义数据类型的关键字:
true 真
false 假
nuil 空
3.用来定义流程控制的关键字:
if 条件语句的引导词
else 用在条件语句中,表明当条件不成立时的分支
switch 分支语句结构的引导词
case 用在switch语句之中,表面其中的一个分支
default 默认,例如,用在switch语句中,表明一个默认的分支
while 用在循环结构中
do 用在do-while循环结构中
for 一种循环结构的引导词
break 提前跳出一个块
continue 回到一个块的开始处
return 从成员方法中返回数据
4.用于定义权限访问修饰符的关键字:
protected 一种访问控制方式:保护模式
public 一种访问控制方式:共用模式
private 私有,用于修饰类中的成员(成员变量,成员函数),只在本类中有效
5.用来定义类,函数,变量修饰符的关键字:
abstract 表明类或者成员方法具有抽象属性
static 表明具有静态属性
synchronized 表明一段代码需要同步执行
final 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变
6.用于定义类与类之间关系的关键字:
implements 表明一个类实现了给定的接口
extends 表明一个类型是另一个类型的子类型,这里常见的类型有类和接口
7.用于定义建立实例及引用实例,判断实例的关键字:
new 用来创建新实例对象
this 指向当前实例对象的引用
instanceof 用来测试一个对象是否是指定类型的实例对象
super 表明当前对象的父类型的引用或者父类型的构造方法
8.用于异常处理的关键字:
try 尝试一个可能抛出异常的程序块
catch 用在异常处理中,用来捕捉异常
throw 抛出一个异常
throws 声明在当前定义的成员方法中所有需要抛出的异常
finally 用于处理异常情况,用来声明一个基本肯定会被执行到的语句块
9.用于包的关键字:
package 包
import 表明要访问指定的类或包
10.其他修饰符关键字:
native 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的
strictfp 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范
transient 声明不用序列化的成员域
volatile 表明两个或者多个变量必须同步地发生变化
assert 用来进行程序调试
*****************************************************************************************
对于整数:java有3种表现形式:
十进制: 0-9, 满10进1
八进制: 0-7, 满8进1 用0表示开头
十六进制:0-9、A-F,满16进1 用0x表示开头
二进制: 0-1 满2进1
(一个字节(b)=8个二进制位(bit),例如1010-0110为一个字节,一字节最大为255)
1(tb)=1024 千兆字节 (gb)
1(gb)=1024 兆字节 (mb)
1 (mb) =1024 千字节 (kb)
1 (kb) =1024 字节 (b)
1 (b)=8 比特(bit)
//定义变量的格式
//变量类型 变量=初始化值;
//例如 int a=4;
变量类型:
byte 整型 用于存储整数 (二进制8位)// -128~127(十进制)
short 整型 用于存储整数 (二进制16位)
默认 int 整型 用于存储整数 (二进制32位)
long 整型 用于存储整数 (二进制64位)
float 单精度 用于存储小数 精度7位
默认 double 双精度 用于存储小数 精度16位
char 字符型‘’ 用于存储单个字符 2个字节
String 字符串 "" 用于存储一串字符
boolean 布尔值 真:true 假:false
-------------------------------------------------------
在计算机内,定点数有3种表示法:原码、反码和补码
[原码]就是前面所介绍的二进制定点表示法
即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。
[反码]表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
[补码]表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
----------------------------
Java使用补码来表示二进制数,在补码表示中,最高位为符号位,正数的符号位为0,负数为1
补码的规定如下:
对正数来说,最高位为0,其余各位代表数值本身(以二进制表示)
如+42的补码为00101010。
对负数而言,把该数绝对值的补码按位取反,然后对整个数加1,即得该数的补码
如-42的补码为11010110 (00101010 按位取反11010101 +1=11010110 )
用补码来表示数,0的补码是唯一的,都为00000000
(而在原码,反码表示中,+0和-0的表示是不唯一的,可参见相应的书籍)
而且可以用111111表示-1的补码(这也是补码与原码和反码的区别)。
-------------------------------------------------------
int ch1;
ch1='a';
System.out.println(ch1 == 'a'); //true
int ch2=97;
System.out.println((char) ch2); //a
*****************************************************************************************
赋值运算符:
= 最后运算,把右边的值放入左边
+= 把左右两边的和赋值与左边
-=
*=
/=
%=
short a=5;
a=a+5;//错误,2次运算,a+5是int类型无法赋值给a
a+=5;//正确,1次运算,只做赋值运算,类似上面的short a=5
算数运算符:
+加 -减 *乘 /除 %求余 ++自增 --自减
比较运算符:(结果只能是true或者flase)
> 大于 >= 大于等于
< 小于 <= 小于等于
!= 不等于 == 恒等于
逻辑运算符:
& 与
| 或
^ 异或: 当true^true=false
&& 条件一&&条件二 &&表示并且
|| 条件一||条件二 ||表示或者
! !条件 取反
位运算符:位运算直接对二进制进行计算
<< 左移 3<<2=12 -->3*2*2=12
>> 右移(最高位补原数值) 3>>1=1 -->3/2=1
>>> 无符号右移(最高位补0) 3>>>1=1 -->3/2=1
& 与运算 6 & 3 = 2
| 或运算 6 | 3 = 7
^ 异或运算(可以用于加密) 6 ^ 3 = 5//6^3^3=6 异或2次等于原值
~ 反码 ~6 = -7
与”是计算机中一种基本的逻辑运算方式。符号表示为 &
只有都是真的时候才返回真,其他都返回假
用于2进制就是都是1的时候才返回1,其他都返回0
11111111111111111111111111000001 /-63
00000000000000000000000011111111 /255
-----------------------------------------------
00000000000000000000000011000001 -63&255后的值
转义字符:通过 \ 来转变后面字母或者符号的意义
\n 换行
\t 退8格,制表符,相当与tab键
\b 退格
\r 按下回车键,在window系统,回车符是由2个字符来表示\r\n
System.out.println("hello"); 输出 hello
System.out.println("\"hello\""); 输出 "hello"
System.out.println("\\hello\\"); 输出 \hello\
*****************************************************************************************
语法结构
(1)条件结构: if()
if(条件){
}
(2)多重条件结构: if-else if-else
if(条件一){
执行代码一
}else if(条件二){
执行代码二
}else if(条件三){
执行代码三
}
(三)分支结构: switch case default
switch(表达式或某值){
case1:
xxx;
break;
case2:
xxx;
break;
case3:
xxx;
break;
default:
xxx;
break;
}
(四)嵌套结构
if(条件一){
if(条件二){
}else{
}
}else{
if(条件三){
}else{
}
}
*****************************************************************************************
一元运算符
i++;<=>i+=1<=>i=i+1;//先使用后对自身+1 int i=1; int b=i++; b=1 i=2
++i;<=>i+=1<=>i=i+1;//先对自身+1后使用 int i=1; int b=++i; b=2 i=2
i--;//意思和i++类似
--i;//意思和++i类似
二元运算符
+加 -减 *乘 /除 %求余
三元运算符
if(a>100){
c = 200;
}else{
c = 500;
}
<=>等价于
int a=100;
int c=a>100 ? 200: 500;
c=500
*****************************************************************************************
计数器思想:
通过一个变量记录住数据的状态变化,需要通过循环来完成
循环条件成立就循环,直到循环条件不成立,则跳出循环。
while循环语句:先判断,再执行
while(循环条件){
循环操作
}
do-while循环语句:先执行,再判断
do{
循环操作
}while(循环条件);
for循环:
for(参数初始化;循环条件;更新循环变量){
循环操作;
}
也可以没有循环操作,因为 ↓这也是循环操作。
for(参数初始化;循环条件;更新循环变量);
continue 只能用在循环里 (继续)可以用于跳循环的标号
作用:跳过循环体中剩余的语句而执行下一次循环
break 能用于switch结构和循环结构 (跳出)可以用于跳循环的标号
作用:break语句终止某个循环,程序跳转到循环块外的下一条语句
*****************************************************************************************
函数:
函数就是定义在类中的具有独特功能的一段独立小程序
函数也称为方法
函数中可以调用函数,但不能定义另外的函数
函数的格式:
修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,......){
执行语句;
retum 返回值;
}
返回值类型:函数运行后的结果数据类型
参数类型:是形式参数的数据类型
实际参数:是一个变量,用于存储调用函数时传递给函数的实际参数
retum:用于结束函数
返回值:该值会返回调用者
//当函数运算后,没有具体的返回值时,这时返回值类型用 void 来标识
//void代表的是函数是没有具体返回值的情况
//当函数的返回类型是void时,函数中的return语句可以不写
如何定义一个函数?
1.既然函数是一个独立的功能,那么该功能的运算结构是什么先明确
(明确函数的返回值类型)
2.在明确在定义该功能的过程中是否需要未知的内容参与运算
(明确函数的参数列表,即参数的类型和参数的个数)
重载:
什么时候用重载?
当定义的功能相同,但参与运算的未知内容不同(即参数列表)
那么,这时就定义同一个函数名称以表示其功能,方便阅读,
计算机通过参数列表的不同来区分重载
*****************************************************************************************
数组使用步骤:数组是属于引用类型数据
1.申明变量 int[] a;int a[](2种表达方式)
2.分配空间 a=new int[5];
3.赋值 a[0]=8;
4.处理数据 a[0]=a[0]*10;
java中的数组类型:
char char[]
int int[]
double double[]
String String[]
Scaner Scaner[]
random random[]
使用数组的三种方式:
第一种:
int a[];或者int[] a;
a=new int[5];
a[0]=32;
第二种:
int a[]=new int[5];或者int[] a=new int[5];
a[0]=22;
第三种:
int a[]={20,80,40};或者int[] a={20,30,40};
Arrays.sort(a)//对数组A进行升序操作,直接永久改变数组排序。//sort 分类;整理
例如原本数组a[5]
9|5|1|4|7
0 1 2 3 4
Arrays.sort(a);//后数组排序改变
1|4|5|7|9
0 1 2 3 4
数组的算法:
1.数组的复制
2.查找算法(搜索)
3.插入算法
4.冒泡算法
5.选择排序
多维数组:
int[] a1={5,7,8};//一维数组
int[][] a2={{8644},{15,456,23},{11,6}};//二维数组
System.out.println(a2[1][2]);//输出为23
二维数组可以看成以一维数组为元素的数组
java中多维数组的声明和初始化一样,应按高维到低维的顺序进行,例如:
int[][] a=new int[3][];
a[0]=new int[2];
a[1]=new int[6];
a[2]=new int[3];
int[][] a=new int[][4];//非法,应先声明高维
//数组中有一个属性可以直接获取到数组元素个数:length
//使用方法:数组名称.length
*****************************************************************************************
//面向对象:三个特征:封装,继承,多态
找对象,建立对象,使用对象,维护对象的使用
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:将变化隔离,便于使用,提高重用性,提高安全性
封装原理:将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。
函数就是java中最小的封装体
//private 私有,用于修饰类中的成员(成员变量,成员函数),只在本类中有效
注意:私有仅仅是封装饿一种体现形式
一个程序可以由N多类组成,搞一个主函数就行,没必要搞第二个入口。
/类和对象的关系:
现实生活中的对象:张三 李四
想要描述:提取对象忠的共性内容。对具体的抽象。
描述时:对这些对象的共性有:姓名,年龄,性别,学习java的能力。
映射到java中,描述就是class定义的类
具体对象就是对应java在堆内存中用new建立实体
类就是:对现实生活中事物的描述
对象:就是这类事物,实实在在的个体
需求:描述汽车(颜色,轮胎数),描述事物就是在描述事物的属性和行为。
属性对应是类中的变量,行为对应的是类中的函数(方法)。
其实定义类,就是在描述事物,就是在定义属性和行为。属性和行为共同成为类中的成员。
成员(成员变量和成员方法(函数))
成员变量和局部变量。
作用范围:
成员变量作用于整个类中
局部变量作用于函数中,或者语句中
在内存中的位置:
成员变量:在堆内存中,因为对象的存在,才在内存中存在。
局部变量:存在栈内存中。
class car /*汽车*/{
//描述颜色
String color="红色";
//描述轮胎数
int unm=4;
//运行行为
void run(){
System.out.println(color+".."+unm);
}
}
//生产汽车,在java中通过new操作符来完成,new之后会在堆内存中产生一个实体
//在java中的指挥方式: 对象.对象成员
Car c1=new Car();
c1.num=6;
Car c2=c1;
c2.color="blue";
c1.run();
c2.run();
//匿名对象使用方式一:当对对象的方法只调用一次时,可以用匿名对象来完成
如果对一个对象进行多个成员调用,必须给这个对象起一个名字。
//调用方法用匿名对象有意义,调用属性基本没意义
//匿名对象使用方式二:可以将匿名对象作为实际参数进行传递。
*****************************************************************************************
构造函数:
特点:1.函数名与类名相同
2.不用定义返回值类型
3.不可以写return语句
作用:给对象初始化。
注意:1.默认构造函数的特点。
2.多个构造函数是可以以重载的形式存在的。
3.所有对象创建时,都需要初始化才可以使用。
//对象一建立就会调用与之对应的构造函数。
//构造函数,当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数。
//构造函数和一般函数在写法上有不同。
//在运行上也不同,构造函数是在对象一建立就运行。给对象初始化。
//而一般方法是对象调用才执行,是给对象添加对象具有的功能。
// 一个对象建立,构造函数只运行一次。
//而一般方法可以被该对象调用多次。
//什么时候定义构造函数呢?
当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中
构造代码块。
作用:给对象进行初始化。
对象一建议就运行,而且优先于构造函数执行。
和构造函数的区别:
构造代码块是给所有对象进行统一初始化,
而构造函数是给对应的函数初始化
*****************************************************************************************
this 代表它所在函数所属对象的引用。
简单说:哪个对象在调用this所在的函数,this就代表哪个对象
this的应用:当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。
但凡本类功能内部使用了本类对象,都用this表示。
this语句:用于构造函数之间互相调用。、
this语句只能放在构造函数的第一行。
---------------------------------------------------------------------------------------
静态:static
用法:是一个修饰符,用于修饰成员(成员变量,成员函数)
当成员被静态修饰后, 就多了一个调用方式,除了被对象调用外,还可以直接被类名调用。
类名.静态成员
static特点:
1.随着类的加载而加载,随着类的消失而消失。说明他的生命周期最长。
2.优先于对象存在,静态是先存在的,对象是后存在的。
3.被所有对象共享
4.可以直接被类调用
---------------------------------------------------------------------------------------
实例变量和类变量的区别:
1.存放位置:
类变量随着类的加载而存放于方法区中
实例变量随着对象的建立而存放于堆内存中
2.生命周期:
类变量生命周期长,随着类的消失而消失
实例变量生命周期随着对象的消失而消失
---------------------------------------------------------------------------------------
静态的使用注意事项:
1.静态方法只能访问静态成员(成员变量,成员函数)
非静态方法即可以访问静态页可以访问非静态
2.静态方法中不可以定义this,super关键字。
因为静态优先于对象存在。
3.主函数是静态的。
静态有利有弊:
利:对对象的共享数据进行单独空间存储,节省空间。没有必要每个对象都存储一份
可以直接被类名调用。
弊:生命周期过长。
访问出现局限性。(静态虽好,只能访问静态)
什么时候使用静态?
要从两方面下手:因为静态修饰的内容有乘员变量和函数
什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被静态修饰。
对象中的特有数据要定义成非静态存在于堆内存中
什么时候定义静态的函数呢?
当功能内没有访问到非静态数据(对象的特有数据),
那么该函数可以定义成静态的。
静态的应用:
每一个应用程序都有共性的功能,可以将这些功能进行抽取,独立封装,以便使用。
虽然可以通过ArrayTool的对象使用这些工具方法,对数组进行操作。
但是,发现了问题:
1.对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。
2.操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
这时就考虑,让程序更严谨,是不需要对象的。
可以让ArrayTool中的方法都定义成static的。直接通过类名调用即可。
通查工具类中都是静态方法。
将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。
为了更为严谨,强制让该类不能建立对象,可以将构造函数私有化。private ArrayTool(){}
*****************************************************************************************
一个类中默认会有一个空参数的构造函数,
这个默认的构造函数的权限和所属的类一致
如果类被public修饰,那么默认的构造函数也带public修饰符
如果类没有被public修饰,那么默认的构造函数也没有没public修饰
默认构造函数的权限是随着类的变化而变化的
*****************************************************************************************
Person p1=new Person("张三",20);
该句话都做了什么事情?
1.因为new用到了person.class 所以会先找到Person.class文件并加载到内存中。
2.执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3.在堆内存中开辟空间,分配内存地址。
4.在堆内存中建立对象的特有属性。并进行默认初始化
5.对属性进行显示初始化
6.对对象进行构造代码块初始化
7.对对象进行构造函数初始化
*****************************************************************************************
public static void main(String[] args)
主函数:是一个特殊的函数。作为程序的入口,也可以被jvm调用
主函数的定义:
public:代表着该函数访问权限是最大的(公开的)
static:代表着主函数随着类的加载就已经存在了
void:主函数没有具体的返回值。
main:不是关键字,但是是一个特殊的单词,可以被jvm识别。
(String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。
主函数是固定格式的:jvm识别。
jvm在调用主函数时,传入的是new String[0];
*****************************************************************************************
设计模式:解决某一类问题最行之有效的方法。
java中23种设计模式
单例设计模式:解决一个类在内存中只存在一个对象
想要保证对象唯一。
1.为了避免替他程序过多建立该类对象。先禁止其他程序建立该类对象
2.还为了让其他程序可以访问到该类对象,那只好在本类中,自定义一个对象。
3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三部怎么用代码体现呢?
1.将构造函数私有化。
2.在类中创建一个私有并静态的本类对象。
3.提供一个公有并静态的方法可以获取到本类对象。
对于事物该怎么描述,还怎么描述。
当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
*****************************************************************************************
继承:
1.提高了代码的复用性
2.让类与类之间产生了关系。有了关系,才有了多态的特性
注意:千万不要为了获取其他类的功能,简化代码继承
必须是类与类之间有所属关系才可以继承,所属关系 is a
Java语言中:java只支持单继承,不支持多继承。
因为多继承容易带来安全隐患:当多个父类中定义了相同功能,
但功能内容不同时,子类对象不确定要运行哪一个。
但是java保留了这种机制,并用另一种体现形式来表达:多实现
java支持多层继承:A继承B,B继承C,C又继承了D。也就是继承体系
如何使用一个继承体系中的功能呢?
想要使用体系,先查阅体系父类的描述,因为父类中定义的是该体系中的共性功能
通过了解共性功能,就可以知道该体系的基本功能
那么这个体系已经可以基本使用了。
那么在具体调用时,要创建最子类的对象,为什么呢?
一是因为有可能父类不能创建对象
二是创建子类对象可以使用更多的功能,包括基本的也包括特有的。
简单一句话:查阅父类功能,创建子类功能对象使用功能。
---------------------------------------------------------------------------------------
子父类出现后:类成员的特点:
类中的成员:
1.变量:
如果子类中出现非私有的同名成员变量时,
子类要访问本类中的变量,用this
子类要访问父类中的同名变量,用super
super的使用和this的使用几乎一致。
this代表的是本类对象的引用
super代表的是父类对象的引用。
2.函数:
当子类出现和父类一模一样的函数时,
当子类对象调用该函数,会运行子类函数的内容。如同父类函数被覆盖一样
这种情况是函数的另外一个特性:重写(覆盖)
当子类继承父类,沿袭了父类的功能到子类中,
但是子类虽具备该功能,但是功能的内容却和父类不一致
这时,没必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重写功能内容
覆盖:
1.子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。
2.静态只能覆盖静态。
注意
重载:只看同名函数的参数列表
重写(覆盖):子父类方法要一模一样,包括返回值类型。
3.构造函数
在对子类对象进行初始化时,父类的构造函数也会运行,
那是因为子类的构造函数默认第一行有一条隐式的语句 super();
super():会访问父类中的空参数的构造函数。而且子类所有的构造函数默认第一行都是super();
为什么子类要访问父类中的构造函数。
因为父类中的数据子类可以直接获取。
所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的
所以子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定
注意:super一定定义在子类构造函数第一行。
子类的实例化过程:
结论:
子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类必须通过super语句形式来指定要访问父类中的构造函数。
当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
而且子类中至少会有一个构造函数会访问父类中的构造函数。
父类也同上,因为父类上面还有一个隐藏的父类 Object
父类中定义了的方法,子类可以直接调用来用
调用构造函数super(xxx);
调用一般函数super.xxx ;
*****************************************************************************************
final:最终,作为一个修饰符,
1.可以修饰类,函数,变量。
2.被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。
3.被final修饰的方法不能被复写。
4.被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,也可以修饰局部变量
当在描述事物时,一些数据的出现值是固定的,那么这时为了方便阅读,都给这些值起一个名字
而这个值不需要改变,所以加上final修饰。
作为常量:常量的书写规范所有的字母都大写,如果由多个单词组成。
单词间通过 _ 连接。
public static final double PI=3.14
public:公有 static:静态,可以被类名调用。 final:锁住这个值。
5.内部类定义在类中的局部变量上时,只能访问该局部被final修饰的局部变量。
*****************************************************************************************
abstract 表明类或者成员方法具有抽象属性
当多个类中出现相同功能,但是功能主题不同,
这时可以进行向上抽取,这时,只抽取功能定义,而不抽取功能主体。
抽象:看不懂。
抽象类的特点:
1.抽象方法一定定义在抽象类中
2.抽象方法和抽象类都必须被abstract关键词修饰。
3.抽象类不可以被new创建对象,因为调用抽象方法没意义
4.抽象类中的方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用。
5.如果子类只覆盖了部分抽象方法,那么该子类还是以个抽象类。
抽象类和一般类没有太大的不同。
该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西
这些不确定的部分,也是该事物的功能,需要明确出来,但无法定义主体。
通过抽象方法来表示。
抽象类比一般类多了抽象函数。就是在类中可以定义抽象方法
抽象类不可以实例化。
特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
---------------------------------------------------------------------------------------
什么是模板方法?
在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定部分在使用不确定的部分
那么这时就将不确定的部分暴露出去。由该类的子类去完成。
---------------------------------------------------------------------------------------
接口:初期理解,可以认为是一个特殊的抽象类
当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。
class 用于定义类
interface 用于定义接口
implements 表明一个类实现了给定的接口
abstract 表明类或者成员方法具有抽象属性
接口在定义时,格式特点:
1.接口中常见定义:常量,抽象方法。
2.接口中的成员都有固定修饰符。
常量:public static final
方法: public abstract
记住:接口中的成员都是public的。
接口:是不可以创建对象的,因为有抽象方法。
需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化
否则子类是一个抽象类
接口可以被类多实现,也是对多继承不支持的转换形式,java支持多实现。
1.接口是对外暴露的规则
2.接口是程序的功能扩展
3.接口可以用来多实现
4.类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
5.接口与接口之间可以有继承关系
//接口型引用只能指向自己的子类对象
*****************************************************************************************
多态:可以理解为事物存在的多种形态
猫 x=new 猫();
动物 x=new 猫();
1.多态的体现
父类的引用指向了自己的子类对象 //动物 x=new 猫();
父类的引用可以接收自己的子类对象
提高了扩展性,但是父类的引用只能访问父类中的成员
2.多态的前提
必须是类与类之间有关系,要么继承,要么实现。
通常还有一个前提:存在覆盖
3.多态的好处
大大的提高了代码的扩展性
4.多态的应用
5.多态的出现代码中的特点(多态的注意事项)
在多态中,成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
在多态中,成员变量的特点:
无论编译还是运行,都参考左边(引用型变量所属的类)。
在多态中,静态成员函数的特点:
无论编译还是运行,都参考左边
--------------------------------------------------------------------------------
Object:是类层次结构的根类。每个类都使用 Object 作为超类。
所有对象(包括数组)都实现这个类的方法。
hashCode():返回该对象的哈希码值。
toString():返回该对象的字符串表示。
--------------------------------------------------------------------------------
内部类的访问规则:
1.内部类可以直接访问外部类中的成员,包括私有。
之所以可以直接访问外部类中的成员,是因为内部类中持有一个外部类的引用
格式:外部类名.this
2.外部类要访问内部类,必须建立内部类对象。
访问格式:
1.当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中
可以直接建立内部类对象
外部类名.内部类名 变量名=外部类对象.内部类对象
waibulei.neibulei a1= new waibulei().new neibulei()
2.当内部类在成员位置上,就可以被成员修饰符修饰。
比如,private:将内部类在外部类中进行封装。
static:内部类就具备了静态的特性。
当内部类被static修饰后,只能访问外部类中的static成员。出现了访问局限
在外部其他类中,如何直接访问static内部类的非静态成员和方法呢?
new 外部类名.内部类名().内部类方法();
new Dome9.Dome8().method2();
在外部其他类中,如何直接访问static内部类的静态成员和方法呢?
Dome9.Dome8.method2();
注意:当内部类中定义了静态成员,该内部类必须是静态的。
当外部类中的静态方法也访问内部类时,内部类也必须是static的。
什么时候定义内部类:
当描述事物时,事物的内部还有事物,该事物用内部类来描述。
内部类定义在局部时,
1.不可以被成员修饰符修饰
2.可以直接访问外部类中的成员,因为还持有外部类中的引用。
但是不访问它所在的局部中的变量,只能访问被final修饰的局部变量
(jdk1.8 内部类访问局部变量自动添加final)
匿名内部类:
1.匿名内部类其实就是内部类的简写格式
2.定义匿名内部类的前提:
内部类必须继承一个类或者实现接口。
3.匿名内部类的格式: new 父类或者接口(){定义子类的内容}
//new Dome8().show();
new Dome7(){
void show(){
System.out.println("show:"+x);
}
}.show(); //匿名内部类
4.其实匿名内部类就是一个匿名子类对象,而且这个对象有点胖,可以理解为带内容的对象。
5.匿名内部类中定义的方法最好不要超过2个。
*****************************************************************************************
异常:就是程序在运行时出现的不正常情况。
1.异常的由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象。
其实就是java对不正常情况描述后的对象体现。
对于问题的划分:两种:一种是严重的问题,一种是非严重的问题。
对于严重的:java通过Error类进行描述。
对于Error一般不编写针对性的代码进行处理。
对于非严重的:java通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
无论Error或者Exception都具有一些共性内容。
比如:不正常情况的信息,引发原因等。
Throwable
|--Error
|--Exception
--------------------------------------------------------------------------------
2.异常的处理
java提供了特有的语句进行处理。(格式固定)
try{
需要被检测的代码;
}
catch(异常类 变量){
处理异常的代码:(处理方式)
}
finally{
一定会执行的语句;
}
finally代码块:定义一定会执行的语句。
finally常用于关闭资源。
catch是用于处理异常,如果没有catch就代表异常没有被处理,如果该异常是检测时异常,那么必须声明
--------------------------------------------------------------------------------
3.对捕获到的异常对象进行常见方法操作
1.Sting getMessage();
throws Exception//在功能上通过throws 关键字声明该功能有可能会会出现问题
对多异常的处理
1.声明异常时,建议声明更为具体的异常,这样处理的可以更具体。
2.对方声明几给异常,就对应有几给catch块。不要定义多余的catch块
如果多给catch块中的异常出现继承关系,父类异常catch块放在最下面。
建议在进行catch处理时,catch中一定要定义具体处理方式。
不要简单定义一句e.printstackTrace();
也不要简单的就书写一条输出语句。
--------------------------------------------------------------------------------
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。
所以对于这些特有的问题可以按照java的对问题封装的思想。
将特有的问题。进行自定义的异常封装。
自定义异常;
需求:在本程序中,对于除数是负数,也视为是错误的是无法进行运算的。
那么就需要对这个问题进行自定义描述.
当在函数内部出现了throw抛出异常对象,那么就必须要给出对应的处理动作。
要么在内部try catch处理
要么在函数上声明让调用者处理
一般情况在,函数内出现异常,函数上需要声明。
发现打印结果中只有异常的名称,却没有异常的信息。
因为自定义异常并未定义信息。
如何定义信息呢?
因为父类中已经把异常信息都完成了。
所以子类只要在构造时,将异常信息通过super语句传递给父类
那么就可以直接通过getMessage方法获取自定义的异常。
自定义异常:必须是自定义类继承Exception
继承Exception的原因:
异常体系有一个特点:因为异常类和异常对象都被抛出。
他们都具有可抛性。这个可抛性是Throwable这个体系中独有特点。
只有这个体系中的类和对象才可以被throw和throws操作。
throw和throws的区别
throw 使用在函数内
throws 使用在函数上
throw 后面跟的是异常对象
throws 后面跟的是异常类。可以跟多个,用逗号隔开。
Exception中有一个特殊的子类异常RuntimeException 运行时异常
如果在函数内抛出该异常,函数上可以不用声明,编译一样通过。
如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过。
之所以不用在函数上声明,是因为不需要调用者处理。
当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后
由程序员对代码进行修正。
自定义异常时:如果该异常的发生,无法在继续运算,
就让自定义异常继承RuntimeException
对于异常分两种:
1.编译时被检测的异常
2.编译时不被检测的异常(运行时异常。RuntimeException以及其子类)
--------------------------------------------------------------------------------
异常在子父类覆盖的体现:
1.子类在覆盖时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或该异常的子类。
2.如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常
如果子类方法发生了异常,就必须要进行try处理,绝对不能抛
--------------------------------------------------------------------------------
异常是什么?是对问题的描述。将问题进行对象的封装。
异常体系:
Throwable
|--Error
|--Exception
|--RuntimeException
异常体系的特点:异常体系中的所有类以及建立的对象都具备可抛性。
也就是说可以被throw和throws关键字操作。
只有异常体系具备这个特点。
--------------------------------------------------------------------------------
throw和throws的用法:
throw定义在函数内,用于抛出异常
throws定义在函数上,用于抛出异常类,可以抛出多个,用逗号隔开
当函数内有throws抛出异常对象,并未进行try处理。必须要在函数上声明,否则编译错误
注意:RuntimeException异常除外,也就是说,函数内抛出的是RuntimeException异常,函数上可以不声明
如果函数声明了异常,调用者需要进行处理。处理方式可以throws可以try。
--------------------------------------------------------------------------------
异常有两种:
1.编译时被检测异常
该异常在编译时,如果没有处理(没有抛也没有try),编译失败。
2.运行时异常(编译时不检测)
在编译时,不需要处理,编译器不检测。
该异常的发生,建议不处理,让程序停止。需要对代码进行修正。
--------------------------------------------------------------------------------
异常处理的语句
try{
需要被检测的代码;
}
catch(异常类 变量){
处理异常的代码:(处理方式)
}
finally{
一定会执行的语句;
}
注意:
1.finally中定义的通常是 关闭资源代码。因为没用的资源必须被释放。
2.finally只有一种情况不会被执行,当执行到System.exit(0);时。系统,退出。jvm结束。
catch是用于处理异常,如果没有catch就代表异常没有被处理,如果该异常是检测时异常,那么必须声明
--------------------------------------------------------------------------------
自定义异常:按照java的面向对象思想,将程序中出现的特有问题进行封装。
自定义异常:
定义类继承Exception或者RuntimeException
1.为了让该自定义具备可抛性
2.让该类具备操作异常的共性方法。
当要定义自定义异常的信息时,可以使用父类已经定义好的功能。
将异常信息传递给父类的构造函数。
class MyException extends Exception{
MyException(String message){
super(message);
}
}
--------------------------------------------------------------------------------
异常的好处:
1.将问题进行封装。
2.将正常流程代码和问题处理代码相分离,方便于阅读。
异常的处理原则:
1.处理方式有两种:try或者抛。
2.调用到抛出异常的功能时,抛出几个,就要处理几个
一个try对应多个catch的情况。
3.多个catch,父类的catch放到最下面。
4.catch内,需要定义针对性的处理方式。不要简答的定义printstackTrace,或者输出语句,也不要不写。
5.当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
如果该异常处理不了,但并不属于该功能出现的异常。
可以将异常转换后,再抛出和该功能相关的异常。
或者异常可以处理,但需要将异常产生后和本功能相关的问题提供出去,让调用者知道,并处理。
也可以将捕获异常处理后,转换新的异常抛出。
异常的注意事项:
在子父类覆盖时:
1.子类抛出的异常必须是父类的异常的子类或者子集。
2.如果父类或者接口没有异常抛出时,子类覆盖出现异常只能try不能抛
参阅
ExceptionTest.java 老师用电脑上课
ExceptionTest1.java 图形面积
*****************************************************************************************
包:
对类文件进行分类管理
给类提供多层命名空间
写在程序的第一行
类名的全称是 包名.类名
包也是一种封装形式。
总结:
包于包之间进行访问,被访问的包中的类以及类中的成员,需要public修饰
不同包中的子类可以访问父类中被protected权限修饰的成员。
包于包之间可以使用的权限只有2种:public protected
public protected default private
同一类中 ok ok ok ok
同一包中 ok ok ok
子类 ok ok
不同包中 ok
import 导入的是包中的类,不能导入包中的子包中的类。
建议,不要写通配符*,需要用到包中的哪个类,就导入哪个类。
*****************************************************************************************
进程:是一个正在执行的程序
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元
线程:就是进程中的一个独立的控制单元。
线程在控制着进程的执行。
一个进程中至少一个线程。
Java VM 启动时会有一个进程java.exe
该进程中至少有一个线程负责java的执行。
而且这个线程运行的代码存在于main方法中。
该线程称之为主线程。
扩展:其实jvm启动不止一个线程,其中至少还有一个垃圾回收线程(用于释放无用的对象)
1.如何在自定义的代码中,自定义一个线程呢?
通过对api的查找,java已经提供了对线程这类事物的描述。Thread类
--------------------------------------------------------------------------------
创建线程的第一种方式:继承 Thread 类,并且重写 Thread 类中的 run 方法。
步骤:
1.定义一个类继承Thread
2.复写Thread类中的run方法
目的:将自定义的代码存储在run方法中。
3.调用线程的start方法
该方法有两个作用:启动线程,调用run方法。
为什么要覆盖run方法呢?
Thread类用于描述线程。
该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法
也就是说Thread类中的run方法,用于存储线程要运行的代码。
主线程运行的代码存储在main方法中。
线程都有自己默认的名称,可以通过getName获取
Therad-编号 该编号从 0 开始。
static Thread currentTherad():获取当前线程对象。
getName():获取线程名称。
设置线程名称:setName或者构造函数。
--------------------------------------------------------------------------------
创建线程的第二张方式:实现 Runnadle 接口
步骤:
1.定义类实现 Runnadle 接口
2.覆盖 Runnadle 接口中的run方法
将线程要运行的代码存放在该run方法中
3.通过 Therad 类建立线程对象
4.将 Runnadle 接口的子类对象作为实际参数传递给 Therad 类的构造函数
为什么要将 Runnadle 接口的子类对象传递给 Therad 类的构造函数
因为,自定义的run方法所属的对象是 Runnadle 接口的子类对象
所以要让线程去指定指定对象的 run 方法.就必须明确该run方法所属的对象
5.调用 Therad 类的start开启线程并调用 Runnadle 接口子类的run方法。
--------------------------------------------------------------------------------
实现方式和继承方式有什么区别呢?
实现方式好处:避免了单继承的局限性。
在定义线程时,建议使用实现方式。
两种方式的区别:
继承 Therad :线程代码存放在 Therad 子类中的 run 方法中。
实现 Runnable :线程代码存放在接口子类的 run 方法中。
--------------------------------------------------------------------------------
多线程的安全问题:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完
另一个线程参与进来执行。会导致共享数据错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程先执行完,在执行过程中,其他线程不可以参与执行
Java对于多线程的安全问题提供了专业的解决方式,就是同步代码块。
synchronized(对象){
需要被同步的代码
}
对象如同锁,持有钥匙的线程可以在同步中执行。
一个线程运行到 synchronized 进行判读里面是否有线程,如果没有就给钥匙
没有钥匙的线程即使获取cpu的执行权,也进不去,因为没有钥匙
同步的前提:
1.必须要有两个或者两个以上的线程
2.必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行
好处:解决了多线程的安全问题。
弊端:消耗了运算资源
死锁:同步中嵌套同步,而锁却不同。
同步函数使用的锁是this
如果同步函数被静态修饰后,使用的锁是什么呢?(静态方法中不可以定义this)
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象
类名.class 该对象的类型是class
静态的同步方法,使用的锁是该方法所在类的字节码文件。即:类名.class
--------------------------------------------------------------------------------
设计模式:解决某一类问题最行之有效的方法。
java中23种设计模式
单例设计模式:解决一个类在内存中只存在一个对象
想要保证对象唯一。
1.为了避免替他程序过多建立该类对象。先禁止其他程序建立该类对象
2.还为了让其他程序可以访问到该类对象,那只好在本类中,自定义一个对象。
3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三部怎么用代码体现呢?
1.将构造函数私有化。
2.在类中创建一个本类对象。
3.提供一个方法可以获取到本类对象。
对于事物该怎么描述,还怎么描述。
当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
--------------------------------------------------------------------------------
这个是先初始化对象。称为:饿汉式。
Single类一进内存就创建了对象。
class Single{
private static Single s=new Single();
private Single(){}
public static Single getInsttance(){
return s;
}
}
--------------------------------------------------------------------------------
对象是方法被调用时,才初始化,也叫做对象的延时加载。称为:懒汉式。
Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
class Single{
private static Single s=null;
private Single(){}
public static Single getInsttance(){
if(s==null){
s=new Single();
}
return s;
}
}
--------------------------------------------------------------------------------
线程间通讯:
其实就是多给线程在操作同一个资源,但是操作动作不同。
锁.whit(); //将线程丢进线程池,暂停运行。
锁.notify(); //唤醒线程池中的最先存入那个同锁线程
锁.notifyAll(); //唤醒线程池中所有的同锁线程
都使用在同步中,因为要对持有监视器(锁)的线程操作。
所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义Object类中
因为这些方法在操作同步中线程时,都需要标识它们所操作线程持有的锁
只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。
不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。
--------------------------------------------------------------------------------
为什么定义notifyAll,
因为需要唤醒对方线程。
因为用notify,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待。
jdk1.5中提供了多线程升级解决方案。
将同步 synchronized 替换成了显示的Lock操作。
以前看不见,现在就 .lock(); 拿锁 .unlock();
将Object中的wait,notify,notifyAll,替换了Condition对象。
该对象可以通过Lock锁进行获取。
--------------------------------------------------------------------------------
如何停止线程?stop方法已经过时,只能run方法结束。
开启多线程运行,运行代码通常都是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:当线程处于了冻结状态。就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束
Thread类提供该方法 interrupt();
.setDaemon();将一个线程定义成后台线程(也叫保护线程)
.join();当A线程执行到了B线程的.join()方法时,A线程就会等待,等B线程执行完,A线程才会执行
join可以用来临时加入线程执行。
*****************************************************************************************
String类适用于描述字符串事物。
那么它就提供了多给方法对字符串进行操作。
常见的操作有:例如字符串"abcd"
1.获取
1.1字符串中包含的字符数,也就是字符串的长度。
int length();//获取长度
1.2根据位置获取位置上的某个字符。
char charAt(int index);
1.3根据字符获取该字符在字符串中的位置。
int indexOf(int ch);返回的是ch在字符串中第一次出现的位置
int indexOf(int ch,int fromIndex); :从fromIndex指定位置开始,获取ch在字符串中出现的位置
int indexOf(String str);返回的是str在字符串中第一次出现的位置
int indexOf(String str,int fromIndex); :从fromIndex指定位置开始,获取str在字符串中出现的位置
--------------------------------------------------------------------------------
2.判断
2.1字符串中是否包含某一个子串
boolean contains(str);
特殊之处:indexOf(str):可以索引str第一次出现的位置,如果返回-1 表示该str不在字符串中存在
所以也可以用于对指定字符串的判读是否包含str
if(str.indexOf("aa")!=-1)
而且该方法既可以判断,也可以获取出现的位置
2.2字符串中是否有内容
boolean isEmpty();原理就是判断长度是否为0
2.3字符串是否是以指定内容开头
boolean startsWith(str);
2.4字符串是否是以指定内容结尾
boolean endsWith(str);
2.5判断字符串内容是否相同。String类复写了Object类中的equals方法
boolean equals(str);
2.6判断内容是否相同,并忽略大小写
boolean equalsIgnoreCase();
--------------------------------------------------------------------------------
3.转换
3.1将字符数组转换成字符串
构造函数:
String(char[])
String(char[],offset,count);将字符数组中的一部分转换
静态方法:
static String copyValueOf(char[]);
static String copyValueOf(char[] data,int offset,int count);
static String valueOf(char[]);
3.2将字符串转换成字符数组
char[] toCharArray();
3.3将字节数组转换成字符串
String(byte[])
String(byte[],offset,count);将字节数组中的一部分转换
3.4将字符串转换成字节数组
byte[] getBytes();
3.5将基本数据类型转换成字符串
static String valueOf(int) //3+"";//String.valueOf(3);
static String valueOf(double)
特殊:字符串和字节数组在转换过程中,是可以指定编码表的
但凡你想要做编码操作时,要变成字节数组才可以。
--------------------------------------------------------------------------------
4.替换
String replace(old,new);
5.切割
String[] split(reqex);
6.子串 //获取字符串中的一部分
String substring(begin);//从指定位置开始到结尾
String substring(begin,end);//从指定位置开始到第二个指定位置(包含头,不包含尾)
--------------------------------------------------------------------------------
7.转换,去除空格,比较
7.1将字符串转换成大写或者小写
String toUpperCace(); //将字符串转换成大写
String toLowerCace(); //将字符串转换成小写
7.2将字符串两端的多个空格去除
String trim(); //将字符串两端的空格去除
7.3对两个字符串进行自然顺序的比较
int compareTo(string);
String s2="aac"; //十进制:a是97 c是98 1是49
String s3="a1a"; //为什么只比较a和1,因为这2个是最先不相等的字符
sop(s2.compareTo(s3)); //这里就是比较97于49,输出的值是48
--------------------------------------------------------------------------------
StringBuffer是字符串缓冲区,是一个容器。
特点:
1.长度是可以变化的
2.可以直接操作多个数据类型
3.最终会通过 toString 方法变成字符串
C create U update R read D delete
创建 更新 读取 删除
1.存储(创建)
StringBuffer append():将指定的数据作为参数添加到已有数据的结尾处
StringBuffer insert(index,数据):可以将数据插入到指定 index 位置
2.删除
StringBuffer delete(start,end):删除缓冲区中的数据,包含start 不包含end
StringBuffer deleteCharAt(index):删除指定位置的字符
3.获取(读取)
char charAt(int index)
int indexOf(String str)
int lasrIndexOf(String str)
int length()
String substring(int start,int end)
4.修改(替换,更新)
StringBuffer replace(1,3,"java") 把角标1和2上的替换成指定的
void setCharAt(int index,char ch) 替换指定位置的
5.反转
StringBuffer reverse() 反转
6.将缓冲区中指定数据存储到指定数组中
void getChars(int srcBegin,int srcEnd,char[],int dstBegin)
getChars(1,4,chs,1);//取角标123上的,传进数组chs替换,从chs[1]开始
---------------------------------
StringBuilder(jdk1.5后出现)
StringBuffer 是线程同步 多线程建议使用,安全性
StringBuilder 是线程不同步 单线程建议使用,提高效率
java的升级不外乎3种:1.为了提高效率 2.为了提高安全性 3.简化书写
*****************************************************************************************
基本数据类型对象包装类
byte Byte
short short
int Integer
long Long
boolean Boolean
float Float
double Double
char Character
基本数据类型对象包装类的最常见作用
就是用于基本数据类型和字符串类型之间做转换
基本数据类型转成字符串
基本数据类型+""
基本数据类型.toString(基本数据类型值);
如:Integer.toSting(34);//将34整数变成"34";
字符串转成基本数据类型
xxx a=Xxx.parseXxx(String)
int a=Integer.parseInt("123") //实例1
double b=Double.parseDouble("12.34") //实例2
boolean b=Boolean.parseBoolean("true") //实例3
--------------------------------------------------------------------------------
十进制转成其他进制
toBinaryString();
toHexString();
toOctalString();
其他进制转成十进制
parseInt(Sting s,int radix);
int a2=Integer.parseInt("110",10); //将十进制的110转换成十进制
int a2=Integer.parseInt("110",8); //将八进制的110转换成十进制
int a2=Integer.parseInt("3c",16); //将16进制的3c转换成十进制
--------------------------------------------------------------------------------
JDK1.5版本以后出现的新特性
Integer x=new Integer(4);
Integer x=4;//自动装箱 //new Integer(4)
x=x+2;//x+2: x进行了自动拆箱,变成了int类型,和2进行了加法运算
再将和进行装箱赋给x
----------------------------
Integer a=128;
Integer b=128;
sop("a==b:"+(a==b)); 结果为false,比较两个对象,不同
Integer c=123;
Integer d=123;
sop("c==d:"+(c==d)); 结果为true,因为a和b指向了同一个Integer对象
因为当数值在byte范围内时,对于新特性,如果该数值已经存在,就不会再开辟新的空间
*****************************************************************************************
Collection 集合类(容器)
|--List:元素是有序的,元素可以重复。因为该集合体系有索引
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询修改速度很快,元素越多增删越慢
|--LinkedList:底层使用的是链表数据结构。特点:增删的速度快,查询修改慢
|--Vector:底层是数组数据结构。Vector线程是同步的。
--------------------------------------------------------
|--Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。
|--HashSet:底层数据结构是哈希表,线程是同步的
HashSet是如何保证元素的唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成的。
如果元素的hashCode值相同,才会判断equals是否为true
注意,对于判断元素是否存在,以及删除等操作
依赖的方法是元素的hashCode和equals方法
----------------------------
|--TreeSet:可以对Set集合中的元素进行排序。
记住:当排序时,主要条件相同,一定要判断次要条件
底层数据结构是二叉树
保证元素唯一性的依据:
compareTo 方法 return -1 0 1
----------------------------
TreeSet排序的第一种方式:让元素自身具有比较性
元素需要实现CompareTo接口,覆盖compareTo方法。
这种方式也称为元素的自然顺序,也叫做默认顺序
TreeSet排序的第二种方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。
定义一个比较器,将比较器对象作为参数传递给TreeSet的构造函数
怎么定义:
定义一个类,实现Comparator接口,覆盖compare方法。
当两种排序都存在是,以比较器为主
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
对于随机访问的get和set,ArrayList比较占优势,因为LinkedList要移动指针。
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
--------------------------------------------------------
Set集合的功能和Collection一致。
----------------------------
List: 特有方法。凡是可以操作角标的方法都是该体系特有的方法
----------------------------
List集合判断元素是否相同,依据的是元素的equals方法。
contains基于equals方法
remove也基于equals方法
----------------------------
增
add(index,element); //在指定位置添加元素
addAll(index,Collection); //在指定位置添加多个元素
删
remove(index); //删除指定角标上的元素
改
set(index,element); //修改指定位置上元素
查
get(index); //通过角标获取元素
indexOf(element) //获取对象的位置
dubList(from,to); //包含头部不包含尾
ListIterator();
----------------------------
Enumeration枚举就是Vector特有的取出方式,类似迭代器
其实枚举和迭代是一样的。
因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。
----------------------------
LinkedList:特有方法
addFirst(); //添加到头部
addLast(); //添加到尾部
getFirst(); //获取头部,没有元素的话会抛异常 //不使用
getLast(); //获取尾部,没有元素的话会抛异常 //不使用
removeFirst(); //获取并移除头部,没有元素的话会抛异常 //不使用
removeLast(); //获取并移除尾部,没有元素的话会抛异常 //不使用
----------------------------替换为
offerFirst(); //添加到头部
offerLast(); //添加到尾部
peekFirst(); //获取头部,没有元素的话会抛unll(空)
peekLast(); //获取尾部,没有元素的话会抛unll(空)
pollFirst(); //获取并移除头部,没有元素的话会抛unll(空)
pollLast(); //获取并移除尾部,没有元素的话会抛unll(空)
----------------------------
List集合特有的迭代器。ListIterator是Iterator的子接口
在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生异常
所以,在迭代器时,只能用迭代器的方法操作元素,可是Interator方法是有限的
只能对元素进行判断,取出,删除的操作
如果想要其他操作如:添加,修改等 就需要使用其子接口 ListInerator
该接口只能通过 List集合的 ListInterator方法获取
----------------------------
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象
数组长度是不可变的,数组可以存储基本数据类型,集合只能存储对象
----------------------------
//创建一个集合容器,使用Collection接口的子类。比如:ArrayList
ArrayList al1=new ArrayList();
Iterator it1=al1.iterator();//获取迭代器,接口型引用只能指向自己的子类对象
while (it1.hasNext()){//判断是否还有元素可迭代
sop(it1.next());//迭代下一个元素
}
al1.retainAll(al2); //取交集,al1中只会存放和al2相同的元素
--------------------------------------------------------
泛型格式:通过<>来定义要操作的引用数据类型
集合类<类型>
泛型:JDK1.5版本以后出现的新特性。用于解决安全问题,是一个安全机制。
好处:
1.将运行时期出现问题 ClssCastException ,转移到了编译时期
方便与程序员解决问题。让运行时期问题减少
2.避免了强制转换的麻烦
在使用java提供的对象时,什么使用使用泛型呢?
通常在集合框架中很常见,只要见到<>就要定义泛型
其实<> 就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可
----------------------------
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候
早期定义Object来完成扩展
现在定义泛型类完成扩展
----------------------------
<?> 通配符 也可以理解为占位符
泛型的限定:
<? extends E> :可以接受E类型或者E的子类型 上限限定
<? super E> :可以接受E类型或者E的父类型 下限限定
泛型:
T类必须要是Comparable的子类,Comparable接口也带着泛型<只接受T或者T的父类>
--------------------------------------------------------------------------------
Map集合:该集合存储键值对。一对一对往里存,而且要保证键的唯一性
1.添加
put(K key,V value) 类似add方法
putAll(Map extends K,? extends V>m) 类似addAll 添加一大片
2.删除
clear() 全部删除
remove(Object key) 将制定键删除 返回值是V
3.判断
isEmpty 判断映射是否是空映射
containsKey(Object key) 是否包含某个键
containsValue(Object value) 是否包含某个值
4.获取
get(Object key) 提供一个键 返回键所映射的值,没有则返回null
size() 获取长度
values() 返回此映射中包含的值的Collection 视
Map(和Set很像,其实Set集合底层就是使用了Map集合.你Map能存一对,我Set存一个当然没问题
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的
|--HashMap:底层是哈希表数据结构,允许存入null键null值,该集合是不同步的
|--TreeMap:底层是二叉树数据结构。线程不同步,可以用于给Map集合中的键进行排序
当数据之间存在映射关系时,就要先想到map集合,因为map集合中存放的就是映射关系
--------------------------------------------------------
Map集合的两种取出方式
1 Set
将map集合中所有的键存入到Set集合。因为Set具备迭代器
所以可以迭代方式取出所有的键,再通过get方法,获取每一个值
Map集合的取出原理:将map集合转成set集合。通过迭代器取出
2 Set
将map集合中的映射关系存入到了Set集合中
而这个关系的数据类型就是:Map.Entry
Map.Entry 其实Entry也是一个接口,它是Map接口中的一个内部接口
interface Map{
public static interface Entry{
//能加static的接口都是内部接口,接口只有在成员位置上才能加静态修饰符
public abstract Object getKey(); //抽象方法,等待实现
public abstract Object getValue();
}
}
class HashMap implements Map{
class Hash implements Map.Entry{
public Object getKey(){}
public Object getValue(){}
}
}
*****************************************************************************************
集合框架的工具类
Ccllections 静态的,在java.util里,可以直接被静态方法调用.
Collections.sort(list) 首字母排序
Collections.max(list) 排序的最大值
Collections.min(list) 排序的最小值
Collections.binarySearch(list,"haha") 在list这个容器中查找"haha",返回角标位置
//如果不存在,返回(-(插入值)-1)
Collections.reverse(list); //将list集合反转
Collections.fill(list, "pp"); //将集合中的元素全部替换成pp
Collections.reverseOrder() //倒序排序,也可以强行逆转一个比较器
如TreeSet
----------------------------
Arrays 用于操作数组的工具类,里面都是静态方法
Arrays.toString(数组) 返回指定数组中的内容,字符串表示,返回值是字符串
Arrays.asList(数组) 将数组变成list集合,或者直接创建,如下例
String[] arr={"abc","aa","cdsg"};
List
//List
把数组变成list集合的好处,可以使用集合的思想和方法来操作数组中的元素。
注意:
将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的
如果你增删,会发生不支持操作异常 UnsupportedOperationException
如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转换成集合中的元素
如果数组的的元素都是基本数据类型,那么会将该数组作为集合中的元素存在
int[] arr2={2,3,4}; //基本数据类型,装的是基本数据类型
Integer[] arr2={2,3,4}; //基本数据类型对象包装类,装的是对象
----------------------------
集合转换成数组
String[] s1=al1.toArray(new String[al1.size()]);
1.制定类型的数组到底要定义多长呢?
当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组长度为集合的size
当指定类型的数组长度大于了集合的size,就不会新创建数组,而是使用传进来的数组
所以创建一个刚刚好的数组最优 new 数组类型[集合名称.size()]
2.为什么要将集合变数组?
为了限定对元素的操作
--------------------------------------------------------------------------------
高级for循环
格式:
for(数据类型 变量名:被遍历的集合(Collection)或者数组){
}
对集合进行遍历,只能获取元素 但不能对集合进行操作
迭代器除了遍历,还可以进行remove集合中元素的动作
如果使用listIterator,还可以在遍历中对集合进行增删改查的动作
传统for循环和高级for有什么区别呢?
高级for循环有一个局限性 必须有被遍历的目标
建议在遍历数组的时候,还是希望使用传统for,因为传统for可以定义角表
----------------------------
StaticImport 静态导入
当类名重名时,需要指定具体的包名
当方法重名时,指定具体所属的对象或者类
比如
import static java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员
import static java.lang.System.*;//导入了System类中所有的静态成员
*****************************************************************************************
Runtime对象
该类并没有提供构造函数
说明不可以new对象,那么会直接想到该类中的方法都是静态的
发现该类中含有非静态方法
说明该类肯定会提供一个方法获取本类对象
而且该方法是静态的,并返回值类型是本类类型
该方法是static Runtime Runtime();
由这个特点可以看出该类使用了单例设计模式完成
----------------------------
public Process exec(String cmmand) //Process:进程
thows IOException
该方法返回值是一个进程,该方法默认抛出异常
----------------------------
Thread.sleep(...) //使得当前线程休眠(暂时停止执行millis毫秒)
public static void sleep (long millis) thorows InterruptedException{}
由于是静态方法,sleep可以由类名.直接调用:Thread.sleep(…)
--------------------------------------------------------------------------------
Date对象
字母 日期或时间元素 表示 示例
G Era 标志符 Text AD
y 年 Year 1996; 96
M 年中的月份 Month July; Jul; 07
w 年中的周数 Number 27
W 月份中的周数 Number 2
D 年中的天数 Number 189
d 月份中的天数 Number 10
F 月份中的星期 Number 2
E 星期中的天数 Text Tuesday; Tue
a Am/pm 标记 Text PM
H 一天中的小时数(0-23) Number 0
k 一天中的小时数(1-24) Number 24
K am/pm 中的小时数(0-11) Number 0
h am/pm 中的小时数(1-12) Number 12
m 小时中的分钟数 Number 30
s 分钟中的秒数 Number 55
S 毫秒数 Number 978
z 时区 General time zone
Z 时区 RFC 822 time zone -0800
--------------------------------------------------------
日期和时间模式 结果
"yyyy.MM.dd G 'at' HH:mm:ss z" 2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ''yy" Wed, Jul 4, '01
"h:mm a" 12:08 PM
"hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time
"K:mm a, z" 0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa" 02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z" Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ" 010704120856-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSZ" 2001-07-04T12:08:56.235-0700
----------------------------
date 日期
mon 星期一
tue 星期二
wed 星期三
thu 星期四
fri 星期五
sat 星期六
sun 星期日
----------------------------
January Jan 一月
February Feb 二月
March Mar 三月
April Apr 四月
May May 五月
June Jun 六月
July Jul 七月
August Aug 八月
September Sep 九月
October Oct 十月
November Nov 十一
December Dec 十二
--------------------------------------------------------------------------------
Calendar类
Calendar c=Calendar.getInstance();
String[] mons={"一月","二月","三月","四月"
,"五月","六月","七月","八月"
,"九月","十月","十一月","十二月"};
String[] weeks={"","星期天","星期一","星期二","星期三","星期四"
,"星期五","星期六"};
sop(c.get(Calendar.YEAR) + "年");
sop(mons[c.get(Calendar.MONTH)]);
sop(c.get(Calendar.DAY_OF_MONTH) + "日");
sop(c.get(Calendar.HOUR_OF_DAY)+"点");
sop(c.get(Calendar.MINUTE)+"分");
sop(c.get(Calendar.SECOND)+"秒");
sop(weeks[c.get(Calendar.DAY_OF_WEEK)]);//星期
--------------------------------------------------------------------------------
Math类(工具类)
double d=Math.ceil(-12.34);//ceil返回大于指定数据的最小整数。
double d2=Math.floor(12.34);//floor返回小于指定数据的最大最整数。
long l2=Math.round(12.54);//四舍五入
double d3=Math.pow(2,3);//2的3次幂
double d=Math.random();//返回一个大于等于0且小于1的值
----------------------------
//我取0~1之间的随机小数莫名其妙取出了double d1 = 1.1106905110025433E-4
//事实证明,后面的E-4是移动小数点,-1是小数点左移一位,+1是小数点往右移一位
//那么比如double类型的值 12.34E-3 就是0.01234
----------------------------
重点: E是科学计数法,a E b的意思就是a乘以10的b此方
--------------------------------------------------------
关于随机数
计算机不会产生绝对随机的随机数,计算机只能产生“伪随机数”。
其实绝对随机的随机数只是一种理想的随机数
计算机只能生成相对的随机数,即伪随机数。伪随机数并不是假随机数
这里的“伪”是有规律的意思,就是计算机产生的伪随机数既是随机的又是有规律的。
1.计算机的伪随机数是由随机种子根据一定的计算方法计算出来的数值。
所以,只要计算方法一定,随机种子一定,那么产生的随机数就是固定的。
2.只要用户或第三方不设置随机种子,那么在默认情况下随机种子来自系统时钟。
----------------------------
随机数的质量等级
K1——相同序列的概率非常低
K2——符合统计学的平均性,比如所有数字出现概率应该相同,卡方检验应该能通过,
超长游程长度概略应该非常小,自相关应该只有一个尖峰,
任何长度的同一数字之后别的数字出现概率应该仍然是相等的等等
K3——不应该能够从一段序列猜测出随机数发生器的工作状态或者下一个随机数
K4——不应该从随机数发生器的状态能猜测出随机数发生器以前的工作状态
我们一般用的随机数发生器至少要符合K1和K2
而用于加密等应用的随机数发生器应该符合K3和K4。
****************************************************************************************
IO流(Input Output)输入(读) 输出(写)
重点~~~~~~流是用来操作数据的
从cpu的角度想 输入:读 输出:写
IO流用来处理设备之间的数据传输
java对数据的操作是通过流的方式
java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流和字符流
流按流向分为:输入流和输出流
----------------------------
字节流的抽象基类
InputStream OutputStream
字符流的抽象基类
Reader Writer
注:由这四个类派生出来的子类名称都是父类名作为子类名的后缀
如:InputStream 的子类 FileInputStream
Reader 的子类 FileReader
----------------------------
字节流:(操作的都是字节数据)
InputSteram 输入
OutputStream 输出
FileInputSteram 输入(读进来)
FileOutputStream 输出(写出去)
BufferedInputStream 字节流输入缓冲区
BufferedOutputStream 字节流输出缓冲区
字符流:(其实字符流操作的也都是字节数据,不过里面有编码表
以系统中默认码表的为码表
Reader 输入
Writer 输出
FileReader(操作文件) 输入
FileWriter(操作文件) 输出
BufferedReader 字符流输入缓冲区
BufferedWriten 字符流输出缓冲区
--------------------------------------------------------
//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件
//而且该文件会被创建到指定目录下。如果该目录下已有同名的文件,旧的将被覆盖
//其实该操作就是在明确数据要存放的目的地
FileWriter fw=new FileWriter("E:\\demo.txt");//创建一个demo.txt文件
//调用write方法,将字符串写入流中;
fw.write("你好");
//刷新流对象中的缓冲中的数据
//将数据刷到目的地
//fw.flush();
//关闭流资源,但是关闭前会刷新一次内部的缓冲中的数据
//将数据刷到目的地中
//和flush()的区别:flush刷新后,流可以继续使用,close刷新后流会关闭
fw.close();
----------------------------
fr=new FileReader("d:\\Demo.txt");
//调用读取流对象的read()方法,一次读一个字符
//把读取的字符作为整数返回0~65535之间(0x00~0xffff)
//如果以达到流的末尾,则返回-1;
int ch;
while ((ch=fr.read())!=-1){
sop("ch="+(char)ch);
}
----------------------------
fr=new FileReader("d:\\Demo.txt");
//定义一个字符串数组,用于存储读到的字符
//该read(char[])返回的是读到的字符个数;
//如果以达到末尾,则返回-1;
char[] chars=new char[1024];
int num;
while((num=fr.read(chars))!=-1){
sop("num="+num+"---"+new String(chars,0,num));
//从0开始取,取到num的个数
}
--------------------------------------------------------------------------------
字符流的缓冲区
缓冲区的出现提供了对数据的读写效率
对应类:
BufferedWriter
BufferedReader
缓冲区要结合流才可以使用
在流的基础上对流的功能进行增强
缓冲区的技术的原理就是这个对象里面封装了数组
----------------------------
字符串输出流缓冲区 BufferedWriter
缓冲区的出现是为了提高流的操作效率而出现的
所以在创建缓冲区之前,必须要先有对象。
只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可
该缓冲区中提供了一个跨平台的换行符。
newLine(); 换行(多系统通用)
\r\n 换行 windows
----------------------------
字符串输入流缓冲区 BufferedRander
该缓冲区提供了一个一次读一行的方法,方便于对文本数据的获取
readline();
当返回null时表示读到文件末尾
readLine方法返回的时候只返回回车符之前的数据内容,并不返回回车符
----------------------------
两个流之间没有直接关系,需要一个中转站,或者说容器,暂时存放数据
String s;
while ((s=bufr.readLine())!=null){ //输出
bufw.write(s); //写入缓冲区
bufw.newLine(); //换行
bufw.flush(); //刷新缓冲区,写入数据到地址
-------------------------------------------------------
readLine方法的原理
无论是读一行,获取多个字符,其实最终都是在硬盘上一个一个读取的
所以最终使用的还是read()方法一次读一个的方法
--------------------------------------------------------------------------------
装饰设计模式:
当想要对已有的对象进行功能增强时
可以定义一个类,将已有对象传入,基于已有对象的功能,并提供加强功能
那么自定义的该类就称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象
并基于被装饰的对象的功能提供更强的功能
----------------------------
MyReader//专门用于读数据的类(继承体系)
|--MyTextReader //读txt的类
|--MyBufferTextReader //带缓冲区的读txt的类
|--MyMediaReader //读媒体的类
|--MyBufferMediaReader //带缓冲区的读媒体的类
|--MyDateReader //读数据的类
|--MyBufferDateReader //带缓冲区的读数据的类
//这样显得臃肿,单独定一个缓冲区
class MyBufferReader{
MyBufferReader(MyTextReader text){
}
MyBufferReader(MyMediaReader media){
}
MyBufferReader(MyDateReader date){
}
}
上面这个类扩展性很差,后期要不断修改
找到其参数的共同类型,通过多态的形式。可以提供扩展性
class MyBufferReader extends MyReader{
private MyReader r;
MyBufferReader(MyReader r){
this.r=r;
}
}
优化后的体系(这就是装饰设计模式)
MyReader//专门用于读数据的类(新的体系)
|--MyTextReader //读txt的类
|--MyMediaReader //读媒体的类
|--MyDateReader //读数据的类
|--MyBufferReader //缓冲区的类
装饰模式比继承要灵活。避免了继承体系的臃肿
而且降低了类与类之间的关系
装饰类因为是增强已有对象,具备的功能和已有对象是相同的,只不过提供了更强功能
所以装饰类和被装饰类通常都属于一个体系中
装饰类和被装饰类同属于一个父类或者接口
--------------------------------------------------------
字节流的缓冲区
BufferedOutputStream 字节流输出缓冲区
BufferedInputStream 字节流输入缓冲区
缓冲区思想:
从硬盘中取出比如(1024)个字节的文件存入一个数组(缓冲区)
获取数组长度
从数组中取出,每取一次,数组长度减1,当数组长度为0时,再从硬盘中获取数据
当硬盘中获取完数据时,再一次获取数据,数组长度为0
长度减1,为-1;视为数据取完,并返回-1;
--------------------------------------------------------
1111-1111 -->提升为int类型 还是-1 原因是在前面一直补的是1导致的
那么只要在前面补0,就可以了,可以使用 &(与)操作
1111-1111 1111-1111 1111-1111 1111-1111
& 0000-0000 0000-0000 0000-0000 1111-1111
------------------------------------------(保留相同的)
0000-0000 0000-0000 0000-0000 1111-1111
--------------------------------------------------------
long start=System.currentTimeMillis();//程序起始时间
//
long end=System.currentTimeMillis();//程序结束时间
System.out.println((end-start)+"毫秒");
--------------------------------------------------------
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个
通过三个明确来完成
1.明确源和目的
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
2.操作的数据是否是纯文本
是:用字符流
不是:用字节流
3.当体系明确后,在明确要使用哪个具体的对象:
通过设备来进行区分:
源设备:
键盘 System.in
硬盘 FileStream
内存 ArrayStream
目的设备:
控制台 System.out
硬盘 FileStream
内存 ArrayStream
--------------------------------------------------------
1.将一个文本文件中的数据储存到另一个文件中——>复制文件
源:因为是源,所以使用读取流 InputStream Reader
是不是操作文本文件
是!这时就可以选择 Reader
这样体系就明确了
接下来明确要使用该体系中的哪个对象
明确设备:硬盘,上一个文件
Reader体系中可以操作文件的对象是:FileReader
FileReader fr=new FileReader("d:\\1.txt");
是否需要提高效率:是!加入Reader体系中的缓冲区:BufferedReader
BufferedReader bufr=new BufferedReader(fr);
目的:OutputStream Writer
是否是纯文本。
是! Writer
设备:硬盘,一个文件
Writer体系中可以操作文件的对象是:FileWriter
FileWriter fw=new FileWriter("d:\\2.txt");
是否需要提高效率:是!加入Writer体系中的缓冲区:BufferedWriter
BufferedWriter bufw=new BufferedWriter(fw);
--------------------------------------------------------
2.将键盘录入的文件保存到一个文件中
这个需求中有源和目的都存在 分析:
源:InputStream Reader
是不是纯文本? 是! Reader
设备:键盘,对应的对象是System.in
不是选择Reader吗? System.in 对应的不是字节流吗?
为了操作键盘的文本数据方便,转成字符流,按照字符串操作
所以既然明确了Reader 那么就将System.in转成Reader
用Reader体系中转换流,InputStreamReader
InputStreamReader isr=new InputStreamReader(System.in);
需要提高效率吗?需要!就使用BufferedRander
BufferedRander bufr=new BufferedRander(isr);
目的:OutputStream Writer
是否是纯文本?是! Writer
设备:硬盘。一个文件 FileWriter
FileWriter fw=new FileWriter("d:\\2.txt");
需要提高效率吗 需要。
BuffereadWriter bufw=new BuffereadWriter(fw);
-----------------------
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存入到文件中
目的:OutputStream Writer
是否是纯文本?是! Writer
设备:硬盘。一个文件 FileWriter
但是FileWriter是使用的默认编码表GBK
但是存储时,需要加入指定的编码表 utf-8 而指定的编码表只有转换流可以指定
所以要使用的对象是OutputStreamWriter
而该转换流对象要接收一个可以操作文件的字节输出流 FileOutputStream
OutputStreamWriter osw=new OutputStreamWriter(
new FileOutputStream("d:\\2.txt","UTF-8"))
需要提高效率吗 需要。
BuffereadWriter bufw=new BuffereadWriter(osw);
转换流什么时候用。字符和字节之间的桥梁
通常,涉及到字符编码转换时,需要用到转换流
--------------------------------------------------------
File类
用来将文件或者文件夹封装成对象
方便对文件与文件夹的属性信息进行操作
File对象可以作为参数传递给流的构造函数
跨平台的分隔符 File.separator 表示当前系统下的默认分隔符
-----------------------
File类的常见方法
1.创建
boolean createNewFile();
在指定位置创建文件创建文件,如果该文件已经存在,则不创建,返回false
和输出流不一样,输出流对象一建立就会创建文件,而且会覆盖已存在的文件
返回值static File | createTempTest(); 创建临时文件
boolean mkdir() 创建文件夹,只能创建一级目录
boolean mkdirs() 创建多级文件夹,建议使用
2.删除
boolean delete();
删除指定文件,比如a1.delete();就是删除a1指向的地址的文件
void deleteOnExit();
在虚拟机结束时删除指定文件
3.判断
boolean canExecute(); 测试程序是否可执行
boolean isHidden(); 判断是否是一个隐藏文件
boolean isAbsolute(); 判断是否是绝对路径
boolean exists(); 判断文件是否存在
boolean isDirectory(); 判断是否为标准文件夹
boolean isFile(); 判断是否为标准文件
记住在判断文件对象是否是文件或者目的时
必须要先判断该文件对象封装的内容是否存在 通过 exists 判断
4.获取信息
getName(); 获取名称
long length(); 返回对象大小
getPath(); 获取对象的路径
getParent(); 返回绝对路径中的父目录,没有则返回null
getAbosolutePath(); 返回对象的绝对路径
long lastModified(); 返回对象最后一次修改的时间
f1.renameTo(f2) f1的文件名称改为f2的
static File[] listRoots() 列出可用的文件系统根(盘符)
String[] list();返回一个字符串数组,存放的是对象中的所有对象名称
调用list方法的file对象必须是封装一个目录。该目录必须存在
String[] list(FilenameFilter Filter); 文件名过滤,只返回指定文件名
示例:过滤掉所有非 .txt 文件
String[] s= dir.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".txt");
}
});
File[] listFiles(); 同上,不过返回值是File类型的数组
里面的数据可以用File类的方法操作
--------------------------------------------------------
列出指定目录下文件或者文件夹,包含子目录中的内容
也就是列出指定目录下所有内容
因为目录中还有目录,只要使用同一个列出目录功能的方法完成即可
在列出过程中出现的还是目录的话,可以再次调用本功能
也就是函数自身调用自身
这种表现形式,或者编程手法叫做递归
递归要注意:
1.限定条件
2.要注意递归的次数,避免内存溢出
------------------------
Properties是hashtable的子类
也就是说它具备了map集合的特点,而且它里面存储的键值对都是字符串
是集合中和IO技术相结合的集合容器
该对象的特点:可以用于键值对形式的配置文件
Properties加载的必须是键值对,前面带#号的信息,不读取
那么在加载数据时,需要固定的格式:键=值
--------------------------------------------------------
打印流
可以直接操作输入流和文件
该流提供了打印方法,可以将各种数据类型的数据都原样打印
字节打印流
PrintStream
构造函数可以接收的参数类型
1.file对象 file
2.字符串路径 String
3.字节输出流 OutputStraeam
------------------------
字符打印流 (常用)
PrintWriter
构造函数可以接收的参数类型
1.file对象 file
2.字符串路径 String
3.字节输出流 OutputStraeam
4.字符输出流 Writer
--------------------------------------------------------
合并流
SequencelnputStream
对多个流进行合并
--------------------------------------------------------
序列流 操作对象
ObjectInputStream和ObjectOutputStream
被操作的对象需要实现Serializable(接口标记)
没有方法的接口被称为标记接口
设置自定义的UID,为了让修改过的类能操作曾经被序列化的对象
static final long serialVersionUID=42L;
42L就是自己设置的UID
--------------------------------------------------------
管道流
PipedInputStream和PipedOutputstream
输入输出可以直接进行连接,通过结合线程使用
--------------------------------------------------------
RandomAccessFile(多线程下载的原理)
随机访问文件,自身具备读写的方法
通过skipBytes(int x),seek(int x)来达到随机访问
该类不算是IO体系中的子类
而是直接继承自Object
但是它是IO包中的成员,因为它具备读和写的功能
内部封装了一个大型数组,而且通过指针对数组的元素进行操作
可以通过 getFilePointer 获取指针的位置
同时可以通过 seek 改变指针的位置
其实完成读写的原理就是内部封装了字节输入流和输出流
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:"r"只读 "rw"读写
如果模式为只读 r 的话,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常
如果模式为读写 rw 的话,那么要操作的文件不存在,会自动创建,如果存在则不会覆盖。
//调整对象中的指针
//raf.seek(8);
//跳过指定的字节数,skipBytes() 只能往前跳,不能往后跳
//raf.skipBytes(8);
--------------------------------------------------------------------------------
IO包中的其他类
-------------------------------------------
操作基本数据类型的流对象
DataInputStream DataOutputStream
-------------------------------------------
操作字节数组的流对象:用流的读写思想来操作数组
ByteArrayInputStream
在构造的时候,需要接受数据源,而且数据源是一个字节数组
ByteArrayOutputStream
在构造的时候,不用定义数据目的,因为该对象中已经内部封装了一个可变长度的字节数组,这就是数据目的
因为这两个流对象都操作的数组,并没有使用系统资源
所以,不用进行close关闭
在流操作规律讲解时:
源设备:
键盘 System.in
硬盘 FileStream
内存 ArrayStream
目的设备:
控制台 System.out
硬盘 FileStream
内存 ArrayStream
-------------------------------------------
操作字符数组的流对象
CharArrayReader CharArrayWrite
-------------------------------------------
操作字符串的流对象
StringReader StringWriter
--------------------------------------------------------
转换流:
字符流的出现是为了方便操作字符数据
更重要的是加入了编码转换
通过子类转换流来完成
InputStreamReader
OutputStreamWriter
在两个对象进行构造的时候可以加入字符集
----------------------------
编码表的由来
计算机只能识别二进制数据,早期由来是通过电信号
为了方便应用计算机,让它可以识别各个国家的文字
就将各个国家的文字用数字来表示,并一一对应,形成一张表(编码表)
----------------------------
常见的编码表
ASCII :美国标准信息交换码
用一个字节的7位表示
ISO 8859-1:拉丁码表、欧洲码表
用一个字节的8位表示
GB 2312:中国的中文编码表
GBK :中国的中文编码表升级,融合了更多的中文文字符
Unicode :国际标准码,融合了多种文字。
UTF-8 :最多用三个字节来表示已个字符。
************************
比如汉字 "路" ,先使用utf8编码后,得到结果是%e8%b7%af
然后将他的utf8编码(即"%e8%b7%af")进行gb2312解码后变成"璺?"
再对"璺?"进行gb2312编码后变成了"%e8%b7%3f"
已经不是原来的utf8编码,还同时发现不少这样的汉字.
比如"号","司".
请教这种情况为什么发生?又如何能保证不发生?
-------
不合法解码会被替换成'?',也就是0x3f,被改掉了当然转不回去了。
************************
编码:字符串变成字节数组
String-->byte[]; String.getBytes(charsetName);
解码:字节数组变成字符串
byte[]-->String; new String(byte[],charsetName);
*****************************************************************************************
GUI Graphical User Interface(图形用户接口)
用图形的方式,来显示计算机操作的界面,这样更方便更直接
GLI Command line Uesr Interface(命令行用户接口)
就是常见的Dos命令行操作
需要记忆一些常用的命令,操作不直观
举例:
比如:创建文件夹,或者删除文件夹等
Java为GUI提供的对象都存在java.Awt和javax.Swing两个包中。
Awt和Swing
java.Awt:Abstract Window ToolKit(抽象窗口工具包)
需要调用本地系统方法实现功能。属重量级控件。
不同的操作系统使用AWT建立的class文件,产生的图形化界面会有差异
javax.Swing:在AWT的基础上,建立的一套图形界面系统,其中提供了更多的组件
提高了跨平台性,在任何系统中运行都一模一样。
而且完全有Java实现,增强了移植性,属轻量级控件。
Component
|--Button(按钮)
|--Label(标签)
|--Checkbox(复选框)
|--TextComponent(文本组件)
|--TextField(文本框)
|--TextArea(文本区域)
|--Container(容器)
|--Panel(面板)
|--Window(窗口)
|--Frame(框架)
|--Dialog(对话框)
|--FileDialog(文件对话框)
Container:为容器,是特殊组件,该组件中可以通过add方法添加其他组件进来。
--------------------------------------------------------------------------------
容器中的组件的排放方式,就是布局
常见的布局管理器
Flow Layout (流式布局管理器)
从左到右的顺序排列
Panel默认的布局管理器
Border Layout (边界布局管理器)
东,南,西,北,中
Frame默认的布局管理器
Grid Layout (网格布局管理器)
规则的矩阵
Card Layout (卡片布局管理器)
选项卡
GridBag Layout (网格包布局管理器)
非规则的矩阵
-------------------------------------------
创建图形化界面
1.创建frame窗体
2.对窗体进行基本设置
比如:大小,位置,布局
3.定义组件
4.将组件通过窗体的add方法添加到窗体中
5.让窗体显示,通过setVisible(true)
-------------------------------------------
事件监听机制组成
事件源(组件)
事件(Event)
监听器(Listener)
事件处理(引发事件后的处理方式)
事件源:就是Awt包或者Swing包中的那些图形界面组件。
事件:每一个事件源都有自己特有的对应事件和共性事件。
监听器:将可以触发某一个事件的动作(可能不只一个动作)都已经封装到了监听器中
以上三者,在java中都已经定义好了,直接获取其对象来用就行
我们要做的事情是:就是对产生的动作进行处理
*****************************************************************************************
网络通讯要素
1.找到对方IP地址
2.数据要发送到对方指定应用程序上。为了标识这些应用程序,
所以给这些网络应用程序都用数字进行标识。
这个数字叫做端口(逻辑端口)
3.定义通信规则,这个通讯规则称为协议。
国际组织定义了通用协议 TCP/IP。
那么2台计算机只使用一个全球唯一的协议通讯
那么他们直接的通讯就是绝对安全的
本机未配置任何IP地址的情况下
默认的IP地址是127.0.0.1
-------------------------------------------
网咯模型:
OSI参考模型 TCP/IP参考模型
1应用层 1应用层(HTTP/FTP)协议
2表示层
3会话层
4传输层 2.传输层(TCP/UDP)协议
5网络层 3.网际层(IP)协议
6数据链路层
7物理层 4.主机至网络层
-------------------------------------------
IP地址
网络中设备的标识
不容易记忆,可用主机名
本地回环地址:127.0.0.1 主机名:localhost
端口号:
用于标识进程的逻辑地址,不同进程的标识
有效端口:0~65535,其中0~1024系统使用或保留端口
传输协议
通讯的规则
常见协议:TCP,UDP
-------------------------------------------
java.net.InetAddress
|----Inet4Address
|----Inet6Address
IP地址是IP使用的32位或128位无符号数字,它是一种低级协议
,UTP和TCP协议都是在它的基础上构建的。
--------------------------------------------------------------------------------
UDP:
将数据及源和目的封装成数据包中,不需要建立连接
每个数据包的大小在限制在64k内
因无连接,是不可靠协议
不需要建立连接,速度快
由此可见类似以前的QQ聊天就是UDP,对方不在线,我也能发送,
但是数据就丢失了,对方上线也无法接受,而现在有了离线功能,
不在线的数据可能是暂存qq服务器上了。不可能存放在本地,也不可能
存放在对方那里(因为对方不在线),但是对方上线后却能收到,
我认为是存在了服务器上。
-------------
TCP:
建立连接,形成传输数据的通道
在连接中进行大数据量传输
通过3次握手完成连接,是可靠协议
必须建立连接,效率会稍低
TCP 要先确定对方在,对方不在,则不发送信息
3次握手
张三———>"你在吗"———>李四
李四———>"我在"———>张三
张三———>"我知道你在了"———>李四
-------------------------------------------
Socket
Socket就是为网络服务提供的一种机制
通讯的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输
--------------------------------------------------------------------------------
UDP传输
DatagramSocket于DatagremPacket
DatagremSocket:此类表示用来发送和接受数据报包的套接字
DatagremPacket:可以定义数据包,用于存储接收到的数据,并进行分析。
建立发送端,接收端
建立数据包
调用Socket的方送接受方法
关闭Socket
发送端与接受端是两个独立的运行程序
-------------------------------------------
发送端 通过udp传输方式将一段文字数据发送出。
思路:
1.建立udpSocket服务。
2.提供数据并将数据封装到数据报包中。
3.通过Socket服务的发送功能将数据包发出去。
4.关闭资源。
接收端 用于接收udp协议传输的数据并处理
思路:
1.定义udpSocket服务,通常都会监听一个端口,其实就是给这个接收网络应用程序定义一个数字标识。
方便于明确哪些数据过来,该应用程序可以处理。
2.定义一个数据包,因为要存储接收到的字节数据
因为数据包对象中有更多功能可以提取字节数据中不同数据信息。
3.通过Socket服务的receive方法将收到的数据存入已定义好的数据包中
4.通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上
5.关闭资源。
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),52777);
InetAddress.getByName("192.168.1.101")接收端ip
("192.168.1.255")表示发送广播1~255的指定端口52777都能收到。
--------------------------------------------------------------------------------
TCP传输
Socket和ServerSocket
建立客户端和服务器端
建立后,通过Socket中的IO流进行数据的传输
关闭Socket
同样,客户端与服务器端是两个独立的应用程序。
------------------------
客户端:
1.创建客户端的Socket服务,指定目的主机和端口
2.获取Socket流中的输出流。将数据写入该流。通过网络发送到服务端
3.获取Socket流中的输入流,将服务端反馈的数据获取并打印
4.关闭客户端资源。
------------------------
服务端:
1.建立服务端的Socket服务。ServerSocket();
并监听一个端口
2.获取连接过来的客户端对象,
通过ServerSocket的accept方法。
没有连接就会等,所以这个方法是阻塞式的
3.客户端如果发过来数据,那么服务端要使用对象的客户端对象,
并获取到该客户端对象的读取流,并打印在控制台。
4.发送数据到客户端。
5.关闭服务端(可选操作)
--------------------------------------------------------------------------------
www.baidu.com 想要将主机名翻译成ip地址,需要域名解析。DNS
http://127.0.0.1:8080
http://localhost:8080
其实127和loclhost的映射关系就在本机上。
c:\windows\system32\deivers\ext\hosts
先在本地hosts文件找,找不到去网上dos找。
127.0.0.1 本地回环地址。
*****************************************************************************************
java.util.regex.Pattern
正则表达式:符合一定规则的表达式
作用:用于专门操作字符串。
特点:用一些特定的符号来表示一些代码操作,简化书写。
所以学习正则表达式,就是在学习一些特殊符号的使用。
好处:可以简化对字符串的复杂操作
弊端:符号定义越多,正则越长,阅读性越差
具体操作功能:
1.匹配:String类 matches()
用规则匹配整个字符串,只要有一处不符合规则就匹配结束,返回false
//第一位必须是1,第二位只能是3`5`8 ,后面9位为任意数字
String telReg="1[358]\\d{9}";
2.切割:String类 Split()
按照多个空格来进行切割,表达为 " +"
splitDemo("zhangsan lisi wangwu"," +");
按照.来进行切割,表达为 "\\."
因为.在正则表达式中是特殊符号,所以要加转译符 \\
splitDemo("zhangsan.lisi.wangw","\\.");
按照\\来进行切割,表达为 "\\\\",转译符的问题
splitDemo("c:\\abc\\123.txt","\\\\");
按照叠词切,为了可以让规则的结果被重用,可以将规则封装成一个组
用()完成。组的出现都有编号。从1开始。
想要使用已有的组可以通过\n的形式来获取,n就是组的编号,$1也可以
.表示任意字符,"()"封装成一个组,"()\\1"表示1这个组重复1次
"()\\1+"表示这个组重复1次或多次
(A(B(C))(D)) 表达为4组,先出现的左括号为第一组A
splitDemo("jgkkkkduyfgqqqyuwk","(.)\\1");
public static void splitDemo(String str,String reg){
//str表示被切的字符串,reg表示切割方法
//arr数组存放切完后的每一个字符串
String[] arr=str.split(reg);
System.out.println(arr.length);
for(String s:arr){
System.out.println(s);
}
}
3.替换:String类 replaceAll();
//屏蔽出现连续5个数字以上情况,替换成#;
String str="udy13859096843egwea123456";
replaceAllDemo(str,"\\d{5,}","#");
//将叠词替换成#;
String str="udyqqqqegweawwww45aaaa6zzzz";
replaceAllDemo(str,"(.)\\1+","#");
//将叠词替换成单个词,比如aaaaaa替换成a,bb替换成b;用$符号获取组。
String str="udyqqqqegweawwww45aaaa6zzzz";
replaceAllDemo(str,"(.)\\1+","$1");
public static void replaceAllDemo(String str,String reg,String newStr){
str表示要被替换的字符串
reg表示要替换的目标
newStr表示替换成什么
str=str.replceAllDemo(reg,newStr);
System.out.println(str);
}
4.获取:将字符串中符合规则的子串取出
操作步骤:
1.将正则表达式封装成对象
2.让正则对象和要操作的字符串相关联
3.关联后,获取正则匹配引擎
4.通过引擎对符合规则的字串进行操作,比如取出
String str="ming tian jiu yao fang jia le,hao kai xin。";
String reg="\\b[a-z]{3}\\b";
//将规则封装成对象
Pattern p=Pattern.compile(reg);
//让正则对象和要作用的字符串相关联,获取匹配器对象
Matcher m=p.matcher(str);
//boolean b1=m.find();将规则作用到字符串上,并进行符合规则的字串查找
//System.out.println(b1);
//System.out.println(m.group());//用于获取匹配后结果
while(m.find()){
System.out.println(m.group());
System.out.println(m.start()+"...."+m.end());
}
--------------------------------------------------------------------------------