Java基础的面试复习

#一. Java简介:
JDK,JRE,JVM之间的关系:
JDK 是针对Java开发员的产品.包含运行环境JRE,Java工具类和Java基础类库(也就是JRE+开发工具).
JRE 是运行Java的运行时环境,包含JVM和Java核心类库(如Java.lang包).
JVM Java虚拟机,是整个Java实现跨平台的最核心部分,能够运行Java原因写的程序.

Java的跨平台:
Java程序可以实现"一次编译,处处运行",Java程序是通过虚拟机在系统平台上运行,只要系统上安装了Java虚拟机,就可以运行Java程序.

Java程序的运行实现:
Java源代码(.java文件)—>编译器—>JVM可执行的字节码文件(.class文件)—>虚拟机—>解释
器—>电脑可执行的二进制代码.

文字说明:
	       每一种系统平台的解释器是不同的,但是实现的虚拟机是相同的,编译程序只需要面向虚拟机,将Java源代码(.Java文件),生成虚拟机理解的字节码(.class文件),再由解释器将虚拟机代码转换为特定系统的机器码执行.

##二. 数据类型和计算:
基本数据类型:
位bit 字节byte 1byte=8bit
类型名称 字节空间 取值范围
整数型 byte 1 -27到27-1 5 -128到127
short 2 -215到215-1
int 4 -231到231-1
long 8 -263到263-1
浮点型 float 4 单精度,对小数部分的精度要求不高
double 8 双精度,精确的小数部分并操作值很大时
字符 char 2 0到65535
布尔 boolean 1 真true 假false

	       需要注意char类型可以存储单独的字符,用单引号括起来,如果不用单引号括起来的数字,系统将会查询阿斯克码表(ASCII),来输出数字对应的字符.

运算符:  

算术运算符 + - * / 基本运算
% 取余数,求模,算整除
++ – 自增 自减
比较运算符 == 相等比较
!= 不等比较
逻辑运算符 && & 逻辑与(短路与),两边同为真结果才为真
|| | 逻辑或(短路或),两边只要有一个真结果就是真
+ 字符串连接
! 非,非真是假,非假是真
三元运算符 ?: 三项运算
1?2:3
1是真取2,1是假取3
赋值运算符 = 赋值运算
+= -= 复合的赋值运算
*= /= a+=2;//a=a+2

&(逻辑与)和&&(短路与)的区别:
	       当在&表达式中,&号前后的两个表达式,不管是true和false都需要求值.而&&表达式中,当&号前面的表达式为true时,后面的就不在求值.

#三. 分支结构:
顺序结构的程序虽然能解决计算、输出等问题,但不能做判断再选择。对于要先做判断再选择的问题就要使用分支结构。

1. if 语句
1.单分支:                                           2.多分支                                           3.嵌套分支

														if(判断条件1){
														       代码1。。。
														}else if(条件2){
														       代码2。。。
														} else if(判断条件3){
														       代码3。。。
														}else{
														       代码4。。。
														}
2. switch 语句
当一个case成立,从这个case向后穿透所有case,包括default,直到程序结束或者遇到break程序才结束。
        switch(expr1)中,expr1是一个整数表达式, 整数表达式可以是int基本类型或Integer包装类型,由于byte,short,char都可以隐含转换为int,所以也支持。
注意: jdk1.7以后新增 String
	例:
		 int i=3;
		              switch (i) {
		              case 1:
		                     System.out.println("1");
		                     break;
		              case 2:
		                     System.out.println("2");
		                     break;
		              case 3:
		                     System.out.println("3");
		                  break;
		              default:
		                     System.out.println("default");
		                     break;
		              }
		
3. break和continue的区别
	Break: 中断当前循环,简单粗暴,直接结束,不在执行后面的代码.
	Continue: 跳出本次循环,继续执行下面的代码.
4.  default:
	       使用在switch语句中,意思就是当case里的值与switch里的key都不能匹配的时候,执行default里的方法。
		使用在接口中:
		§ default修饰的目的是让接口可以拥有具体的方法,让接口内部包含了一些默认的方法实现。
		§ 被default修饰的方法是接口的默认方法。既只要实现该接口的类,都具有这么一个默认方法,默认方法也可以被重写。

#四. 循环结构:
循环结构是指在程序中需要反复执行某个功能而设置的一种结构.
根据判断条件,循环结构又可细分为先判断后执行的循环结构和先执行后判断的循环结构。

1 .for 循环:
	       根据外层的条件,判断里层能否执行,如果能执行,就把里层代码都循环完毕后,再继续执行外层,继续判断。。
	形式:
		for(开始条件;循环条件;更改条件){
		       循环体代码…
		}
		
2.   while 循环
	先判断在执行,
	形式:
		while(执行条件){
		       代码…
		}
	经典死循环:
		While(true){代码块…}
		
3. do-while 循环
	先执行在判断
	do{
	       代码…
	}while(执行条件);

4. 三种循环的区别:
	1、 for:知道循环次数
	2、 while/do while:当循环次数不确定时
	3、 while:先判断,不符合规则,不执行代码
	4、 do while:代码最少被执行一次,再去判断,符合规则,再次执行代码

#五. 对象:
new出来的对象的地址值存在栈里面,对象的属性和信息存在堆内.通过栈里面的地址值找到堆内的对象进行复制等操作.

new一个对象需要:
Person p = new Person()
1. 把Person.class文件加载进内存
2. 在栈内存中,开辟空间,存放变量p
3. 在堆内存中,开辟空间,存放Person对象
4. 对成员变量进行默认的初始化
5. 对成员变量进行显示初始化
6. 执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
7. 堆内存完成
8. 把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值.
9. 同一个对象,不同的实例,地址值是不同的,都是new出来的就相当与两个对象.
匿名对象:
没有名字的对象,是对象的简化表示形式。
使用场景:
1、 当被调用的对象只调用一次时(多次会创建多个对象浪费内存)
构造方法:
构造方法是一种特殊的方法,它是一个与类同名且返回值类型为同名类类型的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的创建或者对象的初始化。当类实例化一个对象时会自动调用构造方法。
构造方法的使用:
1、 子类创建对象时,默认会去访问父类的无参构造方法
2、 在构造方法的第一行,都有一条默认的语句:super();
3、 父类没有无参构造时,可以用super调用父类的其他构造
封装:
封装是指隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式。
好处:
1、 提高安全性
2、 提高重用性
3. 使用private关键字
继承:
继承是面向对象最显著的一个特性。
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类/超类/基类。
这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
提高复用性:只要继承父类,就能有一样的功能
1、 使用extends关键字
2、 相当于子类把父类的功能复制了一份
3、 java只支持单继承
4、 继承可以传递(爷爷,儿子,孙子的关系)
5、 不能继承父类的私有成员
6、 继承多用于功能的修改,子类可以拥有父类的功能的同时,进行功能拓展
7、 像是is a 的关系
多态:
多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。
主要是指同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
好处是可以把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
1、 多态的前提是继承
2、 要有方法的重写
3、 父类引用指向子类对象,如:Animal a = new Dog(); – 小到大,向上转型
4、 多态中,编译看左边,运行看右边
构造代码块:
1、 在类的内部,方法外部,的代码块。
2、 通常用于抽取构造方法中的共性代码。
3、 每次调用构造方法前都会调用构造代码块
4、 优先于构造方法加载
局部代码块:
1、 在方法里面的代码块
2、 通常用于控制变量的作用范围,出了括号就失效
3、 变量的范围越小越好,成员变量会有线程安全问题
4、 总结:执行顺序:
构造代码块是最优先的,局部代码块顺序执行
静态代码块:
随着类的加载而加载,并且只被加载一次,一般用于项目的初始化
代码块的加载顺序:
静态 - 构造代码块 - 构造方法 - 局部
this关键字:
this代表本类对象的一个引用对象。
构造函数中,this()必须放在第一行。
可以在本类中调用成员变量和方法,包括构造方法, 也用于区分同名的成员变量和局部变量;
super关键字:
通过super关键字可以使用父类的内容
super代表父类的一个引用对象
如果用,必须出现在调用位置的第一行
this和super的区别:
1、 this代表本类对象的引用,super代表父类对象的引用。
2、 this用于区分局部变量和成员变量
3、 super用于区分本类变量和父类变量
4、 this.成员变量 this.成员方法() this(【参数】)代表调用本类内容
5、 super.成员变量 super.成员方法() super(【参数】),代表调用父类内容
6、 this和super不可以同时出现在同一个构造方法里,他们两个只要出现都得放在第一行,同时出现的话,到底第一行放谁呢。
重写与重载的区别:
1、重载:是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同
2、重写:是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型
3、重写是父类与子类之间多态性的一种表现
4、重载是一类中多态性的一种表现

方法的重写:
	1、 继承后,子类就拥有了父类的功能
	2、 那么在子类中,可以添加子类特有的功能也可以修改父类的原有功能
	3、 子类中方法签名与父类完全一样(包括方法的返回值,方法名和参数列表,完全一致)时,会发生覆盖/复写操作,相当于修改功能
	注意:
	1、父类中的私有方法不能被重写
	2、子类重写父类方法时,修饰符要大于等于父类修饰符的权限

#六. 异常:
概述:
用来封装错误信息的对象。
组成结构:类型,提示,行号。
继承结构:
Throwable - 顶级父类
– Error:系统错误,无法修复
– Exception:可修复的错误
–RunTimeException
–ClassCastException
–ClassNotFoundException
–……
异常处理:
程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出。
当调用了一个抛出异常的方法时,调用位置可以不做处理继续向上抛出也可以捕获异常。
#七. 面向对象:
1. 访问控制符:
类 包 子类 任意
public √ √ √ √ (最高级别, 公共的)
protected √ √ √ (相对较少使用)
default √ √ (默认值)
private √ (最低级, 私有化的)
2. 抽象类:
Java中可以定义没有方法体的方法,该方法由其子类来具体的实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。
抽象类可以理解为是一个只有方法声明没有方法体的特殊类。
特点:
1、 通过java关键字abstract实现
2、 可以修饰方法或者类
3、 抽象类中可以没有抽象方法(由子类去实现)
4、 如果类中有抽象方法,那该类必须定义为一个抽象类
5、 子类继承了抽象类以后,要么还是一个抽象类,要么就把所有抽象方法都重写
6、 多用于多态中
7、 抽象类不可以被实例化
8、 既可以有变量,也可以有常量。
9、 抽象类里,既可以有普通方法,有可以有抽象方法。
抽象类也有构造方法,但是不能本身实例化。一般用于给子类实例化。来实现多态.
3. 接口:
Java不允许多重继承,所以如果要实现多个类的功能,则可以通过实现多个接口来实现。
OOP面向对象的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程。
特点:
1、 接口中都是抽象方法
2、 通过interface关键字创建接口
3、 通过implements让子类来实现
4、 可以理解成,接口是一个特殊的抽象类
5、 接口突破了java的单继承的局限性
6、 接口和类之间可以多实现,接口和接口之间可以多继承
7、 接口是对外暴露的规则,是一套开发规范
8、 接口提高了程序的功能扩展,降低了耦合性
9、 接口里没有成员变量,都是常量。
接口可以多继承也可以多实现,甚至可以继承的同时多实现。
接口里是没有构造方法的。
在创建实现类的对象时默认的super(),是调用的默认Object的无参构造。
#八. 类和抽象类和接口的总结
1、类和类的关系:继承 extends / 单继承 / 单根继承
– 继承的意义:为了提高代码的复用性,减少了代码的编写提高开发效率。
– 方法重写的意义:在不修改父类源码的前提下,在子类中重写业务,从此使用的就是重写后的功能。
– 要求子类的方法声明和父类一样,只要改方法体。
– 有了继承有了重写就产生了多态,多态的意义:为了统一程序的调用标准,标准就是父类。
– 多态 也就是向上转型/向上造型。
– 向下造型的意义:很少用,相当于想要使用子类的特殊功能,还不如直接创建子类对象简单。
– class A extends B
– 其中,A和B都是类,A是子类,B是父类,A就拥有了B的所有功能(除了私有的和构造方法)
– 其他知识点:this 和super ,构造方法,各种代码块…
2、类和接口关系:实现implements / 单实现 / 多实现
– class A implements B,C
– 其中,A是实现类,B和C是接口
– 要求A 可以把 B 和C 接口里的所有 抽象方法 都重写掉,否则 A 就是抽象类
– 接口不能创建对象
– 接口里没有构造方法,接口里都是常量,接口里都是抽象方法
3、接口和接口关系:继承extends / 单继承 / 多继承
– 接口的多继承的关系,打破了java单继承的局限性
– interface A extends B,C
– 其中,A B C 都是接口,A是子接口,同时拥有B和C接口里的所有功能
– class AImpl implements A
– 要求AImpl需要重写A接口里的所有方法(是包含B和C接口的所有方法),否则就是抽象类
4、接口和抽象类的区别!!!
– 相同点:都是抽象层,都不能实例化
– 不同点:
1、抽象类用abstract关键字描述,接口用interface
2、子类和抽象类之间是extends关系,实现类和接口之间是implements关系
3、抽象类中 可以 有构造方法 ,接口里 不能 出现 构造方法
4、抽象类里可以有 变量,接口里没有变量全都是静态的常量
5、接口里定义常量的语法:public static final String NAME=“jack”,会为变量自动拼接public static final
6、抽象类里 可以有普通方法 也可以有 抽象方法,接口都是抽象方法
7、抽象类和子类之间是继承关系,而且java中,只支持单继承
8、接口突破了java单继承的局限性,因为接口可以多继承也可以多实现,甚至可以继承的同时多实现
9、接口的复杂用法
–多继承: interface A extends B,C 其中A是子接口,同时拥有自己的和BC的功能
–多实现: class AImpl implements M,N,O,P 其中AImpl是实现类,需要同时重写MNOP的所有抽象方法,否则就是一个抽象类
–继承的同时多实现: class AImpl extends Object implements M,N 一定是先继承后实现
#九. 内部类:
1. 概述:
在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本身就是类的一个属性,与其他属性定义方式一致。
2. 分类:
内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。
a. 静态内部类:
定义在类内部的静态类,就是静态内部类。
静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量;静态内部类的创建方式,new 外部类.静态内部类()。
b. 成员内部类:
定义在类内部,成员位置上的非静态类,就是成员内部类。
成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类()。
c. 局部内部类:
定义在方法中的内部类,就是局部内部类。
定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应方法内,new 内部类()。
d. 匿名内部类:
匿名内部类就是没有名字的内部类,日常开发中使用的比较多。
匿名内部类必须继承一个抽象类或者实现一个接口。
匿名内部类不能定义任何静态成员和静态方法。
当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

#十. StringBuffer和StringBuilder的区别:
StringBuffer加了同步锁,式线程安全的,是先出现的;StringBuilder是非线程安全的,是后出现的。
StringBuilder的效率要高于StringBuffer,而String是最低的,在字符串拼接数较多的时候,不能使用String。
#十一. 自动装箱和自动拆箱:
与数据类型相对应的包装类型,在需要的时候,系统底层会自动帮我们转换,这个过程就是自动装箱和拆箱。
自动装箱:把基本类型包装成一包装类的对象
Integer a = 5;//a是引用类型,引用了包装对象的地址。
编译器会完成对象的自动装箱:Integer a = Integer.valueOf(5);

	自动拆箱:从包装对象中,自动取出基本类型值
	    int i = a;//a现在是包装类型,没法给变量赋值,需要把5取出来。
	编译器会完成自动拆箱:int i = a.intValue();

#十二. IO流:
1. IO概述:
I和O 也就是in/out, 相对于程序而言,对应输入(读取)和输出(写出)的过程。
在Java中,根据处理的数据类型不同,分为字节流和字符流。
2. 什么是流:
Java中的流是对字节序列的抽象,相当于数据的读写抽象成数据,像水一样在管道中流动。像水一样,Java的流也是有方向的,读入一个字节序列的对象叫输入流,写出一个字节序列的对象叫输出流。
Ø 流只能单方向流动
Ø 输入流用来读取(in)
Ø 输出流用来写出(Out)
Ø 数据只能从头到尾顺序的读写一次

一. File文件流

1. 概述:
	封装一个磁盘路径字符串,对这个路径可以执行一次操作。
	可以用来封装文件路径、文件夹路径、不存在的路径。
2. 常用方法:
	length():文件的字节量
	exists():是否存在,存在返回true
	isFile():是否为文件,是文件返回true
	isDirectory():是否为文件夹,是文件夹返回true
	getName():获取文件/文件夹名
	getParent():获取父文件夹的路径
	getAbsolutePath():获取文件的完整路径
	createNewFile():新建文件,文件夹不存在会异常,文件已经存在返回false
	mkdirs():新建多层不存在的文件夹\a\b\c
	mkdir():新建单层不存在的文件夹\a
	delete():删除文件,删除空文件夹

##二. 字节流:
字节流是由字节组成的字节流是用来处理二进制文数据的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,也可以用来处理文本文件。读写字节数据时,建议使用bufferedInputStream/BufferedOutputStream,效率会更高.
1. 实现类:
字节流:针对二进制文件
InputStream
–FileInputStream
–BufferedInputStream
–ObjectInputStream
OutputStream
–FileOutputStream
–BufferedOutputStream
–ObjectOutputStream
2. 输入操作:
a. InputSteam抽象类:
此抽象类是表示字节输入流的所有类的超类和抽象类.
b. FileInputSteam子类:
直接插在文件上,读取数据.
c. BufferedInputStream子类:
添加缓冲输入,支持mark和reset方法,在创建时,会创建一个内部缓冲区数组(默认8M)。在读取字节时可以根据需要从包含的输入流再次填充进缓冲区,一次可以填充多个字节
3. 输出操作:
a. OutputStream抽象类:
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。
b. FileOutputStream子类:
直接插在文件上,直接写出文件数据。
c. BufferedOutputStream
实现缓冲的输出流,可以将各个字节写入底层输出流中,不用针对每次的字节写出调用底层系统

三. 字符流:

        字符流是由字符组成的.,Java里字符由两个字节组成.。用于处理纯文本数据.
	• 输出字符流:把要写入文件的字符序列(实际上是Unicode码元序列)转为指定编码方式下的字节序列,然后再写入到文件中;
	• 输入字符流:把要读取的字节序列按指定编码方式解码为相应字符序列(实际上是Unicode码元序列从)从而可以存在内存中。
1. 实现类: 
	字符流:针对文本文件。读写容易发生乱码现象,在读写时最好指定编码集为utf-8
	Writer
	--BufferedWriter
	--OutputStreamWriter
	Reader
	--BufferedReader
	--InputStreamReader
	--PrintWriter/PrintStream
2. 输入流:
	a. Reader抽象类:
		用于读取字符流的抽象类
	b. InputStreamReader子类:
	       是字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符,字符集可以由名称指定,或者使用默认的字符集.
	c. FileReader子类:
		用来读取字符文件的便捷类,可以自己指定构造方法里的字符编码和字节缓冲区大小.
	d.BufferedReader子类:
	        从字符输入流中读取文本,缓冲各个字符,从而实现高效读取.同时可以指定缓冲区的大小,不过多数情况下,默认的大小就够用了.
3. 写出流:
	a. Writer抽象类
		写入字符流的抽象类。
	b. OutputStreamWriter子类
		是字符流通向字节的桥梁,可以指定要写入流中的字符的编码集,也可以接受默认的编码集。
	c. FileWriter子类:
	       用来写入字符文件的便捷类,可以自己指定构造方法里的字符编码和字节缓冲区大小。也可以使用默认值。
	d. BufferedWriter子类:
	       将文本写入字符输出流,缓冲各个字符,从而实现高效输出,同时可以指定缓冲区的大小,不过多数情况下,默认的大小就够用了。

##四. BIO:
同步阻塞的IO,就是传统的IO,基于流模型实现的。在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用是可靠的线性顺序,优点是:代码比较简单、直观;缺点是:效率和扩展性低,性能较差,处理不了高并发的程序。
五. NIO:
同步非阻塞IO,在传统IO上进行的扩展,实现了多路复用,对于高负载、高并发的(网络)应用,应该使用NIO的非阻塞模式来开发。
六. AIO:
异步非阻塞IO,在NIO模式上进行的扩展。异步IO是基于事件和回调机制实现的,在应用操作之后会直接返回,不会阻塞,当后台处理完成后,系统会让其他线程继续操作。但目前还不够成熟,应用不多。

#十三. 序列化和反序列化:
1. 概述:
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。
在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
序列化:
利用ObjectOutputStream,对象的信息,按固定格式转成一串字节值输出并持久保存到磁盘化。
反序列化:
利用ObjectInputStream,读取磁盘中序列化数据,重新恢复对象。
简单来说:序列化就是将对象转换成字节流的过程。反序列化就是将字节流回复成对象的过程。
2. 应用场景:
• 对象的持久化(将对象内容保存到数据库或文件中)
• 远程数据传输(将对象发送给其他计算机系统)
• 常用于服务器之间的数据传输,序列化成文件,反序列化读取数据。
• 常用于使用套接字流在主机之间传递对象。
3. 特点:
1、 需要序列化的文件必须实现Serializable接口以启用其序列化功能。
2、 不需要序列化的数据可以被修饰为static的,由于static属于类,不随对象被序列化输出。
3、 不需要序列化的数据也可以被修饰为transient临时的,只在程序运行期间,在内存中存在不会被序列化持久保存。
4、 在反序列化时,如果和序列化的版本号不一致时,无法完成反序列化。
5、 每个被序列化的文件都有一个唯一id,如果没有添加编译器会根据类的定义信息计算产生一个版本号。
4. ObjectOutPutStream
将对象的基本数据类型和图像写入OutputStream,通过在流中使用文件可以实现对象的持久储存。
5. ObjectInputStream
对以前使用ObjectOutputStream写入的基本数据和对象进行反序列化。

#十四. 泛型:
1.概念:
即“参数化类型”,将类型由原来的具体的类型参数化,类似于方法中的变量参数,是一个语法糖,是编译器为了提供更好的可读性。在虚拟机层面是没有所谓的泛型概念的,编译之后泛型就会被删除,不会出现在最终的源代码中,也就是说不会影响程序的最终运行。
2.作用:
类型擦除,提供了编译器的类型安全,把错误显示在编译期,避免在运行时才出现异常。
使代码的通用性更强。
提升代码的可读性。
泛型类、泛型方法、方法接口、泛型集合。

#十五. 集合:
1.概述:
用于储存对象的容器。
2. 集合类:
Map接口和Conllection接口是所以集合框架的父接口:
1.Conllection接口的子接口有:Set接口和List接口;
2.Map接口的实现类主要有:HsahMap、TreeMap、Hashtable、ConcurrentHashMap、Peoperties等;
3.Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等;
4.List接口的实现类主要有:ArrayList、LinkedList、Stack、Vector等;
如图:

3. Conllection接口:
		主要有List和Set两大接口。
	a.  List:
		       有序的(元素存入集合的顺序和取出的顺序一致),元素可以重复的,可以插入多个null元素,每个元素都有索引,方便检索。并且支持for循环,也就是通过下标来遍历,也可以使用迭代器。常用实现类:ArrayList、LinkedList、以及 TreeSet。
		①ArrayList:
			       底层以数组结构实现,支持随机访问,缺点是元素之间不能有间隔。当从ArrayList中插入或删除元素时,需要对数组进行复制、移动,代价比较高,因此它适和查询和顺序添加,不适合插入和删除。
		②LinkedList:
			       底层以双向链表结构存储数据的。在进行查询操作时,需要移动指针从前后两端依次查找,效率较低。在进行插入和删除操作时,只需要修改要操作元素的前后两个元素的指针就行。因此适合插入和删除,不适合查询和遍历。
		③Vector:
			      与ArrayList一样,都是通过数组实现的,不同的是它是支持线程同步的,即某一个时刻只有一个线程能进行操作。因此它的效率比ArrayList慢,但它是线程安全的。
	b. Set:
		       无序的(存入和取出顺序有可能不一致),元素不可重复的,只允许存入一个null元素,必须保证元素的唯一性,常用来去重。检索效率较低,删除和插入效率高,插入和删除操作,不会引起元素位置改变。常用实现类:HashSet、LinkedHashSet、TreeSet。
		①HsahSet:
			       存储元素不是按照存入时数据的顺序来进行存储,而是按照哈希值来存的,所以取的时候也是按照哈希值取的,而哈希值是通过Hashcode方法获取的。
			         HashSet首先会判断两个元素的Hash值是否相等,接着会用equals方法进行比较,如果两次比较都相等,则视为是同一个元素。
			       当哈希值相等,equals不等时,元素就在相同哈希值下顺延(就像糖葫芦一样,往下串起来)。也就是将哈希值不同的存在一行上,相同的存在一列。
		②LinkedHsahSet:
			       继承于HashSet,又基于LikdedHashMap来实现的。底层使用LikedHashSet来保存元素,方法操作上和HashSet相同。HashSet的值存在HashMap的key上,value统一为PERSENT,实现起来较为简单。
		③TreeSet:
			       是使用二叉树的原理对新add()对象按照指定的顺序进行排序,每次添加都会重新排序,将对象插入指定的位置。
4.Conllections类:
	Conllection的工具类,提供了一系列的静态方法,用于对集合中元素进行排序、搜索等等操作。
5. Map接口:
		       储存一组键值对象,提供key(键)到value(值)的映射。键是唯一的,值可以重复。常用实现类有:HsahMap、Hashtable、ConcurrentHashMap等;
			可以根据键提取对应的值;键不允许重复,如果重复了,后添加的会覆盖先添加的;无序的,初始容量是16,默认加载因子是0.75.
	①HashMap:
			由 数组+链表+红黑 树 组成。 
		       根据键的hashcode值存储数据,大多数情况下可以直接地位到对应的值,因此查询速度较快,但是在遍历时,遍历顺序时不确定的。只允许一条记录的键为null,但是值可以有多个null。它是非线程安全的。
		JDK8 HashMap的结构:
			

	②ConcurrentHashMap
		      支持并发操作,底层由由一个个 Segment 组成,Segment 代表”部分“或”一段“的 意思,所以很多地方都会将其描述为分段锁。是线程安全的。
	③HashTable
		Hashtable 是遗留类,很多映射的常用功能与 HashMap 类似,不同的是它承自 Dictionary 类, 并且是线程安全的。
6. Iterator接口:
	      提供遍历任何Conllection的接口,使用迭代器方法来获取迭代器实例,再通过实例对集合进行操作。只能单向遍历,确保在遍历的同时如果元素被更改的时候会抛出异常。可以边遍历边移除。
7. ListIterrator:
	实现了Iterator接口,进行功能扩展。只能遍历List集合,可以双向遍历(向前/向后)。

#十六. 多线程:
1. 进程:
a. 概念:
就是正在运行的程序,代表了程序锁占用的内存区域。
b. 特点
l 独立性:进程是系统中独立存在的实体,它可以拥有自己的独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间。
l 动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念,进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的。
l 并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。
2. 线程:
a. 概念:
是操作系统 能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位,一个 进程可以有多个进程。
多线程拓展了多进程的概念,使得同一个进程可以同时并发处理多个任务;
一个程序最少有一个进程,一个进程有多个线程;
如果一个进程只有一个线程,这个程序被称为单线程;
如果一个进程中有多条执行路径,就被称为多线程。

3. 多线程的特性:
	a. 随机性:
			

	b. 线程的五种状态:
		

		1)   新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
		2)   就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
		3)   运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
		4)   阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态;
	                  4.1)根据阻塞产生的原因不同,阻塞状态又可以分为三种
			a)   等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
			b)   同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
			c)   其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
		5)   死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
		
4. 多线程的实现:
		继承Thread类或者实现Runnable接口。或基于线程池获得线程。
	1.继承Thread类:
		a. 概述:
			      本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法,这是一个native方法(也就是一个不是用Java语言编写的方法),他将通知底层操作系统,最终由操作系统启动一个新线程,执行run()方法。
		b. 实现方式:
			       通过自己的类直接继承Thread类,并重写run()方法,将需要多线程执行的代码写在run()方法体内,就可以启动新线程并执行自己定义的run()方法。
	2. 实现Runnable接口:
		a. 概述:
			       如果自己的类以及继承了一个类,就无法再继承Thread,此时想要实现多线程,就得实现Runnable接口。
		b. 实现方式:
			       用一个类实现Runnable接口,重新run()方法,将想要多线程实现的代码写在方法体内。实现时,创建该类的实例,在new一个Thread类,并将该实例传进去。在掉用start()方法开启线程。
	3. 线程池:
		a. 概述:
			使用缓存的策略,实现线程的复用。避免资源的浪费。
		b. 实现方式:
			newCachedThreadPool :
				       创建一个可根据需要创建新线程的线程池,对于执行 很多短期异步任务的程序而言,这些线程池通常可提高程序性能。
			newFixedThreadPool :
				创建一个可重用固定线程数的线程池,,以共享的无界队列方式来运行这些线程。
			newScheduledThreadPool:
				创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 
			newSingleThreadExecutor:
				       Executors.newSingleThreadExecutor()返回一个线程池(这个线程池只有一个线程)。
5. sleep 与 wait 区别 :
	      1. 对于 sleep()方法,我们首先要知道该方法是属于 Thread 类中的。而 wait()方法,则是属于 Object 类中的。
	       2. sleep()方法导致了程序暂停执行指定的时间,让出 cpu 该其他线程,但是他的监控状态依然 保持者,当指定的时间到了又会自动恢复运行状态。
	       3. 在调用 sleep()方法的过程中,线程不会释放对象锁。
	       4. 而当调用 wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此 对象调用 notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
6. . start 与 run 区别:
	      1. start()方法来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕, 可以直接继续执行下面的代码。
	       2. 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运 行。 
	       3. 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运 行 run 函数当中的代码。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程。 
7. 同步锁:
	a. 概念
	       把有可能出现问题的代码包起来,一次只让一个线程执行。通过sychronized关键字实现同步。
	当多个对象操作共享数据时,可以使用同步锁解决线程安全问题。
	b. 特点:
		1、 前提1,同步需要两个或者两个以上的线程。
		2、 前提2,多个线程间必须使用同一个锁。
		3、 同步的缺点是会降低程序的执行效率,  为了保证线程安全,必须牺牲性能。
		4、 可以修饰方法称为同步方法,使用的锁对象是this。
		5、 可以修饰代码块称为同步代码块,锁对象可以任意。

#十七. 反射:
1. 概念:
指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法; 并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方 法的功能成为 Java 语言的反射机制。
反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。
2. 应用:
a. 获取类对象
b. 获取构造方法
c. 获取成员方法
d. 获取成员变量
e. 创建对象
3. 暴力反射:
指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。

#十八. 注解:
1. 概述:
是 Java 提供的一种对元程序中元素关联信息和元数据(metadata)的途径 和方法。程序可以通过反射来获取指定程序中元素的 Annotation 对象,然后通过该 Annotation 对象来获取注解中的元数据信息。
2. JDK注解:
JDK注解的注解,就5个:
l @Override
l @Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期
l @SuppressWarnings(“deprecation”) 忽略警告
l @SafeVarargs jdk1.7出现,堆污染,不常用
l @FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用
3. 元注解:
描述注解的注解,就5个:
l @Target 注解用在哪里:类上、方法上、属性上
l @Retention 注解的生命周期:源文件中、class文件中、运行中
l @Inherited 允许子注解继承
l @Documented 生成javadoc时会包含注解,不常用
l @Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用
4. 自定义注解:
自己可以根据需求定义注解,创建@interface修饰的注解类,利用元注解对其进行修饰,再添加需要的代码。

#十九. 设计模式:
1.单例模式:
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。保证一个类在内存中的对象就一个。
目的:控制外界创建对象的个数只能创建1个对象。
开发步骤:
1、 私有化构造方法,不允许其他类new对象。
2、 通过new在类的内部创建好对象(自己)。
3、 对外界提供一个公共的get(),返回一个已经准备好的对象
a.饿汉式:
在类加载的时候就完成实例化,避免了线程同步的问题,但是没有达到懒加载的效果,会造成内存的浪费。自己直接 new一个自己的实例。在通过get方法返回这个实例。
b.懒汉式:
new一个null,在get方法里通过判断来决定在需要的时候才创建对象,实现懒加载的效果。
懒汉式有线程安全和线程不安全两种,单纯在get方法上加synchronized可以解决线程安全的问题,但是性能太低。使用双重校验锁,可以很好的解决这个问题。
c. 静态内部类:
和饿汉式一样,利用类加载机制来保证只有一个实例对象,不同的是,它在内部类里面去实现的,这样的话,只要不使用内部类,就不会创建该实例来占用内存,从而实现懒加载。
d. 枚举:
在枚举中我们明确了构造方法限制为私有,在我们访问枚举实例时会执行构造方法。
同时每个枚举实例都是static final类型的,也就表明只能被实例化一次。在调用构造方法时,我们的单例被实例化。
在我们要通过网络传输一个数据库连接的句柄,会提供很多帮助。

       2. 开闭原则:
	       开放功能扩展,关闭源码修改。等
	       开闭原则的英文全称是Open Close Principle,缩写是OCP,它是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的、灵活的系统。
	       开闭原则的定义是:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封的。
	       开闭原则,是一种设计模式,随着面向对象程序设计的思想,应运而生。
         开,指的是可以在源代码的基础上进行扩展,比如继承,接口,抽象类等。在JAVA中,之所以用继承,是在可以直接调用类库的前提下,对其功能进行扩展。不需要应用者去了解封装类的内部逻辑就可以做开发。
	闭:指不允许对原有的代码进行修改。以免影响其他现有功能,造成功能瘫痪。

#二十. 进制转换:
1. 概念:
进制也就是进位计数制,是人为定义的带进位的计数方法,类似于统计“正”字。
对于任何一种进制—X进制,就表示每一位置上的数运算时都是逢X进一位。
十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推。
通常情况下,1byte=8个二进制位
所以表示一个数字用二进制来表示的话就可以这样表示:0000 0000
把这8个位进行组合,每三位组合就形成了八进制,每四位组合就形成了十六进制。
2. 特点:
二进制:0和1,逢二进一,以0b开始
八进制:0-7,逢八进一,以0开始
十进制:0-9,逢十进一
16进制:0-9,abcdef,逢16进一,以0x开始
3. 进制的转换:
a. 十进制转二进制:
十进制数不断除以2,一直到商为0为止,取余数,在把余数倒着些,就是二进制数。
例: 把十进制11转成2进制:1011

	b. 二进制转十进制数:
		从低次位,每次乘以2的位次次幂,在求和。
		    例:
			计算二进制数据:0000 1101对应的十进制
			
			0110 1110对应的十进制
	c. 二进制转八进制:
		从低次位开始,没三位位一组,产生一个八进制数字,最高位不足补零。
		     例:
			计算二进制数据110 0111对应的八进制
			
		
	d. 八进制转二进制:
		把一个数字转为三个数字,不住三位的,最该位补0;
		      例:  
			  计算八进制数据:023 0653对应的二进制数据

#二十一. Lambda表达式:
1. 概念:
一个重要用法是简化某些匿名内部类(Anonymous Classes)的写法。只能用来取代函数接口(Functional Interface)的简写。
实际上Lambda的类型就是对应函数接口的类型。Lambda表达式另一个依据是类型推断机制,在上下文信息足够的情况下,编译器可以推断出参数表的类型,而不需要显式指名。

2. 例:
	// Lambda表达式的书写形式

①Runnable run = () -> System.out.println(“Hello World”);// 1
②ActionListener listener = event -> System.out.println(“button clicked”);// 2
③Runnable multiLine = () -> {// 3 代码块
System.out.print(“Hello”);
System.out.println(" Hoolee");
};
④BinaryOperator add = (Long x, Long y) -> x + y;// 4
⑤BinaryOperator addImplicit = (x, y) -> x + y;// 5 类型推断
①展示了无参函数的简写;②处展示了有参函数的简写,以及类型推断机制;
③是代码块的写法;④和⑤再次展示了类型推断机制。
#二十一. 时间复杂度:
1. 定义:
a. 时间频度:
一个算法花费的时间与算法中语句的执行的次数成正比,执行的多耗时就大。语执行的次数称为语句频度或时间频度,用T(n) 表示,n表示问题的规模。
b. 时间复杂度:
①概述:
用来体现问题的规模,而不是具体的次数。
②计算方法:
一般情况下,算法中基本操作重复执行的次数是问题规模的某个函数,用T(n) 表示;有等式T(n)=O(f(n)),0(f(n))被称为算法的渐进时间复杂度,简称时间复杂度。
或者说:时间复杂度就是时间频度去掉低阶项和首项的常数。
③常用的时间复杂度级别:
常数阶O(1)
对数阶O(log2n)
线性阶O(n)
线性对数阶O(n*log2n)
平方阶O(n2)
立方阶O(n3)
。。
K次方阶0(nk)
指数阶O(2n)
阶乘阶O(n!)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值