变量

定义变量的方法细则
1.变量必须先声明再使用.

2.定义的什么类型变量,就存储什么类型的数据.

3.变量存在访问范围,同一个范围变量名不能重复.

4.变量定义时可以没有初始化值,但是在使用时必须有初始值.
定义变量名细则

标识符:标识符是由一些字符,符号组合起来的名称,用于给类,方法,变量等起名字的规矩

基本要求:由数字,字母,下划线 (_)和美元符($)等组成

强制要求:不能以数字开头,不能是关键字,区分大小写

命名指导规范:

变量名称:满足标识符规则,建议权英文,有意义,首字母小写,满足驼峰模式.

类名称:满足标识符规则,建议全英文,有意义,首字母大写,满足驼峰模式.

数据类型

数据类型分别为:
1.byte字节型 占一个字节  -128 127

2.short 短整型  占2个字节

3.int 整型 (一般默认使用int)占4个字节

4.long 长整型 8个字节(数字默认为int,若需使用long ,需在数字后面加上L)例:long  a = 112333L

5.浮点型(即是小数) float 单精度 占4个字节(小数默认为double类型,若需使用float类型,需在数字后加上F)

6.double 双精度  占8个字节

7.字符类型 :char

8.布尔类型   boolean
引用数据类型

string

自动类型转换

类型范围小的变量,可以直接赋值给类型范围大的变量.

例: byte a =20;

int b = a ----此处发生自动类型转换

输出后,a,b都等于20;

自动转换的2种形式

1: byte ---short-----int----long------float-------double

2: char-----int;

表达式的自动类型转换

1.小范围的类型会自动转换成大范围的类型计算

2.表达式的最终类型由表达式中的最高类型决定

  1. byte,short,char 是直接转换成int类型参与运算的.

例1: byte a =10;

int b =20;

 double c=1.0;

double rs = a+b+c; --------最终表达式类型由式子中出现的最高类型决定.

例2: byte i=10;

byte j=20;

byte k= i+j -------看似无错,实则有错,需用int

(int k =i+j)-----完全正确

这是因为,byte,short,char,是直接转

强制类型转换

可以强行将范围大的变量,数据赋值给类型范围小的变量.

格式为:数据类型 变量 =(数据类型)变量,数据

强制类型转换可能会出现数据丢失,以及小数强制转换成整数是直接截断小数保留整数

算术运算符

常规运算符

'+' '-' '*' '/' '%'

需要注意,俩个整数相除,其结果一定是整数,因为运算类型为整数,如果想要得到小数,需在被除数上 乘 1.0.

例:int a=10;

int b=3;

system.out.println (a * 1.0 / b)=3.3333

 

衍射1:拆分数字

例:int a =589;需拆分 个 十 百,三位,分别输出

int gw =a %10;

system.out.println(gw);

int sw =a /10%10;

system.out.println(sw);

int bw =a/100;

system.out.println(bw);

 

衍射2:连接符

'+'这个符号,除了做基本数学运算,还能做连接符

1.与字符串做 + 运算时会被当成连接符,其结果还是字符串

2.能算则算,不能算就连在一起.

例:

int a=5;
System.out.println("abc"+'a');
System.out.println("abc"+a);
System.out.println(5+a);
System.out.println("abc"+5+'a');
自增自减运算符

++,-- (对变量值 + 1或 - 1)

1.如果运算符单独使用,那么放前放后没有区别,都是给变量加1.

2.非单独使用时,分俩种情况.

(1)在变量前,先进行变量自增或自减,再使用变量.

(2)在变量后,先使用变量,再进行变量自增或自减.

例: int a=10;

a++ 或 ++a ----------(输出结果a都等于11,这是因为运算符单独使用.)

int a=10;

b=a++; ---------(输出结果b=10,a=11,因为运算符,在不是单独运算.同理++a时,b=11,a=11.)

基本赋值运算符

+= 加后赋值 a+=b 等价于 a=(a的数据类型)(a+b);即将a+b的值给a

-= 减后赋值 a-=b 等价于 a=(a的数据类型)(a-b);即将a-b的值给a

*= 后赋值 a=b 等价于 a=(a的数据类型)(ab);即将ab的值给a

/= 除后赋值 a/=b 等价于 a=(a的数据类型)(a/b);即将a/b的值给a

%= 取余后赋值 a%=b 等价于 a=(a的数据类型)(a%b);即将a%b的值给a

关系运算符

== a==b,判断a和b的值是否相等,成立为true,不成立为false

!= a!=b,判断a和b的值是否不相等,成立为true,不成立false

》 a》b,判断a是否大于b,成立为true,不成立为false

》= a>=b,判断a是否大于等于b,成立为true,不成立为false

< a<b,判断a是否小于b,成立为true,不成立为false

<= a<=b,判断a和b的值是否相等,成立为true,不成立为false

逻辑运算符

& 逻辑与 必须都是true,结果才是true;只有一个是false,结 果一定是false。

| 逻辑或 只要一个为true,结果就是true

! 逻辑非 你真我假,你假我真。!true=false,!false=true

^ 逻辑异或 如果俩个条件都是false,或者都是true则结果是 false。俩个条件不同结果是true.

 

&& 短路与 判断结果与&一样。过程是左边为false,右边就不执行.

|| 短路或 判断结果是|一样。过程是左边为true,右边则不执行

三元运算符

格式:条件表达式 ?值1:值2;

首先计算关系表达式的值,如果值为true,返回值1,如果为false,返回值2.

例:

int i=10;
int j=20;
int k=30;
int max =i > j ? (i > k ? i : k) :j > k ? j : k);
System.out.println(max);
运算符优先级

& > ^ > | > && > || > ? :(括号永远优先)

分支结构

if

格式1: if(条件表达式){ 语句体;}

格式2: if(条件表达式){ 语句体1} else{ 语句体2;}

格式3: if(条件表达式){ 语句体1;} else if(条件表达式2)

{语句体2;}else if (条件表达式3){语句体3;}

switch

格式:switch(表达式){

case值1:

执行代码;

break;

case值2:

执行代码;

break;

……

default:

执行代码;

}

注意事项:

表达式类型只能是byte,short,int,char,不支持double,float,long.

ase给出的值不允许重复,且只能是字面量,不能是变量.

不要忘记写break,否则会出现穿透现象

 

pay:穿透现象可解决代码繁杂的问题.即存在多个case分支的功能代码是一样时,可以用穿透性把流程集中到同一处处理,用次简化代码

例:

int month = 7;
switch (month) {
   case 1:
   case 3:
   case 5:
   case 7:
   case 8:
   case 10:
   case 12:
       System.out.println(month + "月是31天");
       break;
   case 2:
       System.out.println(month + "闰年28天,非闰年29天");
       break;
   case 4:
   case 6:
   case 9:
   case 11:
       System.out.println(month + "是30天");
}

循环结构

for循环

控制一段代码反复执行很多次.

格式:for(初始化语句;循环条件;迭代语句){ 循环体语句-即需重复执行的代码; }

例: for(int i=0;i<3;i++){ system.out.println("Hello World') }

while循环

格式: 初始化语句:

while(循环条件){

循环体语句;

迭代语句;

}

例:

double shan=8848;
double zhi=0.1;
int count=0;
while (zhi<shan){
   zhi*=2;
   count++ ;

for循环与while循环功能上完全一样,for能解决的while也能解决,反之亦然.

知道循环几次则用for,不知道循环次数建议用while.

do-while

先执行一次再判断循环条件.

格式:初始化语句;

do{

循环体语句;

迭代语句;

}while(循环条件);

例:

int i=0;
do{
   System.out.println("hello world");
   i++;
}
while(i<5);
三种循环的区别

for循环和while循环(先判断后执行)

do....while(第一次先执行再判断)

死循环

1.while(true){

System.out.paintln("hello world");

}

2.for(; ;){

System.out.paintln("hello world");

}

  1. do{

System.out.paintln("hello world");

}while(true);

共三种,推荐使用第一种while(true),后面这两种一般不使用.

跳转控制语句介绍

break:跳出并结束当前所在循环的执行.

continue:用于跳出当前循环的当次执行,进入下一次循环.

注意事项:

break:只能用于结束所在循环,或者结束所在switch分支的执行。

continue:只能在循环中进行使用.

Random随机数技术

作用:用于在程序中获取随机数技术.

使用步骤:

1.导包

2.写一行代码代表得到随机数对象.

3.调用随机数的功能获取0到()的随机数

注意:

nextint(n)功能只能生成:0至n-1的随机数,不包含n.

Random生成随机数的特点

nextint(n)功能只能生成:0-(n-1)之间的随机数.

Random生成区间随机数的技巧:减加法.

例:要生成1到10的随机数,

先减去1,即0到9,再加上1.即

int n= r.nextInt(10)+1;
System.out.println(n);

例2:生成65到91之间的随机数.

65 - 91 =》 ( 0 - 26)+65

int n= r.nextInt(27)+65;

()内的数是在范围上加一,参考前面.

数组

静态化初始数组格式

数据类型[] 数组名 ={元素1,元素2,元素3,....};

例:int[] ages ={12,24,36};

数组的访问:

数组名称[索引]

例:int [] arr={12,24,36};

System.out.println(arr[0]); ----------输出的是12

二次赋值:

arr[2]=100;

System.out.println(arr[2]);------------输出的是100

数组的最大索引就是 数组名 length -1 ---------前提元素个数大于0;

动态初始化的格式

数据类型[] 数组名 =new 数据类型[长度];

例:int [ ] ages = new int[4];

pay:

当前已知道存入的元素值,用静态初始化.

当前还不清楚要存入哪些数据,用动态初始化.

数组的3个注意

1:数据类型 [] 数组名 也可以写成数据类型 数组名 []

int[] ages=....;

int ages[]=......;

2.什么类型的数组存放什么类型的数据,否则报错.

int [] arrs ={30,43,50}

3.数组一旦定义出来,程序执行的过程中,长度,类型就固定了.

数组元素默认值规则

基本类型;byte,short,char,int,long -----默认值为0;

float,double -------默认值为0.0;

               boolean                                   --------默认值为false;

引用类型:类,接口,数组,string ------------null;

两个初始化的使用场景总结,注意事项说明:

动态初始化:只指定数组长度,后期赋值,适合开始知道数据的数量,但是不确定具体元素值得业务场景.

静态初始化:开始就存入元素值,适合一开始就能确定元素值得业务场景.

两种格式的写法独立,切记不可混用.

数组遍历

意义:一个一个的把数据访问一遍.

用for循环可遍历数组.加粗部分意义为最大数组长度.

例:int [] ages ={20,32,40,52}

for(int i=0;i<ages.length;i++){

System.out.println(ages[i]);

}

方法

方法格式

格式: 修饰符 返回值类型 方法名(形参列表){

方法体代码----也就是需要执行的功能代码

return 返回值;

}

1.方法的修饰符:暂时都使用public static 修饰

2.方法申明了具体的返回值类型,内部必须使用return返回对应类型的数据.

3.形参列表可以有多个,甚至可以没有;如果有多个形参,必须用 ---,逗号----隔开,且不能给初始化值.

4.方法的执行:必须进行调用;

调用格式: 方法名称( ……括号内添加数据 )

方法定义时:返回值类型,形参列表可以按照需求进行填写.

注意事项

1.如果方法不需要返回结果,返回值类型必须申明void(也就是无返回值),此时方法内部不能使用return.

2.方法如果没有参数,或者返回值类型申明为void可以称为无参数,无返回值的方法,以此类推.

方法常见问题

1.方法的编写顺序无所谓.

2.方法与方法之间是平级关系,不能嵌套定义.

3.方法的返回值类型为void(无返回值),方法内则不能使用return返回数据,如果方法的返回值类型写了具体类型,方法内部则必须使用return返回对应类型的数据.

4.return语句下面,不能编写代码,因为永远执行不到,属于无效代码.

5.方法不调用就不执行,调用时必须严格匹配方法的参数情况.

6.有返回值的方法调用时可以选择定义变量接收结果,或者直接输出调用,甚至直接调用;无返回值的方法调用只能直接调用一下

方法定义的技巧说明

修饰符:public static

方法名称:自己取名,有意义,英文小写,驼峰模式。(有意义皆可)

方法体代码:完成自己需要写的功能代码即可.(具体要求具体实现)

真正需要关注的就俩点:

1.分析方法是否需要申明返回值类型

2.分析方法是否需要接收参数.

方法的参数传递机制

形参:以方法为例,就是方法定义时的变量

实参:在方法内部定义的变量.

值传递:传输的是实参存储的值.

基本类型的参数传递与引用类型的参数传递的区别:

1.两者都是值传递.但基本类型的参数传输存储的数据值,而引用类型的参数传输存储的地址值.

 

方法重载

同一个类中,多个方法的名称相同,形参列表不同.

使用方法重载的好吃是,对于相似功能的业务场景,可读性好,方法名称相同提示是同一类型的功能,通过形参不同实现功能差异化的选择,这是一种专业的代码设计.

识别方法重载的关键要求:同一个类中,多个方法的名称相同,形参列表不同,其他无所谓.

形参列表不同指的是:形参的个数,类型,顺序不同,不关心形参的名称.

 

return关键字单独使用

单独使用时,可立即跳出并结束当前方法的执行;return关键字单独使用可放在任何方法中.

 

需要直接结束当前方法的执行的3种方法:

  1. return;跳出并立即结束所在方法的执行.

  2. break;跳出并结束当前所在循环的执行.

  3. continue;结束当前所在循环的当次继续,进入下一次执行.

面向对象

类:是共同特征的描述;

对象:是真实存在的具体实例.

格式:

public class 类名{

1.成员变量(代表属性的,一般是名词)

2.成员方法(代表行为的,一般是动词)

}

创建对象语法:

类名 对象名 = new 类名();

访问对象信息:直接用 . 连接

对象.成员变量;

对象.成员方法

定义类的补充注意事项:

1.类名首字母建议大写,且有意义,满足驼峰模式.

2.一个java文件中可定义多个class类,但只能一个类是public修饰,而且public修饰的类名必须成为代码文件名.

----------实际开发中建议还是一个文件定义一个class类.

3.成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始化值;------------------ 一般无需指定初始化值,存在默认值

构造器的作用

作用:定义在类中的,可以用于初始化一个类的对象并返回对象的地址.

格式: 修饰符 类名(形参列表){

....}

调用构造器得到对象的格式: 类 变量名称 = new 构造器;

例:Car c = new Car();

构造器的分类和作用:

1.无参数构造器(默认存在的):初始化对象时,成员变量的数据均采用默认值.

2.有参数构造器:在初始化对象的时候,同时可以接收参数为对象进行赋值.

注意事项:

1.任何类定义出来,默认就自带了无参数构造器,写不写都有.

2.一旦定义了有参数构造器,无参数构造器就没有了,此时就需要自己写无参数构造器了.

this关键字

作用:可以用于指定访问当前对象的成员变量,成员方法

当this出现在构造器和成员方法中,代表当前对象的地址.

 

面向对象的三大特征: 封装,继承,多态.

封装:

意义:告诉我们,如何正确设计对象的属性和方法.

原则:对象代表什么,就得到封装对应的数据,并提供数据对应的行为.

理解封装思想的好处:

1.让编程变得很简单,有事,找对象,调方法就能解决.

2.降低我们的学习成本,可以少学,少记,或者说压根不用学.,不用记对象的那么多方法,有需要时去找就行.

 

进行更好封装的办法:

1.一般建议对成员变量使用private(私有,隐藏)关键字修饰(private修饰的成员只能在当前类中访问)

2.为每个成员变量提供配套public修饰的 getter,setter方法暴露其取值和赋值.

javaBean---实体类

意义:称为实体类,其对象可以用于在程序中封装数据.

标准javaBean 须满足如下书写要求:

1.成员变量使用 private修饰.

2.提供成员变量对应的set..()或 get..()方法.

3.必须提供一个无需构造器,有参数的构造器可写可不写.

API

String概述

String类定义的变量可以用于指向字符串对象,然后操作该字符串.

java程序中的所有字符串文字(“ ”------即双引号)都为此类的对象.

pay: String类其实常被称为不可变字符串类型,它的对象在创建后不能被更改.--------这是因为String变量每次的修改其实都是产生并指向了新的字符串对象,原来的字符串对象都是没有改变的,所以称不可变字符串.

创建字符串对象的2种方式

1.直接用 “ ’‘ 定义(推荐使用)例:String name ="深渊"

2.通过String类的构造器创建对象.

例:public String () 空白字符串对象,不含有任何内容

public String(char[] chs) 根据字符串数组的内容,来创建字符串对象。

public String(byte[] chs)根据字节数组的内容,来创建字符串对象.

pay:以双引号("")方式给出的字符串对象,在字符串常量池中存储,相同内容只会在其中存储一份. 而通过构造器new对象,每new一次都会产生一个新对象,放在堆内存中.

字符串的内容比较:

推荐使用String类提供的"eqquals"比较:只关心内容一样即可.

例:

okname.equals(name)&&okpassword.equals(password)

String常用API

1.public int length ( ) 返回此字符串的长度

2.public char charAt(int index) 获取某个索引位置处的字符

3.public char [] tocharArray( ) 将当前字符串转换成字符数组返回

4.public String substring(开始索引,结束索引) 根据开始索引和结束索引进行截取,得到新的字符串(包前不包后)

5.public String substring(传入的索引) 从传入的索引处截取,截取到末尾,得到新的字符串.

6.public String replace()使用新值,将字符串中的旧值替换,得到新的字符串.

7.public String[] split() 根据传入的规则切割字符串,得到的字符串数组返回.

Arraylist--泛型

Arraylist

创建集合对象:Arraylist list(可变)=new Arraylist();

添加数据: list . add("")-----由上文而来

指定位置添加数据: list . add(1,"")----此处数字为在数组中的位置,即是在此处添加数据.

泛型概述

Arraylist<E>:其实就是一个泛型类,可以在编译阶段约束集合对象只能操作某种数据类型.

例:Arraylist<String>:此集合只能操作字符串类型的元素.

Arraylist<Integer>:此集合只能操作整数类型的元素.

pay:集合中只能存储引用类型,不支持基本数据类型.

统一Arraylist集合操作的元素类型时:使用泛型<数据类型>

例:Arraylist<String>list =new Arraylist();

Arraylist 集合常用方法
  1. get(索引位置--即数字) 返回指定索引处的元素

  2. size() 返回集合中的元素的个数

  3. remove(索引位置) 删除指定索引处的元素,返回被删除的元素.

  4. set(指定索引位置,修改后的元素) 修改指定索引处的元素,返回被修改的元素.

  5. remove( 元素 ) 直接删除元素值,删除成功返回true,失败false.

pay:

遍历并删除元素:

1.完美方法一:遍历一个,倒退一个.

//98,90,78,56,77,79
for (int i = 0; i < list.size(); i++) {
   int car=list.get(i);
   if (car<80){
       list.remove(i);
       i--;
  }
}

2.完美方法二:从末尾遍历

//98,90,78,56,77,79
for (int i =list.size()-1;i>=0; i--) {
   int ccc= list.get(i);
   if(ccc<80){
       list.remove(i);
  }
}

static

静态

静态的意思,可以修饰成员变量和成员方法.

static修饰成员变量表示该成员变量只在内存中存储一份,可以被共享访问,修改.

推荐使用方法:类名 . 静态成员变量

成员变量的分类和访问:

1.静态成员变量(有static修饰,属于类,加载一次,可被共享访问)

2.实例成员变量(无static修饰,属于对象) 即对象 . 实例成员变量

成员方法分类及访问

1.静态成员方法: 需表示在线人数等需共享的信息使用静态成员变量

若该方法是以执行一个通用功能为目的,或者需要方便访问,则申明成静态方法

2.实例成员方法:需表示属于每个对象,且每个对象的该信息不同时(如:name,age,money等)

表示对象自己的行为的且方法中需要直接访问实例成员,则该方法必须申明成实例方法.

static访问注意事项

1.静态访问只能访问静态的成员,不可以直接访问实例成员.

2.实例方法可以访问静态的成员,也可以访问实例成员.

3.静态方法中是不可以出现this关键字的.

工具类

类中都是一些静态方法,每个方法都是以完成一个共用的功能为目的,这个类用来给系统开发人员共同使用.

使用工具类的好处:

1.调用方便

2.提高代码复用----即一次编写,处处可用.

 

工具类定义时的其他要求:

由于工具里面都是静态方法,直接用类名即可访问,因此,工具类无需创建对象,建议将工具类的构造器进行私有化.---即 加 private

代码块概述

代码块是类的5大成分之一,定义在类中方法外.

在java类下,使用 {} 括起来的代码称为代码块.

静态代码块

格式:static { }

特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发只执行过一次.

使用场景:在类加载的时候做一些静态初始化的操作,以便后续使用.

构造代码块

格式: { }

特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行

使用场景:初始化实例资源

单例模式

保证在系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象.

饿汉单例设计模式:在用类获取对象的时候,对象已经提前为你创建好了.

设计步骤:

1.定义一个类,把构造器私有.

2.定义一个静态变量存储一个对象.

懒汉单例设计模式:在真正需要该对象的时候,才去创建一个对象(延迟加载对象)

设计步骤:

1.定义一个类,把构造器私有.

2.定义一个静态变量存储一个对象.

3.提供一个返回单例对象的方法

继承

意义:java中提供一个关键字extends,用这个关键字,我们可以让一个类和另外一个类建立起父子关系.

例:public class Student extends People{}

--- -即Student 可使用People所有属性和方法

1.Student 称为子类(派生类),People称为父类(超类)

作用:当子类继承父类后,就可以直接使用父类公共属性和方法.

继承的好处:提高代码复用性,减少代码冗余,增强类的功能扩展性.

设计规范

1.子类们相同特征(共性属性,共性方法)放在父类中定义.

2.子类独有的属性和行为应该定义在子类自己里面.

继承的特点

1.子类可以继承父类的属性和行为,但是子类不能继承父类的构造器.

2.java是单继承模式:即一个类只能继承一个直接父类.

3.java不支持多继承,但是支持多层继承.

4.java中所有的类都是Object类的子类.

 

子类可以继承父类的私有成员即(private)只是不能直接访问.

子类可以直接使用父类的静态成员(共享)但并不算继承,共享并非继承.-----------这是有争议的知识点.

Object特点

java中所有类,要么直接继承了Object,要么默认继承了Object,要么间接继承了Object,Object是祖宗类.

注意事项:

1.在子类方法中访问成员(成员变量,成员方法)满足:就近原则

具体方法:

1.先子类局部范围找.

2.然后子类成员范围找.

3.然后父类成员范围找,如果父类范围还没有找到则报错.

 

2.pay:一定要使用子类中的元素,使用 this 前缀,在子类中一定要使用父类的元素则使用 super 前缀.

方法重写

意义:在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法.

应用场景:当子类需要父类的功能,但父类的该功能不完全满足自己的需求时. 子类可以重写父类中的方法.

重写注解:@Override

1.@Override是放在重写后的方法上,作为重写是否正确的校验注解.

2.加上该注解后如果重写错误,编译阶段会出现错误提示.

3.重写方法都加@Override注解,使代码安全,优雅!

4.切记重写方法的名称,形参列表必须与被重写方法的名称和参数列表一致.

1.包是用来分门别类的管理各种不同类的,类似于文件夹,建包利于程序的管理和维护.

2.建包的语法格式:package公司域名倒写.技术名称.建议全英文小写且具有意义.

3.建包语句必须在第一行,一般IDEA会帮助创建.

pay:导包

1.相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!导包格式;import包名.类名;

2.假如一个类中需要用到不同类,而这两个类的名称一样,那么默认只能导入一个类,另一个类带详细地址即包名访问.

权限修饰符

1.这是用来控制一个成员能够被访问的范围.

2.可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制

3.四种作用范围由小到大:private--->缺省---->protected---->public.

1.定义私有的成员:private只能本类访问.

2.定义缺省修饰的成员:只能本类中,同包下其他类访问(包访问权限)

3.protected修饰方法:本类,同包的其他类中,其他包的子类中.

4.public修饰的方法,本类,同包的其他类中,其他包的子类中,其他包的无关类中.

fincal

作用:表示最终的意思,可以修饰(类,方法,变量)

修饰类:表明该类是最终类,不能被继承.

修饰方法:表明该方法是最终方法,不能被重写.

修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)

final修饰变量的注意:

1.final修饰的变量是基本类型:变量存储的数据值不能发生改变.

2.final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的.

常量

1.常量是使用了public static final 修饰的成员变量,必须有初始值而且执行的过程中其值不能被改变.

2.常量的作用和好处:可以用于做系统的配置消息,方便程序的维护,同时也能提高可读性.

3.变量命名规范:英文单词全部大写,多个单词下划线连接起来.

枚举

1.枚举是java中的一种特殊类型

2.枚举的作用:做信息的标志和信息的分类.----枚举做信息标志和分类时,代码可读性好,入参约束严谨,代码优雅,是最好的信息分类技术!

定义枚举类的格式:

修饰符 enum 枚举名称{

            第一行都是罗列枚举类实例的名称.

}

例: enum Season{

SPRING,SUMMER,AUTUMN,WINTER;

}

抽象类

1.在java中 abstract是抽象的意思,可以修饰类,成员方法.

2.abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法.

例:修饰符 abstract class 类名{

修饰符 abstract 返回值类型 方法名称(形参列表)

}

实例1:抽象的使用场景

1.抽象类可以理解成不完整的设计图,一般作为父类,让子类来继承.

2.当父类知道子类一定要完成某些行为,但是每个子类该行为的实现又不同,于是该父类就把该行为定义成抽象方法的形式,具体实现交给子类完成,此时这个类就可以声明成抽象.

接口的定义与特点

格式: public interface 接口名{

//常量

//抽象方法

}

用法:接口是用来被类实现(implements)的,实现接口的类称为实现类.实现类可以理解成所谓的子类.

例:修饰符 class 实现类 implements 接口1,接口2,接口3,...{}

实现的关键字:implements

pay:

1.接口可以被类单实现,也可以被类多实现.

2.一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类.

总结:

类和类的关系-----单继承.

类和接口的关系---多实现

接口和接口的关系---多继承,一个接口可以同时继承多个接口.

接口多继承的作用:规范合并,整合多个接口为同一个接口,便于子类实现.

jdk新增3种方法

都默认被public修饰

1.默认方法:类似于之前写的普通实例方法,必须用default修饰.会默认public修饰,但需要用接口的实现类的对象来调用.

例:default void run(){

System.out.printin("--开始跑--")

}

2.静态方法:默认public修饰,必须使用static修饰.接口的静态方法必须用本身的接口名来调用.

例:static void inaddr(){

System.out.println("天天开心")

}

3.私有方法:就是私有的实例方法,必须使用private修饰---从jdk1.9才开始. 只能在本类中被其他的默认方法或者私有方法访问

例:private void go(){

System.out.println("我爱java")

}

接口的注意事项

1.接口不能创建对象.

2.一个类实现多个接口,多个接口中有同样的静态方法不冲突.

3.一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,此时默认用父类的.

4.一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可.

5.一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承.

多态

同类型的对象,执行同一个行为,会表现出不同的行为特征.

常见格式: 父类名称 对象名称 = new 子类构造器;

             接口         对象名称 = new 实现类构造器;

多态中成员访问特点:

1.方法调用:编译看左边,运行看右边.

2.变量调用:编译看左边,运行也看左边.(多态侧重行为多态)

优势:在多态形式下,右边对象可以实现解耦合,便于扩展和维护.

例:

Animal a = new Dog();

a.run();//后续业务行为随对象而变,后续代码无需修改.

定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利.

使用多态会产生的一个问题:多态下不能使用子类的独有功能.

 

自动类型转换(从子到父):子类对象赋值给父类类型的变量指向.

强制类型转换(从父到子):此时必须进行强制类型转换,

子类 对象变量 =(子类)父类类型的变量

作用:可以解决多态下的劣势,可以实现调用子类独有的功能.

注意:如果转型后的类型和对象真实类型不是同一种类型,那么在转换的时候就会出现 ClassCastException.

例:Animal t = new Tortoise();

Dog d =(Dog) t; //------出现异常ClassCastException

java建议强制转换前使用 instanceof 判断当前对象的真实类型,再进行强转转换.

变量名 instanceof 真实类型-------判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true,反之.

例:if(a2 instanceof Tortoise){

Tortoise t =( Tortoise) a2;

t.layEggs();

}else if(a2 instanceof Dog){

Dog d= new Dog();

d.lookDoor();

}-----------强转之前先判断.

内部类

意义:内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主).

内部类的使用场景及作用:

1.当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构可以选择使用内部类来设计.

2.内部类通常可以方便访问外部类的成员,包括私有的成员.

3.内部类提供了更好的封装性,内部类本身就可以用private,protectecd等修饰,封装性可以做更多控制.

静态内部类

1.有static修饰,属于外部类本身.

2.它的特点和使用与普通类完全一样,类的成分他都有,只是位置在别人里面而已.

例:public class Outer{

public static class inner{

}

}

静态内部类创建对象的格式:

外部类名.内部类名 对象名 = new 外部类名.内部类构造器;

例:Outer. inner in = new Outer.inner();

 

静态内部类的访问拓展:

1.静态内部类中可以直接访问外部类的静态成员,外部类只有一份可以被共享访问.

2.静态内部类中不能直接访问外部类的实例成员,外部类的实例成员必须用外部类对象访问.

成员内部类

1.无static修饰,属于外部类的对象.

2.jdk16之前,成员内部类中不能定义静态成员,jdk16开始定义静态成员.

例: public class Outer{

    public class  inner{

}

}

成员内部类创建对象的格式:

外部类名.内部类名 对象名 = new 外部类构造器.new内部类构造器();

例:Outer.inner in = new Outer().new inner();

成员内部类的访问拓展:

1.成员内部类可以直接访问外部类的静态成员,外部类静态成员只一份可以被访问.

2.成员内部类的实例方法可以直接访问外部类的实例成员,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员

pay:在成员内部类中访问所在外部类对象,格式:外部类名.this

匿名内部类

1.本质上是一个没有名字的局部内部类,定义在方法中,代码块中,等.

2.作用:方便创建子类对象,最终目的为了简化代码编写.

格式:new 类|抽象类名|或者接口名(){

重写方法;

}

例:Employee a = new Employee(){

public void work(){

}

};

a.work();

3.匿名内部类可以作为方法的实际参数进行传输.

4.使用匿名内部类的本质是为了简化代码.

常用API

Object类的作用

1.一个类要么默认继承了Object类,要么间接继承了Object类,Object类是java中的祖宗类.

2.Object类的方法是一切子类都可以直接使用的,所以我们要学习Object类的方法.

Object类的常用方法

一:toString方法

public String toString() 默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址

问题引出:

1.开发中直接输出对象,默认输出对象的地址其实是毫无意义的.

2.开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息.

toString存在的意义:父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息!!

二:equals方法

public Boolean equals(Object 0) 默认是比较当前对象与另一个对象的地址是否相同,相同则返回true,不同返回false.

equals存在的意义:父类equals方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则.

 

Objects概述
  1. Objects类与Object还是继承关系,Objects类是从JDK1.7开始之后才有的.

  2. Objects的equals方法比较的结果是一样的但是更安全.

pay:对对象内容进行比较的时候建议使用Objects提供的equals方法,虽然比较的结果是一样的,但是更安全.

StringBuilder概述

1.StringBuilder是一个可变的字符串类,我们可以把它看成是一个对象容器.

2.作用:提高字符串的操作效率,如拼接,修改.

StringBuilder构造器

public StringBuilder() 创建一个空白的可变的字符串对象,不包含任何内容.

StringBuilder(String str) 创建一个指定字符串内容的可变字符串对象.

StringBuilder常用方法:

public StringBuilder append(任意类型) 添加数据并返回StringBuilder对象本身.

public StringBuilder reverse() 将对象的内容反转

public int length() 返回对象内容长度

public StringBuilder() 通过toString()就可以实现把StringBuilder转换为String.

Math类

1.包含执行基本数字运算的方法,Math类没有提供公开的构造器.

2.类中成员都是静态,则通过类名直接调用.

Math类的常用方法

Public static int abs(int a) 获取参数绝对值

Public static double ceil (double a) 向上取整

Public static double floor(double a) 向下取整

Public static int round (float a) 四舍五入

Public static int max ( inta,intb) 获取两个int值中的较大值.

Public static double pow (double a ,double b) 返回a的b次幂值

Public static double random() 返回值为double的随机值,范围[0.0 , 1.0)

System 类概述

1.System的功能是通用的,都是直接用类名调用即可,所以System不能被实例化.

System类的常用方法

public static void exit (int status) 终止当前运行的java虚拟机,非零表示异常终止.---------慎重使用.

public static void currentTimeMillis() 返回当前系统的时间毫秒值形式

public static void arraycopy( 数据源数组,起始索引,目的地数组,起始索引,拷贝个数) 数组拷贝

科普pay:

时间毫秒值

1.计算机认为时间是有起点的,起始时间是1970年1月1日00;00:00

2.时间毫秒值:指的是从1970年1月1日走到此刻的总的毫秒数

1s = 1000ms.

因此1970年1月1日算c语言的生日.

BigDecimal

作用:用于解决浮点型运算精度失真的问题

使用步骤:

1.创建对象BigDecimal封装浮点型数据(最好的方式是调用方法)

public static BigDecimal valueof(double val): 包装浮点数成为BigDecimal对象.

BigDecimal常用API:

public BigDecimal add(BigDecimal b) 加法

public BigDecimal subtract(BigDecimal b) 减法

public BigDecimal multiply(BigDecimal b) 乘法

public BigDecimal divide (BigDecimal b) 除法

public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式) 除法

Data类概述

1.Date类的对象在java中代表的是当前所在系统的此刻日期时间.

Date的构造器

public Date() 创建一个Date对象,代表的是系统当前此刻日期时间.

Date的常用方法

public long getTime() 获取时间对象的毫秒值.

Date类记录时间的2种形式:

形式1:日期对象

Date d = new Date();----------创建一个日期对象代表当前系统此刻日期时间对象

System.out.println(d);

形式2:时间毫秒值

指的是从1970年1月1日走到此刻的总毫秒数.

long time = d.getTime();

System.out.println(time);

时间毫秒值转换为日期对象方法:

1.public Date(long time--有参构造器) 将时间毫秒值转换成Date日期对象.

2.public void setTime(long time) 设置日期对象的时间为当前时间毫秒值对应的时间.

SimpleDateFormat的构造器

public SimpleDateFormat() 构造一个SimpleDateFormat,使用默认格式.

public SimpleDateFormat(String pattern) 构造一个SimpleDateFormat,使用指定的格式.

SimpleDateFormat的格式化方法:

 

public final String format(Date date) 将日期格式化成日期/时间字符串.

public final String format(object time) 将时间毫秒值变成日期/时间字符串.

 

格式化的时间形式的常用的模式对应关系如下:

y 年

M 月

d 日

H 时

m 分

s 秒

填充时间数据格式必须对仗.

例:2020-11-11 13:27:06---------yyyy-MM-dd HH:mm:ss

2020年11月11日 13:27:06-------yyyy年MM月dd日 HH:mm:ss

Calender概述

1.calender代表了系统此刻日期对应的日历对象.

2.calender是一个抽象类,不能直接创建对象.

 

calender常用方法:

public int get( int field) 取日期中的某个字段信息.

public void set (int field , int value)修改日历的某个字段信息.

public void add(int field,int amount)为某个字段增加/减少指定值

public final Date getTime() 拿到此刻日期对象.

public long getTimeInMillis() 拿到此刻时间毫秒值.

新增API

jdk8之后修改的相关的API

新增日期类:

LocalDate:不包含具体时间的日期

LocalTime:不含日期的时间.

LocalDateTime:包含了日期及时间

Instant:代表的是时间戳.

DateTimeFormatter 用于做时间的格式化和解析的.

Duration:用于计算两个"时间" 间隔

period:用于计算两个"日期" 间隔

 

1.LocalDateTime综合了LocalDate和LocalTime里面的方法

2.使用方法返回的是一个新的实例引用,因为LocalDateTime,LocalDate,LocalTime都是不可变的.

plus----------向对象添加天,周,月,年.

minus---------从对象减去天,周,月,年.

Instant 时间戳

1.jdk8获取时间戳特别简单,且功能丰富。Instant类由一个静态的工厂方法now()可以返回当前时间戳.

Instant instant = Instant.now();

System.out.println("当前时间戳是:"+instant);

Date date = Date.from(instant);

System.out.println("当前时间戳是:"+date);

instant = date.toinstant();

System.out.println(instant)

时间戳是包含日期和时间的,与java.util.Date很类似,事实上instant就是类似JDK8以前的Date.

Instant 和 Date 这两个类可以进行转换.

DateTimeFormatter

1.在JDK8中,引入了一个全新的日期与时间格式器DateTImeFormatter.

2.正反都能调用format方法.

LocalDateTime 1dt = LocalDateTime.now();

System.out.rintln(1dt);

DateTImeFormatter dtf = DateTImeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

String ldtstr = ldt.format(dtf);

System.out.println(ldstr);

String 1dtstr1 =dtf.format(1dt);

System.out.println(ldtstr1);

Period

1.在java8中,我们可以使用以下类来计算日期间隔差异:java.time.period

2.主要是period类方法getYears(),getMonths()和getDays()来计算,只能精确到年月日.

3.用于LocalDate之间的比较.

LocalDate today = LocalDate.now();

System.out.println(today);

LoacalDate birthDate = LocalDate.of(1995,1,11);

System.out.println(birthDate);

period period = period.between(birthDate,today);

System.out.println("年龄:%d年%d月%日",period,getYears(),period.getMonths(),period.getDays());

 

ChronnUnit类可用于在单个时间单位内测量一段时间,这个工具类很全,可用于比较所有的时间单位.

包装类

1.其实就是8种基本数据类型对应的引用类型.

int ----------Integer

char ----------Character

除这两种外,其余6种首字母大写就是引用数据类型.

2.集合和泛型只能支持包装类型,不支持基本数据类型.

3.java为实现一切皆对象,为8种基本数据类型提供了对应的引用类型.

自动装箱:基本数据类型的数据和变量可以直接赋值给包装类型的变量.

自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量.

包装类的特有功能:

1.包装类的变量默认值是null,容错率更高.

2.可以把基本类型的数据转换成字符串类型(用处不大)

例:调用toString()方法得到字符串结果.

  调用Integer.toString(基本类型的数据).

3.可以把字符串类型的数据转换成真实的数据类型(很重要)

Integer.parselnt("字符串类型的整数")

Double.parseDouble("字符串类型的小数")

Integer . valueof()-----------可直接用valueof.

正则表达式

1.用一些规定的字符制定规则,并用来校验数据格式的合法性.

字符串对象提供了匹配正则表达式规则的API

public boolean matches(String regex):判断是否匹配正则表达式,匹配返回true,不匹配返回false.

public String[] split(String regex); 按照正则表达式匹配的内容进行分割字符串,返回一个字符串数组.

 

Arrays类概述

1.数组操作工具,专门用于操作数组元素的.

Arrays类的常用API

public static String toString(类型 [] a) 对数组进行排序.

public static void sort(类型 [] a) 对数组进行默认升序排序

public static <T>void sort(类型[]a,Comparator<?superT>c)

使用比较器对象自定义排序

public static int binarySearch(int[]a,int key)

例:int index = Arrays.binarySearch(arr,key:55);

 

二分搜索数组中的数据,存在返回索引,不存在返回-1.

 

Arrays.sort(ages1, new Comparator<Integer>()
  public int compare(Integer o1, Integer o2) {

               return o2-o1;
  }

这段代码的意义是将数组ages1,从大到小排序.若是01-02则是从小到大.

二分查找

实现数组的二分查找步骤:

1.定义变量记录左边和右边位置.

2.使用while循环控制查询(条件是左边位置<=右边位置)

3.循环内部获取中间元素索引.

4.判断当前要找的元素如果大于中间元素,左边位置=中间索引+1

或.判断当前要找的元素如果小于中间元素,右边位置=中间索引-1

5.判断当前要找的元素如果等于中间元素,返回当前中间元素索引.

例:

public static  int binarySearch(int[] arry,int data){

   int left =0;
   int right =arry.length - 1;
   while (left<=right) {
       int midleIndex = (left + right) / 2;
       if (data > arry[midleIndex]) {
           left = midleIndex + 1;
      } else if (data <arry[midleIndex]) {
           right = midleIndex - 1;
      } else {
           return midleIndex;
      }

  }
   return -1;

这是使用二分查找,找数组中的元素.

Lambda概述

1.Lambda表达式是JDK8开始后的一种新语法形式.

2.作用:简化匿名内部类的代码写法.

Lambda表达式的简化格式

(匿名内部类被重写方法的形参列表)->{

被重写方法的方法体代码.

}

注:->是语法形式,无实际意义.

pay:Lambda表达式只能简化函数式接口的匿名内部类的写法形式

函数式接口:1.首先必须是接口,其次接口中有且仅有一个抽象方法的形式.

2.通常我们会在接口上加上一个@Functionallnterface注解,标记该接口必须是满足函数式接口,可简化.

Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化.)

1.参数类型可以省略不写.

2.如果只有一个参数,参数类型可以省略,同时()也可以省略.

3.如果Lambda表达式的方法体代码只有一行代码.可以省略大括号不写,同时要省略分号!

4.如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写。此时,如果这行代码是return语句,则必须省略return不写,同时也必须省略";"不写.

    Animal a =new Animal(){
@Override
public void run(){
System.out.println("乌龟跑的很慢");
}
};
a.run();
------------------------------
Animal a1 =()->{
System.out.println("乌龟跑的很慢");
};
a1.run();

Collection集合体系

List--------- 有这两种 (ArrayList) (LinkdList )

set-----------HashSet (LinkedHashSet) TreeSet

Collection集合特点

1.List系列集合:添加的元素是有序,可重复,有索引.

ArrayList,LinedList,也遵循这一规则.

2.Set集合:添加的元素是无序,不重复,无索引.

HashSet;无序,不重复,无索引;

LinkedHashSet:有序,不重复,无索引.

TreeSet:按照大小默认升序排序,不重复,无索引.

集合对于泛型的支持

1.集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型.

pay:集合和泛型都只能支持引用数据类型,不支持基本数据类型,所以集合中存储的元素都认为是对象.所以,如果需要存储基本类型就使用包装类.

Collection<Integer>List = new ArrayList<>();
Collection<Double> List = new ArrayList<>();

Collection集合是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的.

Collection API 方法如下:

public boolean add(E e)把给的对象添加到集合中
public void clear() 清空集合中的所有元素
public boolean remove(E e) 把给的对象在当前集合中删除
public boolean contains(Object obj) 判断当前集合中是否包含给的对象
public boolean is Empty 判断当前集合是否为空
public int size() 返回集合中元素的个数
public Object[]toArray() 把集合中的元素,存储到数组中.

迭代器遍历概述

1.遍历就是一个一个的把容器中的元素访问一遍.

2.迭代器在java中的代表是Iterator,迭代器是集合的专用遍历方法.

Collection集合获取迭代器

方法名称说明
Iterator<E>iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引.

Iterator的常用方法

方法名称说明
boolean hasNext() 询问当前位置是否有元素存在,存在返回true,不存在false.
E next() 获取当前位置的元素,并同时将迭代器对象移向下一个位置.

pay:迭代器如果取元素越界会出现NoSuchElementException异常.

增强for循环

1.增强for循环,它既可以遍历集合也可以遍历数组.

2.它是JDK5之后出现的,其内部原理是一个Iterator迭代器,遍历集合相当于是迭代器的简化写法.

3.实现Iterable接口的类才可以使用迭代器和增强for,Collection接口已经实现了Iterable接口.

格式: for(元素数据类型 变量名:数组或者Collection接口){
     此处使用变量,该变量就是元素.
}
例:
    Collection<String>list = new ArrayList<>();
      for(String 变量:list){
      System.out.println(变量)
      }
这个例子中list.for可唤醒快捷键.
   
lists.forEach(new Consumer<String>() {
           @Override
           public void accept(String s) {
               System.out.println(s);
          }
      });
       ----------->简化为
        lists.forEach(s-> {
               System.out.println(s);

      });

Lambda表达式遍历集合:它提供了一种更简单,更直接的遍历集合的方式如上面例子所示

pay:集合中存储的是元素对象的地址.

数据结构

1.队列:先进先出,后进后出.

2.栈:后进先出,先进后出.

3.数组:内存连续区域,查询块,增删慢.

4.链表:元素是游离的,查询慢,首尾操作极快.

5.二叉树:永远只有一个根节点,每个节点不超过2个子节点的树

6.查找二叉树:小的左边,大的右边,但是可能树很高,查询性能变差.

7.平衡查找二叉树:让树的高度差不大于1,增删改查都提高了.

8.红黑树:基于红黑规则实现了自平衡的排序二叉树.

List集合特有方法

1.List集合因为支持索引,所以多了许多索引操作的独特API,其他Collection的功能List也都继承了.

方法名称说明
void add(int index,E element) 在此集合中的指定位置插入指定的元素
E remove(int index) 删除指定索引处的元素,返回被删除的元素
E set(int indxe,E element) 修改指定索引处的元素,返回被修改的元素.
E get(int index) 返回指定索引处的元素
List的实现类的底层原理

1.ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢.

2.LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的.

LinkedList的特点

1.底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了许多首尾操作的特有API.

LinkedList集合的特有功能

方法名称说明
public void addFirst(E e) 在该列表开头插入指定的元素
public void addLast(E e) 将指定的元素追加到此列表的末尾
public E getFirst() 返回此列表中的第一个元素
public E getFirst() 返回此列表中的最后一个元素
public E removeFirst() 从此列表中删除并返回第一个元素
public E removeLast() 从此列表中删除并返回最后一个元素
泛型概述

1.泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查.

2.泛型的格式:<数据类型>;注意;泛型只能支持引用数据类型.

public class MyArrayList<T>{}

3.集合体系的全部接口和实现类都是支持泛型的使用的.

泛型的好处:

1.统一数据类型

2.把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来.

泛型接口的概述

1.使用了泛型定义的接口急速泛型接口.

2.泛型接口的格式:修饰符 interface 接口名称<泛型变量>{}

3.泛型接口的原理:实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作.

例: public interface Date<E>{}

泛型通配符:?

1.?可以在"使用泛型"的时候代表一切类型.

2.E T K V是在定义泛型的时候使用的.

泛型的上下限:

  1. ? extends car(car是例子):?必须是car或者其子类

    --------------这是泛型上限

  2. ? super car: ?必须是car或者其父类

    ---------------这是泛型下限

Set系列集合特点

1.无序:存取顺序不一致

2.不重复:可以去除重复

3.无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素.

Set集合实现类特点

1.HashSet :无序,不重复,无索引

2.LinkedHashSet:有序,不重复,无索引

3.TreeSet:排序,不重复,无索引.

Set的功能基本上与Collection的API一致.

HashSet底层原理

HashSet集合底层采取哈希表存储的数据.

哈希表是一种对于增删改查数据性能电动比较好的结构.

哈希表的组成:

1.JDK8之前的,底层使用数组+链表组成.

2.JDK8开始之后,底层采用数组+链表+红黑树组成的.

哈希值

1.这是JDK根据对象的地址,按照某种规则算出来的int类型的数值.

Object类的API

1.public int hashCode(): 返回对象的哈希值

对象的哈希值特点

1.同一个对象多次调用hashCode()方法返回的哈希值是相同的.

2.默认情况下,不同对象的哈希值是不同的.

 

LinkedHashSet集合概述和特点

1.有序,不重复,无索引.

这里的有序指的是保证存储和取出的元素顺序一致.

原理:底层数据结构是哈希表,只是每个元素又额外多出一个双链表的机制记录存储的顺序.

TreeSet集合概述和特点

1.不重复,无索引,可排序(按照元素的大小默认升序(由小到大)排序)

TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都比较好.

注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序.

TreeSet集合默认的规则

1.对于数值类型:Integer,Double,官方默认按照大小进行升序排序.

2.对于字符串类型:默认按照首字母的编号升序排序

3.对于自定义类型如Student对象,TreeSet无非直接排序.

pay:想要使用TreeSet存储自定义类型,需要制定排序规则.

pay:补充

可变参数

1.可变参数用在形参中科院接收多个数据.

2.可变参数的格式:数据类型...参数名称

可变参数的作用

1.传输参数非常灵活,方便,科院不传输参数,可以传输一个或者多个,也可以传输一个数组

2.可变参数在方法内部本质上就是一个数组.

可变参数的注意事项:

1.一个形参列表中可变参数只能有一个.

2.可变参数必须放在形参列表的最后面.

 

Collections集合工具类

1.java.utils.Collections----是集合工具类.

2.作用:Collections并不属于集合,是用来操作集合的工具类.

Collections常用的API

方法名称说明
public static <T>boolean addAll(Collection<?super T>,c,T.........elements) 给集合对象批量添加元素.
public static void shuffle(List<?>list) 打乱List集合元素的顺序

Collections排序相关API

使用范围:只能对于List集合的排序.

排序方式1:
public static <T>void sort(List<T>list)
将集合中元素按照默认规则排序
pay:本方式不能直接对自定义类型的List集合排序,除非自定义类型实现了比较规则Comparable接口.
排序方式2:
public static <T> sort(List<T>list,Comparator<?super T>c)
将集合中元素按照指定规则排序.

Map集合概述和使用

1.Map集合是一种双列集合,每个元素包含两个数据.

2.Map集合的每个元素的格式:key=value(键值对元素).

3.Map集合也被称为"键值对集合".

Map集合整体格式:

1.Colection集合的格式:[元素1,元素2,元素3...]

2.Map集合的完整格式:{key1=value1,key2=value2,key3=value3,...}

Map集合体系
 Map 
HashMap HashTable ...
LinkedHashMap properties TreeMap

pay:使用最多的Map集合是HashMap.

Map集合体系特点

1.Map集合的特点都是由键决定的.

2.Map集合的键是无序,不重复的,无索引的,值不做要求

3.Map集合后面重复的键对应的值会覆盖前面重复键的值.

4.Map集合的键值对都可以为null.

Map集合实现类特点

1.HashMap:元素按照键是无序,不重复,无索引,值不做要求.

2.LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求.

3.TreeMap:元素按照键是排序,不重复,无索引的,值不做要求.

 

Map集合

1.Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的.

Map API如下:

V put(K key,V value)   添加元素
V remove(Object key)    根据键删除值对元素
void clear()            移除所有的键值对元素
boolean containsKey(Object key) 判断集合是否包含指定的键
boolean containValue(Object Value)判断集合是否包含指定值
boolean isEmpty()         判断集合是否为空
int size()          集合的长度,也就是集火中键值对的个数.

Map集合的遍历方式

一:键找值

1.先获取Map集合的全部键的Set集合.

2.遍历键的Set集合,然后通过键提取对应值.

键找值涉及到的API
set<K>keySet()          获取所有键的集合
V get(Object key)       根据键获取值

二:键值对

1.先把Map集合转换成Set集合,Set集合中每个元素都是键值对实体类型了.

2.遍历Set集合,然后提取键以及提取值.

键值对涉及到的API
  Set<Map.Entry<K V>>entrySet()获取所有键值对对象的集合
   K getKey()    获取键
   V getValue()  获取值
   

三:Lambda

1.JDK8开始有Lambda表达式,它能更快,更简单,直接遍历.

Map结合Lambda遍历的API
default void forEach(BiConsumer<?superK,?super V>action) ------------结合Lambda遍历Map集合
---------------------------------------------------
maps.forEach((K,v)->{
   System.out.println(k+"--->"+v);
});

HashMap的特点

1.HashMap的Map里面的一个实现类,特点都是由键决定的:无序,不重复,无索引.

2.HashMap跟HashSet底层原理是一模一样的,都是哈希表结构,只是HashMap的每个元素包含两个值而已.

pay:实际上,Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据而已.

HashMap的特点和底层原理

1.依赖HashCode方法和equals方法保证键的唯一.

2.如果键要存储的是自定义对象,需要重写HashCode和equals方法.

3.基于哈希表,增删改查的性能都比较好.

LinkedHashMap集合概述和特点

1.由键决定:有序,不重复,无索引.

这里的有序指的是保证存储和取出的元素顺序一致.

2.原理:底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序.

TreeMap集合概述和特点

1.由键决定特性:不重复,无索引,可排序.

2.可排序:按照键数据的大小默认升序(由小大大)排序,只能对键排序.

3.注意:TreeMap集合是一定要排序的,可以默认排序也可以将键按照指定的规则进行排序.

4.TreeMap跟TreeSet一样底层原理是一样的.

TreeMap集合自定义排序规则有两种:

1.类实现Compareable接口,重写比较规则.

2.集合自定义Comparator比较器对象,重写比较规则.

补充:Map集合实现类特点

HashMap:元素按照键是无序,不重复,无索引,值不做要求,基于哈希表(与Map体系一致)

LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求,基于哈希表.

TreeMap:元素只能按照键排序,不重复,无索引的,值不做要求,可以做排序.

创建不可变集合

1.在List,Set,Map接口中,都存在of方法,可以创建一个不可变的集合.

static <E>of(E..elements)  
--------创建一个具有指导元素的List集合对象.
static <E>Set<E>of(E...elements)
---------创建一个具有指导元素的Set集合对象.
static <K,V>Map<K,V>of(E...elements)
---------创建一个具有指导元素的Map集合对象

pay:这个集合不能添加,不能删除,不能修改.

Stream

1.在java8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念.

2.目的:用于简化集合和数组操作的API.

步骤:Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能.

集合获取Stream流的方式
可以使用Collection接口中的默认方法Stream()生成流.
default Stream<E>Stream()---获取当前对象的Stream流.
   
数组获取Stream流的方式
public static <T>Stream<T>Stream(T[]array)
-----------------获取当前数组的Stream流.
public static <T>Stream<T>of(T...values)
-----------------获取当前数组/可变数据的Stream流.

Stream流的常用API(中间操作方法)

Stream<T>filter(Predicate<?super T>predicate)
----------------------用于对流中的数据进行过滤.
Stream<T>limit(long maxSize)
----------------------获取前几个元素.
Stream<T>skip(long n)
----------------------跳过前几个元素.
Stream<T>distinct()
-----------去除流中重复的元素,依赖(hashCode和equals方法)
Static<T>Stream<T>concat(Stream a,Stream b)
---------------合并a和b两个流为一个流.

注意:

1.中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程.

2.在Stream流中无法直接修改集合,数组中的数据.

Stream流的常见终结操作方法
void forEach(COnsumer action)对此流的每个元素执行遍历操作
long count()      返回此流中的元素数.

终结方法和非终结方法的区别:终结方法后流不可继续使用,非终结方法会返回新的流.

Stream流的收集

含义:就是把Stream流操作后的结果数据转回到集合或者数组中去.

Stream流是操作集合或数组的手段--集合和数组才是开发的目的重点.

Stream流的收集方法

R collect(collector collector)         开始收集Stream流,指定收集器.

Collectors工具类提供了具体的收集方式

public static <T>Collector toList()        把元素收到List集合中
public static <T>Collector toSet           把元素收集到Set集合中
public static <T>Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中

异常

1.异常是程序在编译或者执行的过程中可能出现的问题,(语法错误不算在异常体系中)

比如:数组索引越界。空指针异常,日期格式化异常.

学习异常的理由:

1.异常一旦出现了,如果没有提起处理,程序就会退出JVM虚拟机而终止.

2.研究异常并且避免异常,然后提前处理异常,体现的是程序的安全,健壮性.

编译时异常和运行时异常

编译时异常:在编译成class文件时必须要处理的异常,也称之为受检异常.

运行时异常:在编译成class文件不需要处理,在运行字节码文件时可能出现的异常.

简单来说:编译异常就是在编译是出现的异常,运行时异常就是在运行时出现的异常.

一:运行时异常

1.直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能出现的错误.

运行时异常示例

数组索引越界异常:ArrayIndexOutOfBoundsException

空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错.

数字操作异常:ArithmeticException

类型转换异常:ClassCastException

数字转换异常:NumberFormatException

运行时异常一般是程序员没有考虑好,或者是编程逻辑不严谨引起的程序错误.

二:编译时异常

1.不是RuntimeException或者其子类的异常,编译阶段就报错,必须处理,否则代码不通过.

编译时异常的作用:担心程序员技术不行,在编译阶段就爆出错误,其目的在于提醒仔细,不要出错.

异常的默认处理流程

1.默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException.

2.异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机.

3.虚拟机接收到异常对象后,先在控制台直接输出异常信息数据.

4.直接从当前执行的异常点干掉程序.

5.后续代码没有机会执行,因为程序已经死亡.

异常的处理机制

编译时异常的处理形式有3种:

1.出现异常直接抛出去给调用者,调用者也继续抛出去

2.出现异常自己捕获处理,不麻烦别人.

3.前两者结合,出现异常直接抛出去给调用者,调用者捕获处理.

异常处理方式1

throws

throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理.

pay:这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡.

抛出异常格式:

方法 throws 异常1,异常2,异常3....{

}
规范格式:
方法 throws Exception{

}
异常处理方式2

try...catch...

1.监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理.

这种方式可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行.

格式:

try{
   //监视可能出现异常的代码
}catch(异常类型1 变量){
//处理异常
}catch(异常类型2 变量){
//处理异常
}...

建议格式:

try{
//可能出现异常的代码
}catch(Exception e){
 e.printStackTrace();//直接打印异常信息
}

pay:Exception可以捕获一切异常类型.

异常处理方式3

---前两者结合

1.方法直接将异常通过throws抛出去给调用者

2.调用者收到异常后直接捕获处理.

总结:在开发中按照规范来说第三章方式是最好的,底层的异常抛出去给最外层,最外层集中捕获处理.

实际应用中,只要代码能够编译通过,并且功能完成,那么每一种异常处理方式都是可以的.

运行时异常的处理方式

1.运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以.

2.按照规范建议还是处理,建议在最外层调用出集中捕获处理(try catch).

try - catch - finally

finally:当异常处理时提供finally块来执行所有清除操作,比如IO流中的释放资源.

特点:被finally控制的语句最终一定会执行,除法JVM退出.

异常处理标准格式:try ....catch ......finally

finally代码块是一定会执行的,在代码执行完毕的最后用于释放资源.

例:
try{
  FileOutputStream fos = new FileOutputStream("a.txt")
  fos.write(97);
  fos.close();
}catch(IOException){
   e.prinStackTrace();
}finally{

}

JDK7之后的改进方案

try(定义流对象){

可能出现异常的代码

}catch(异常类名 变量名){

异常的处理代码;

}

pay:try 后面的()只能放置资源对象,否则报错

资源:资源是实现了Closeable/AutoCloseable接口的类对象。例如InputStream,OutputStream

 

自定义异常

必要性:java无法为这个世界上所有问题提供异常类,企业想通过异常的方式来管理某个业务问题,需要自定义异常类.

好处:可以使用异常的机制管理业务问题,比如提醒程序员注意,同时一旦出现bug,可以用异常的形式清晰的指出出错的地方.

 

自定义异常分类:

一:自定义编译时异常

1.定义一个异常类继承Exception

2.重写构造器

3.在出现异常的地方用throw new自定义对象抛出.

作用:编译时异常是在编译阶段就报错,提醒更加强烈,一定要及时处理.

二:自定义运行时异常

1.定义一个异常类继承RuntimeException

2.重写构造器

3.在出现异常的地方用throw new自定义对象抛出.

作用:提醒不强烈,编译阶段不报错,运行时才可能出现.

File类概述

1.File类在包java.io.File下,代表操作系统的文件对象(文件,文件夹)

2.File类提供了诸如:定位文件,获取文件本身的信息,删除文件,创建文件(文件夹)等功能.

 

File类创建对象
public File(String pathname)       根据文件路径创建文件对象
public File(String parent,String child)  从父路径字符串和子路径字符串创建文件对象.
public File(File parent,String child)   根据父路径对应文件对象和子路径名字符串创建文件对象
绝对路径和相对路径
绝对路径:从盘符开始  依赖当前系统
File filel = new File("D:\\itheima\\a.txt")
相对路径:不带盘符,默认直接到当前工程下的目录寻找文件 可跳转系统使用
File file3 = new File("模块名\\a.txt")

File类的判断文件类型,获取文件信息功能

Public boolean isDirectory()    测试此抽象路径名表示的File是否为文件夹
public boolean isFile()   测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
public boolean getAbsolutePath  返回此抽象路径名的绝对路径名字符串
public boolean getPath() 将此抽象路径名转换为路径名字符串
public boolean getName() 返回此抽象路径名表示的文件或者文件夹的名称
public long lastModified() 返回文件最后修改的时间毫秒值
File类创建文件的功能
public boolean createNewFile()   创建一个新的空的文件
public boolean mkdir()           只能创建一级文件夹
public boolean mkdirs()   可以创建多级文件夹
File类删除文件的功能
public boolean delete()    删除由此抽象路径名表示的文件或空文件夹
delete方法直接删除不走回收站,如果删除的是一个文件,且文件没有被占用则直接删除
File类的遍历功能
public String[] list()  获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回
public File[]listFiles()(常用) 获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
ListFiles方法注意事项

1.当调用者不存在时,返回null

2.当调用者是一个文件时,返回null

3.当调用者是一个空文件夹时,返回一个长度为0的数组

4.当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回

5.当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容

 

方法递归

1.方法直接调用自己或者间接调用自己的方式称为方法递归.

2.递归作为一种算法在程序设计语言中广泛使用.

递归的形式

1.直接递归:方法自己调用自己

2.间接递归:方法调用其他方法,其他方法又回调方法自己-------总之递归就是调自己.

递归存在的问题:使用递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出.

递归解决问题的思路:把一个复杂的问题层层转化为一个与原问题相似规模较小的问题来求解.

递归算法三要素:

1.递归的公式 例:f(n) = f(n-1) * n;

2.递归的终结点:f(1)

3.递归的方向必须走向终结点

例:

f(5) = f(4) * 5
f(4) = f(3) * 4
f(3) = f(2) * 3
f(2) = f(1) * 2
f(1) = 1

面试题:猴子偷桃

 猴子第一天摘下若干桃子,吃了一半,又多吃了一个;第二天吃了第一天剩余桃子的一半,多一个,以后每天都吃前一天剩余桃子数量的一半,多一个,等到第10天的时候桃子只有一个了,求猴子第一天摘了多少桃子?
公式推演
  f(x)-f(x)/2-1=f(x+1)
  2f(x)-f(x)-2=2f(x+1)
  f(x)=2f(x+1)+2----------化简得到最后公式

字符集基础

1.计算机底层不可以直接存储字符的,计算机底层只能存储二进制(0,1)

2.二进制是可以转换成十进制的

pay:计算机底层可以表示十进制编号,计算机可以给人类字符进行编号存储,这套编号规则就是字符串

 

ASCLL字符集

1.ASCLL(美国信息交换标准源码):包括了数字,英文,符号.

2.ASCLL使用1个字节存储一个字符,一个字节是8位,总共可以表示128个字符信息,对于英文,数字来说是够用的.

 

GBK

1.window系统默认的码表,兼容ASCLL码表,包含几万个汉字,并支持繁体汉字以及部分日韩文字.

2.注意:GBK是中国的码表,一个中文以两个字节的形式存储,但不包含世界上所有国家的文字.

 

Unicode码表

1.unicode(又称统一码,万国码,单一码)这是计算机领域里的一项业界字符编码标准.

2.容纳世界上大多数国家的所有常见文字和符号.

3.由于unicode会先通过UTF-8,UTF-16,以及UTF-32的编码成二进制再存储到计算机,其中最为常见的就是UTF-8.

注意:

1.unicode是万国码,以UTF-8编码后一个中文一般以3个字节的形式存储.

2.UTF-8也要兼容ASCLL编码表.

3.技术人员都应该使用UTF-8的字符集编码

4.编码前和编码后的字符集需要一致,否则会出现中文乱码.

 

字符串常见的字符底层组成:

1.英文和数字等在任何国家的字符集都占一个字节.

2.GBK字符中一个中文字符占2个字节

3.UTF-8编码中一个中文一般占3个字节.

 

String编码

byte[]getBytes() 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中.

byte[]getBytes(String charseName) 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中.

60.5 String解码

String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数来构造新的String.

String(byte[] bytes ,String charsetName) 通过指定的字符集解码指定的字节数组来构造新的String.

IO流

I 表示input,是数据从硬盘文件读入到内存的过程,称之输入,负责读.

O 表示output,是内存程序的数据从内存到写出硬盘文件的过程,称之输出,负责写.

IO流的分类

1.按流的方向可分为:输入流,输出流

2.按流中的数据最小单位分为字节流,字符流

 

总结流的四大类

1.字节输入流:以内存为基础,来自磁盘文件/网络中的数据以字节的形式读入到内存中的流称为字节输入流.

2.字节输出流:以内存为基础,把内存中的数据以字节写出到磁盘文件或者网络中的流称为字节输出流.

3.字符输入流:以内存为基础,来自磁盘文件/网络中的数据以字符的形式读入到内容中去的流称为字符输入流.

4.字符输出流:以内存为基础,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流称为字符输出流.

 

文件字节输入流:FileInputStream

作用:以内存为基准,把磁盘文件的中的数据以字节的形式读取到内存中去.

public int read()                   每次读取一个字节返回,如果字节已经没有可读的返回-1
public int read(byte[]buffer)       每次读取一个字节数组返回,如果字节已经没有可读的返回-1  

 

官方为InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中.

public byte[] readAllBytes() throws IOException   直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回.
   例:
    byte[]buffer=is.readAllBytes();
       System.out.println(new String(buffer));

文件字节输出流:FileOutputStream

作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流.

public FileOutputStream(File file)                         创建字节输出流管道与源文件对象接通
public FileOutputStream(File file,boolean append)          创建字节输出流管道与源文件对象接通,可追加数据.
public FileOutputStream(String filepath)                   创建字节输出流管道与源文件路径相通
public FileOutputStream(String filepath,boolean append)    创建字节输出流管道与源文件路径相通,可追加数据.

文件字节输出流(FIleOutputStream)写数据出去的API

public void write(int a)                   写一个字节出去
public void write(byte[] buffer)           写一个数组出去
public void write(byte[],int pos,int len)  写一个字节数组的一部分出去

流的关闭与刷新

flush()      刷新流,还可以继续写数据(添写完一组数据要常刷新,防止数据丢失)
close()      关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据

字节输出流如何实现写出去的数据换行:os.write("\r\n".getBytes() )

字节输出流如何让写出去的数据能成功生效:flush()刷新数据,close()关闭流,关闭包含刷新,关闭流后不能继续使用.

 

 

 

文件字符输入流:Reader

作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去.

public FileReader(File file)        创建字符输入流管道与源文件对象接通
public FileReader(String pathname)  创建字符输入流管道与源文件路径流通
   
public int read()                   每次读取一个字符返回,如果字符已经没有可读的返回-1
public int read(char[]buffer) 每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1
文件字符输入流:FileReader

作用:以内存为基础,把磁盘文件中的数据以字符的形式读取到内存中去.

public int read()                      每次读取一个字符返回,如果字符已经没有可读的返回-1
public int read(char[] buffer)   每次读取一个字符数组,返回读取的字符数,如果字符数已经没有可读的返回-1
文件字符输出流(FileWriter)写数据出去的API
void write(int c)                           写一个字符
void write(char[]cbuf)                      写入一个字符数组
void write(char[]cbuf,int off,int len)      写入字符数组的一部分
void write(String str)                      写一个字符串
void write(String str,int off,int len)      写一个字符串的一部分
void write(int c)                           写一个字符
字符输出流使数据换行

fw.write("\r\n")----------fw调用,可换

字符输出流写完数据后使用 flush()刷新数据,close()方法是关闭流,关闭包含刷新,关闭后流不能再继续使用.

字节流,字符流如何选择使用

1.字节流适合做一切文件数据的拷贝(音视频,文本)

2.字节流不适合读取中文内容.

3.字符流适合做文本文件的操作(读,写)

缓冲流概述

缓冲流优势明显,推荐使用.

1.缓冲流也称为高效流,或者高级流,之前学习的字节流称为原始流.

2.作用:缓冲自带缓冲区,可以提高原始字节流,字符流读写数据的性能.

 

缓冲流大致分两种

字符缓冲流:

字节缓冲输入流:BufferedInputStream

字符缓冲输出流:BufferedInputStream

字节缓冲流:

字符缓冲输入流:BufferedReader

字符缓冲输出流:BufferedWriter

 

字符缓冲流性能优化原理:

1.字节缓冲输入流自带了8KB缓冲池,我们直接从缓冲池读取数据,所以性能较好.

2.字节缓冲输出流自带了8KB缓冲池,数据就直接写入到缓冲池中去,写数据性能极高.

 

字节缓冲流

1.字节缓冲输入流:BufferedInputStream 提高字节输入流读取数据的性能,读写功能上并无变化.

2.字节缓冲输出流:BufferedOutputStream提高字节输出流读取数据的性能,读写功能上并无变化.

public BufferedInputStream(InputStream is)    可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道,从而提高字节输入流读数据的性能.
public BufferedOutoutStream(OutputStream os)  可以把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能.

 

字符缓冲输入流

1.字符缓冲输入流:BufferedReader.

2.作用:提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能.

Public BufferedReader(Reader r)    可以把低级的字符输入流包装成一个高级的缓冲字符输入管道,从而提高字符输入流数据的性能

字符缓冲输入流新增功能:

Public String readLine()        读取一行数据返回,如果读取没有完毕,无行可读返回Null
字符缓冲输出流

1.字符缓冲输出流:BufferedWriter

2.作用:提高字符输出流写取数据的性能,除此之外多了换行功能

public BufferedWrite(Write w)      可以把低级的字符输出流包装成一个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能

newLine                              换行操作

 

字符输入转换流

1.字符输入转换流:InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流.

public InputStreamReader(InputStream is)       可以把原始的字节流按照代码默认编码转换成字符输入流,几乎不用,与默认的FileReader
Public InputStreamReader(InputStream is ,String charset) 可以把原始的字节流按照指定编码转换成字符输入流,这样字符流中的字符就不乱码(重点)

对象序列化

1.作用:以内存为基准把内存中的对象存储到磁盘文件中去,称为对象序列化.

2.使用到的流是对象字节输出流:ObjectOutputStream

public ObjectOutputStream(OUtputStream out)  把低级字节输出流包装成高级的对象字节输出流.
   writeObject()----直接调用序列化方法

对象反序列化

1.使用到的流是镀锡字节输入流:ObjectInputStream

2.作用:以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象,称为对象反序列化.

public ObjectInputStream(InputStream out)  把低级字节输入流包装成高级的对象字节输入流
public Object readObject()                 把存储到磁盘文件中去的对象数据恢复成内存中的对象返回.

 

打印流

1.作用:打印流可以实现方便,高效的打印数据到文件中去。打印流一般是指:PrintStream,PrintWrite两个类。

2.可以实现打印什么数据就是什么数据,例如打印整数97写出去急速97.

PrintWrite

public PrintStream(OutputStream os) 打印流直接通向字节输出流管道
public PrintStream(File f) 打印流直接通向文件对象
public PrintStream(String filepath) 打印流直接通向文件路径

public void print(xxx xx)  打印任意类型的数据出去

printStream 和printWriter的区别

1.打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)

2.printStream继承自字节输出流OutputStream,支持写字节数据的方法.

3.printWriter继承自字符输出流Writer,支持写字符数据出去.

输出语句重定向

1.属于打印流的一种应用,可以把输出语句的打印位置改到文件.

printStream ps = new printStream("文件地址")
System.setOut(ps);

properties属性集对象

1.其实就是一个Map集合,但是我们一般不会当集合使用,因为HashMap更好用.

properties核心作用:

1.properties代表的是一个属性文件,可以把自己对象中的键值对

信息存入到一个属性文件中去.

2.属性文件:后缀是.properties结尾的文件,里面的内容都是key=value,后续做系统配置信息的.

 

properties的API

properties和IO流结合的方法
void load(Reader reader)                      从输入字符流读取属性列表(键和元素对)
void store(Writer writer,String comments)    将此属性表(键和元素对)写入此properties表中,以适合使用load(Reader)方法的格式写入输出字符流.

commons-io概述

io框架

1.commons-io是apache开源基金组织提供的一组有关IO操作的类库,可以提高IO功能开发的效率.

2.commons-io工具包提供了很多有关io操作的类,两个主要的类FIleUtils,IOUtils.

 

FileUtils主要有如下方法:

String readFileToString(File file,String encoding)      读取文件中的数据,返回字符串
void copyFile(File srcFile,File destFile)               复制文件
void copyDirectoryToDirectory(File srcDir,File destDir) 复制文件夹.

线程

1.thread是一个程序内部的一条执行路径.

例:启动程序执行后,main方法的执行就是一条单独的执行路径.

2.多线程:多线程是指从软硬件上实现多条执行流程的技术.

 

Thread类

1.java是通过java.lang.Thread类来代表线程的.

2.按照面向对象的思想,Thread类应该提供了实现多线程的方式.

多线程的实现方案一:继承Thread类
1.定义一个子类MyTread继承线程类java.lang.Thread,重写run()方法
2.创建MyThread类的对象
3.调用线程对象的start()方法启动线程(启动后还是执行run方法)
   
  方式一优缺点:
   1.优点:编码简单
   2.缺点:线程类已经继承Thread,无法继承其他类,不利于扩展.
   若直接调用run方法,会被当做普通方法执行,那就相当于还是单线程执行.只有调用start方法才是启动一个新的线程执行.
   例:public class MyThread extends Thread {
   public void run() {
       for (int i = 0; i < 5; i++) {
           System.out.println("子线程输出;" + i);
      }
  }
}

多线程的实现方案二:实现Runnable接口

1.定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法

2.创建MyRunnable任务对象.

3.把MyRunnable任务对象交给Thread处理.

4.调用线程对象的start()方法启动线程.

方式二优缺点:

1.优点:线程任务类只是实现接口,可以继承继承类和实现接口,扩展性强.

2.缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的.

多线程的实现方案三:利用Callable,FutureTask接口实现.

1.得到对象

定义类实现Callable接口,重写call方法,封装要做的事情.

用FutureTask把Callable对象封装成线程任务对象.

2.把线程任务对象交给Thread处理.

3.调用Thread的start方法启动线程,执行任务.

4.线程执行完毕后,通过FutureTask的get方法去获取任务执行的结果.

FutureTask的API

public FutureTask<>(Callable call)  把Callable对象封装成FutureTask对象.
public V get()throws Exception 获取线程执行call方法返回的结果

方式三优缺点:

1.优点:线程任务类只是实现接口,可以继承继承类和实现接口,扩展性强.

2.可以在线程执行完毕后去获取线程执行的结果.

3.缺点:编码复杂一点.

 

Thread获取和设置线程名称

String getName()   获取当前线程的名称,默认线程名称是Thread-索引.
void setName(String name) 将此线程的名称更改为指定的名称,通过构造器也可以设置线程名称.

Thread的构造器

public Thread(String name) 可以为当前线程指定名称
public Thread(Runnable target) 封装Runnable对象成为线程对象.
public Thread(Runnable target,String name)封装Runnable对象成为线程对象,并指定线程名称.

Thread类的休眠方法

public static void sleep(long time) 让当前线程休眠指定的时间后再继续执行,单位为毫秒.

Thread常用方法,构造器

String getName()    获取当前线程的名称,默认线程名称是Thread-索引.
void setName(String name) 设置线程名称
public static Thread currentThread():返回对当前正在执行的线程对象的引用.
public static void sleep(long time)让线程休眠指定的时间,单位为毫秒.
Public void run()     线程任务方法
public void start()   线程启动方法

线程安全问题

意义:多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题.

线程同步的核心思想:加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来.----------------------加锁的目的是为了让多个线程实现先后依次访问共享资源,解决安全问题.

 

同步代码块

1.作用:把出现线程安全问题的核心代码给上锁.

2.原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行.

synchronized(同步锁对象){
   操作共享资源的代码(核心代码)
}

锁对象要求

理论上:锁对象只要对于当前同时执行的线程来说是同一个对象即可.

规范要求:

1.建议使用共享资源作为锁对象.

2.对于实例方法建议使用this作为锁对象.

3.对于静态方法建议使用字节码(类名.class)对象作为锁对象.

同步方法

1.作用:把出现线程安全问题的核心方法给上锁.

2.原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行.

格式
修饰符 synchronized 返回值类型 方法名称(形参列表){
  操作共享资源的代码
}

同步方法底层原理

1.同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码.

2.如果方法是实例方法,同步方法默认用this作为锁对象,但是代码要高度面向对象.

3.如果方法是静态方法,则同步方法默认用类名.class作为锁的对象

 

Lock锁

1.为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock,更加灵活,方便

2.Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作.

3.Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象.

public ReentrantLock()  获得Lock锁的实现类对象

Lock的API

void lock()      获得锁
void unlock()    释放锁

 

线程通信

1.线程通信就是线程间相互发送数据,线程通信通常通过共享一个数据的方式实现.

2.线程间会根据共享数据的情况决定自己该怎么做,以及通知其他线程怎么做.

线程通信常见模型

1.生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费数据.

2.要求:生产者线程生产完数据后,唤醒消费者,然后等待自己;消费者消费完该数据后,唤醒生产者,然后等待自己.

线程通信的前提:线程通信经常是在多个线程操作同一个共享资源的时候需要进行通信,且要保证线程安全.

Object类的等待和唤醒方法

void wait()           让当前线程等待并释放所占锁,直到另一个线程调用notify()方法或notifyAll()方法
void notify()         唤醒正在等待的单个线程
void notifyAll()      唤醒正在等待的所有线程

上述方法应该使用当前同步锁对象进行调用.

 

线程池

意义:线程池就是一个可以复用线程的技术.

1.JDK5.0起提供了代表线程池的接口:ExecutorService

得到线程池对象的两种方法:

方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象.

方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象.

ThreadPoolExecutor构造器的参数说明

public ThreadPoolExecutor
(
int corePoolSize
int maximumPoolSize
long keepAliveTime
TimeUnit unit
BlockingQueue<Runnable>workQueue
ThreadFactory threadFactory
RejectedExecutionHandler handler
)
参数一:指定线程池的线程数量(核心线程):corePoolSize
----------------------不能小于0
参数二:指定线程池可支持的最大线程数:maximumPoolSize
----------------------最大数量>=核心线程数量
参数三:指定临时线程的最大存活时间:keepAliveTime
----------------------不能小于0
参数四:指定存活时间的单位(秒,分,时,天):unit
----------------------时间单位
参数五:指定任务队列:workQueue
----------------------不能为null
参数六:指定用哪个线程工厂创建线程:threadFactory  
----------------------不能为null
参数七:指定线程忙,任务满的时候,来了新任务:handler
----------------------不能为null

ThreadPoolExecutor创建线程池对象示例

ExecutorService pools = new ThreadPoolExecutor(3,5,8,TimeUnit.SECONDS,new ArrayBlockingQueue<> (6),Executors.defaultThreadFactory(),new ThreadPoolExecutor,AbortPolicy());

ExecutorService的常用方法

void execute(Runnable command) 执行任务/命令,没有返回值,一般用来执行Runnable任务.
Future<T>submit(Callable<T>task) 执行任务,返回未来任务对象获取线程结果,一般用来执行Callable任务.
void shutdown() 等任务执行完毕后关闭线程池
List<Runnable>shutdownNow() 立刻关闭,停止正在执行的任务,并返回队列中未执行的任务.

新任务拒绝策略

ThreadPoolExecutor.AbortPolicy         丢弃任务并抛出RejectedExecutionException异常----默认策略
ThreadPoolExecutor.DiscardPOlicy:      丢弃任务,但是不抛出异常,这是不推荐的做法
ThreadPoolExecutor.DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入队列中
ThreadPoolExecutor.CallerRunsPolicy    由主线程负责调用任务的run()方法从而绕过线程池直接执行.

Executors得到线程池对象的常用方法

Executors:线程池的工具类通过调用方法返回不同类型的线程池对象.

public static ExecutorService newCachedThreadPool 线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉.
public static ExecutorService   newFixedThreadPool(int nThread) 创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程会补充一个新线程替代它.
public static ExecutorService newSingleThreadExecutor() 创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务.
pay:Executors 的底层其实也是基于线程池的实现类ThreadPoolExecutor创建线程池对象的.

Executors使用可能存在的陷阱

1.大型并发系统环境中使用Executors如果不注意会出现系统危险.----需使用ThreadPoolExecutor的方式,这样的处理方式能更明确线程池运行规则,规避资源耗尽的风险.

 

定时器

1.定时器是一种控制任务延时调用,或者周期调用的技术.

2.作用:闹钟,定时邮件发送.

定时器的实现方式:

方式一:Timer

方式二:ScheduledExecutorService

 

Timer定时器

----------------------------------不推荐使用

public Timer() 创建Timer定时器对象.

public void schedule(TimerTask task,long delay,long period) 开启一个定时器,按照计划处理TimerTask任务.

Timer定时器的特点和存在的问题

1.Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入.

2.可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行.

ScheduledExecutorService定时器

--------------------------------------推荐使用

ScheduledExecutorService是JDK1.5中引入了并发包,目的是为了弥补Timer的缺陷,ScheduledExecutorService内部为线程池.

ScheduledExecutorService的优点

1.基于线程池,某个任务的执行情况不会影响到其他定时任务的执行.

 

并发与并行

意义:正在运行的程序(软件)就是一个独立的进程,线程是属于进程的,多个线程其实是并发与并行同时进行的.

并发的理解:

1.CPU同时处理线程的数量有限

2.CPU会轮询为系统的每个线程服务,由于CPU切换很快,给我们的感觉这些线程在同时执行,这就是并发.

线程的生命周期

----------从诞生到消失

1.线程的状态:也就是线程从生到死的过程,以及中间经历的各种状态及状态转换.

2.理解线程的状态有利于提升并发逻辑的理解能力.

JAVA线程的状态

1.JAVA总共定义了6种状态.

2.6种状态都定义在Thread类的内部枚举类中.

新建状态(NEW)
就绪状态(RUNNABLE)
阻塞状态(BLOCKED)
等待状态(WAITING)
计时等待(TIMED_WAITING)
结束状态(TERMIATED)

网络通信编程

实现网络编程关键的三要素

1.IP地址:设备在网络中的地址,是唯一的标识

2.端口:应用程序在设备中唯一的标识

3.协议:数据在网络中传输的规则,常见的协议有UDP协议和TCP协议.

IP地址

1.IP:全称"互联网协议地址",是分配给上网设备的唯一标志.

2.常见的IP分类为:IPv4和IPv6.

IP地址形式:

1.公网地址,和私有地址(局域网使用).

2.192.168.开头的就是常见的局域网地址,范围即为192.168.0.0--192.168.255.255 ,专门为组织机构内部使用.

IP常用命令:

1.ipconfig:查看本机IP地址

2.ping IP地址:检查网络是否连通

特殊IP地址:

1.本机IP:127.0.0.1或者localhost:称为回送地址也可称为本地回环地址,只会寻找当前所在本机.

 

InetAddress的使用

意义:此类表示Internet协议(IP)地址.

InetAddress API 如下
public static InetAddress getLocalHost()  返回本主机的地址对象
public static InetAddress getByName(String host) 得到指定主机的IP地址对象,参数是域名或者IP地址
public String getHostName() 获取此IP地址的主机名
public String getHostAddress() 返回IP地址字符串
public boolean isReachable(int timeout) 在指定毫秒内连通该IP地址对应的主机,连通返回true.

端口号

意义:标识正在计算机设备上运行的进程(程序),被规定为一个16位的二进制,范围是0-65535.

端口类型

1.周知端口:0-1023,被预先定义的知名应用占用

2.注册端口:1024-49151,分配给用户进程或某些应用程序.

3.动态端口:49152到65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配.

注意:我们自己开发的程序选择注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错.

通信协议

意义:连接和通信数据的规则被称为网络通信协议

网络通信协议两套参考模型

一 OSI参考模型:世界互联网协议标准,全球通信规范,由于此模型过于理想化,未能在因特网上进行广泛推广.

二 TCP / IP参考模型(或TCP/IP协议):事实上的国际标准.

 

传输层的2个常见协议

一.TCP:传输控制协议

TCP协议特点:

1.使用TCP协议,必须双方先建立连接,它是一种面向连接的可靠通信协议.

2.传输前,采用"三次握手"方式建立连接,所以是可靠的.

3.在连接中可进行大数据量的传输.

4.连接,发送数据都需要确认,且传输完毕后,还需释放已建立的连接,通信效率较低.

TCP协议通信场景:对信息安全要求较高的场景,比如文件下载,金融等数据通信.

二 .UDP:用户数据报协议

UDP协议

1.UDP是一种无连接,不可靠传输的协议

2.将数据源IP,目的地IP和端口封装成数据包,不需要建立连接.

3.每个数据包的大小限制在64kb内.

4.发送不管对方是否准备好,接收方收到也不确认,故是不可靠的.

5.可以广播发送,发送数据结束时无需释放资源,开销小,速度快.

UDP协议通信场景:语音通话,视频会话等.

 

DatagramPacket:数据包对象

public DatagramPacket(byte[]buf,int length,InetAddress address,int port)  创建发送端数据包对象 buf:要发送的内容,字节数字 length:要发送内容的字节长度。address:接收端的IP地址对象.port:接收端的端口号.
public DatagramPacket(byte[]buf,int length)                       创建接收端的数据包对象 buf:用来存储接收的内容 length:能够接收内容的长度.

DatagramSocket:发送端和接收端对象(人)

public DatagramSocket()  创建发送端的Socket对象,系统会随机分配一个端口号.
public DatagramSocket(int port) 创建接收端的Socket对象并指定端口号.

DatagramSocket类成员方法

public void send(DategramPacket dp)      发送数据包
public void receive(DatagramPacket p)    接收数据包

UDP的三种通信方式

1.单播:单台主机与单台主机之间的通信.

2.广播:当前主机与所在网络中的所有主机通信.

3.组播:当前主机与选定的一组主机的通信.

TCP通信

Socket

public Socket(String host , int port) 创建发送端的Socket对象与服务器连接,参数为服务端程序的IP和端口.

Socket类成员方法

OutputStream getOutputStream() 获得字节输出流对象
InputStream getInputStream()   获得字节输入流对象

ServerSocket(服务端)

public ServerSocket(int port) 注册服务端端口

ServerSocket类成员方法

public Socket accept() 等待接收客户端的Socket通信连接,连接成功返回Socket对象与客户端建立端到端通信

单元测试---Junit

意义:单元测试就是针对最小的功能单元编写测试代码,JAVA程序最小的功能单元是方法,因此,单元测试就是针对JAVA方法的测试,进而检查方法的正确性.

Junit单元测试框架

1.Junit是使用JAVA语言实现的单元测试框架,它是开源的,JAVA开发者都应当学习并使用Junit编写单元测试.

2.此外,几乎所有的IDE工具都集成了Junit,这样我们就可以直接在IDE中编写并运行Junit测试,Junit目前最新版本是5.

Junit优点

1.Junit可以灵活的选择执行那些测试方法,可以一键执行全部测试方法.

2.Junit可以生成全部方法的测试报告.

3.单元测试中的某个方法测试失败了,不会影响其他测试方法的测试.

Junit常用注解(Junit4版本)

@Test              测试方法
@Before            用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次
@After             用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeClass       用来静态修饰方法,该方法会在所有测试方法之前只执行一次
@AfterClass        用来静态修饰方法,该方法会在所有测试方法之后只执行一次

Junit常用注解(Junit5版本)

@Test          测试方法
@BeforeEach    用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次
@AfterEach     用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeAll     用来静态修饰方法,该方法会在所有测试方法之前只执行一次
@AfterAll      用来静态修饰方法,该方法会在所有测试方法之后只执行一次

反射概述

-----------------------得到编译以后的class文件对象

1.反射是指对于任何一个Class类,在运行的时候都可以直接得到这个类全部成分.

2.在运行时,可以直接得到这个类的构造器对象:Constructor

3.在运行中,可以直接得到这个类的成员变量对象:Field

4.在运行时,可以直接得到这个类的成员方法对象:Method

5.这种运行时动态获取类信息以及动态调用类中成分的能力称为Class的全部成分.

反射的关键:

1.反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分.

使用反射技术获取构造器对象并使用

1.反射的第一步是先得到类对象,然后从类对象中获取类的成分对象.

2.Class类中用于获取构造器的方法

Constructor<?>[]getConstructors()                                返回所有构造器对象的数组(只能拿Public的)
Constructor<?>[]getDeclaredConstructors()                        返回所有构造器对象的数组,存在就能拿到
Constructor<T>getConstructor(Class<?>...parameterTypes)          返回单个构造器对象(只能拿public的)
Constructor<T>getDeclaredConstructor(Class<?>...parameterTypes)  返回单个构造器对象,存在就能拿到

使用反射技术获取构造器对象并使用

1.获取构造器的作用依然是初始化一个对象返回

Constructor类中用于创建对象的方法

T newInstance(Object...initargs) 根据指定的构造器创建对象
public void setAccessible(boolean flag) 设置为true,表示取消访问检查,进行暴力反射.

使用反射技术获取方法对象并使用

1.反射的第一步是先得到类对象,然后从类对象中获取类的成分对象.

2.Class类中用于获取成员方法的方法.

Method[] getMethods()     返回所有成员方法对象的数组(只能拿public的)
Method[] getDeclaredMethos()  返回所有成员方法对象的数组,存在就能拿到
Method[] getMethod(String name , Class<?>...parameterTyper)  返回单个成员方法对象(只能拿public的)
Method getDeclaredMethod(String name , Class<?>...parameterTypes) 返回单个成员方法对象,存在就能拿到

使用反射技术获取方法对象并使用

意义:获取成员方法的作用依然是在某个对象中进行执行此方法

Method类中用于触发执行的方法

Object invoke(Object obj , Object...args) 运行方法:参数一:用obj对象调用该方法.参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写)

反射的作用

----------------------绕过编译阶段为集合添加数据

ArrayList<Integer>list = new ArrayList<>();
list.add(100);
list.add("黑马")----报错不能添加此类型

泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了.

pay:达到反射一样的效果的另一种方式

 例:
ArrayList list4 = lists3;
       list4.add("白马");
       list4.add(false);
       list4.add("adasd");
       System.out.println(lists3);

反射的作用:

1.可以在运行时得到一个类的全部成分然后操作.

2.可以破坏封装性(很突出)

3.也可以破坏泛型的约束性(很突出)

4.更重要的用途是适合:做java高级框架

 

注解概述,作用

1.java注解(Annotation)又称java标注,是JDK5.0引入的一种注释机制.

2.java语言中的类,构造器,方法,成员变量,参数等都可以被注解进行标注.

注解的作用:对java中类,方法,成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定.

例:Junit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行.

自定义注解---格式

意义:自定义注解就是自己做一个注解来使用.

public @interface 注解名称{
 public 属性类型 属性名() default 默认值
}

元注解

意义:就是注解注解的注解---------放在注解上面的注解

元注解有两个常用:

1.@Target:约束自定义注解只能在哪些地方使用

@Target中可使用的值定义在ElementType枚举类中,常用值如下:
TYPE          类接口
FIELD         成员变量
METHOD        成员方法
PARAMETER     方法参数
CONSTRUCTOR   构造器
LOCAL_VARIABLE 局部变量

2.@Retention:申明注解的生命周期

SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在.
CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

注解解析

意义:注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就能解析出内容.

与注解解析相关的接口

Annotation:注解的顶级接口,注解都是Annoation类型的对象.

AnnotatedElement:该接口定义了与注解相关的解析方法.

Annotation[] getDeclaredAnnotations()  获得当前对象上使用的所有注解,返回注解数组
T getDeclaredAnnotation(Class<T>annotationClass) 根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class<Annotation>annotationClass) 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false.

所有的类成分CLass,Method,Filed,Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力.

解析注解的技巧

1.注解在哪个成分上,我们就先拿哪个成分对象.

2.比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解

3.比如注解作用在类上,则要该类的Class对象,再来拿上面的注解.

4.比如注解作用在成员变量上,则要获得该成员变量对应的FIled对象,再来拿上面的注解.

 

XML概述

意义:XML是可扩展标记语言的缩写,它是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据.

XML的几个特点和使用场景

1.一是纯文本,默认使用UTF-8编码,二是可嵌套.

2.如果把XML内容存为文件,那么它就是一个XML文件.

3.XML的使用场景:XML内容经常被当成消息进行网络传输,或者作为配置文件用于存储系统的信息.

 

XML的创建

-------就是创建一个XML类型的文件,要求文件的后缀必须使用xml,例如hello_world.xml

 

XML的语法规则

1.XML文件的后缀名为:xml

2.文档声明必须是第一行

<?xml version="1.0"encoding="UTF-8">

version:XML默认的版本号码,该属性是必须存在的
encoding:本XML文件的编码

XML的标签(元素)规则

1.标签由一对尖括号和合法标识符组成:<name></name>必须存在一个跟标签,有且只能有一个.

2.标签必须成对出现,有开始,有结束:<name></name>

3.特殊的标签可以不成对,但是必须有结束标记,如:

4.标签中可以定义属性,属性和标签名 空格 隔开,属性值必须使用引号引起来<student id = "1"></name>

5.标签需要正确的嵌套

例:
<student id = "1">
<name>张三</name>
</student>

XML的其他组成

1.XML文件中可以定义注释信息:<!-注释内容-->

2.XML文件中可以存在以下特殊字符

&lt;   <
&gt;   >
&amp;  &
&apos; ''
&quot; ""

3.XML文件中可以存在CDATA区:<![CDATA[内容]]>

文档约束

意义:是用来限定XML文件中的标签以及属性应该怎么写.

-------------以此强制约束程序员必须按照文档约束的规定来编写xml文件.

文档约束的分类

DTD----可以约束XML文件的缩写,不能约束具体的数据类型.

 

schema----------可以约束XML文件的标签内容格式,以及具体的数据类型.

1.schema可以约束具体的数据类型,约束能力更强大.

2.schema本身也是一个XML文件,本身也受到其他约束条件的要求,所以编写的更加严谨.

XML解析:使用程序读取XML中的数据

两种解析方式:SAX解析,DOM解析.

DOM常见的解析工具

JAXP    SUN公司提供的一套XML的解析的API
JDOM    JDOM是一个开源项目,它基于树形结构,利用java的技术对XML文档实现解析,生成序列化以及多种操作
dom4j   是JDOM的升级品,用来读写XML文件的,具有性能优异,功能强大和极其易使用的特点,它的性能超过SUN公司官方的dom技术,同时它也是一个开放源代码的软件,Hibernate也用它来读写配置文件.
jsoup   功能强大DOM方式的XML解析开发包,尤其对HTMML解析更加方便.