Java知识点总结
2023-04-13 16:06:26 3 举报
AI智能生成
Java面试前个人总结,持续更新~~
作者其他创作
大纲/内容
数据库
MYSQL
1、数据库概述
数据库(DATA BASE 单词一定要记住面试问到了)是指长期保存在计算机存储设备上,按照一定的规则组织起来,可以被各种用户共享的数据集合
2、SQL:(Structure Query Language)结构化查询语言
3、SQL的分类
1、DDL数据定义语言
用来定义数据库对象:库、表、列等。包括创建表、修改表、删除表
2、DML数据操作语言
用来定义数据库记录:是对表中数据的操作,包括插入,更新,删除数据
3、DQL数据查询语言
用来查询记录(数据):只有SELECT
4、DCL数据控制语言
用来定义访问权限和安全级别
4、mysql之连接
外连接
左连接(左外连接):以左表为主表进行查询,左表的数据会全部显示出来,右表如果和左表匹配的字段会显示出来,若没有则显示null
右连接(右外连接):以右表为主表进行查询,右表的所有数据会显示出来,左表如果和右表有相同的字段会显示出来,没有则显示null
全连接
先以左表为主表左连接,再以右表为连接进行右连接
内连接
显示表之间相匹配的所有行
5、mysql之sql注入
通过在web表单中输入恶意sql语句,会得到一个存在安全问题的数据库,不是按照程序的设定着去执行sql。
举例:当执行sql语句“select * from user where username='admin' or 'a='a';”时,sql语句恒成立,输入的参数admin毫无意义
防止sql注入
预编译语句:“select * from user where username=?”;sql语句的语义不会发生改变,sql语句中的参数用?表示,即使传入了“admin or 'a'='a'”时,也只会把这个参数当做字符串去处理。
mybatis框架中的#也可以防止sql注入,$符号无法防止sql注入
6、mysql中的性能优化
1、如果你已知一条sql语句查询只有一个结果,这种情况下加上limit 1会增加性能;因为mysql会在找到这条结果后停止查找,而不是继续查找所有数据。
2、选择正确的数据库引擎引擎
不同版本的数据库好像引擎个数是不一样的,好像都是10个左右,但是主流的是Mylsam和InnoDB,每个引擎都有自己的利弊
Mylsam
MylSAM引擎适用于大量的读取操作,说白了就是查找快,但是对于写功能较弱,甚至你只要update一个字段整个表都会被锁起来,别的进程进行读操作时,也要等到这个update执行完毕;另外MylSAM对于select count(*)这类查询是非常快的
InnoDB
InnoDB的存储引擎的趋势是一个非常复杂的存储引擎,在一些小的应用上可能比MylSAM还慢,但是他是支持“行锁的”,所以他的写功能是远高于MylSAM的;并且也是最主要的,他还支持高级应用(如事务)。
3、用 not exists 代替not in
数据量大时,not exists能够用到连接用到的索引,not in 不能,所以他慢,not in 最慢的 方式是会同所有的记录进行比较
4、对操作符的优化
尽量不要使用不利于索引的操作符 如 in 、 not in、null、is not null、 < >等
7、MylSAM和InnoDB的区别
MylSAM是mysql默认提供的存储引擎,其特点是不支持事务,行锁和全文索引,但对于查找来说操作快,对更新操作支持效率较低
InnoDB引擎支持事务,并且支持行锁,支持外键,是事务的首选引擎
8、mysql事务的介绍
mysql数据库好其他数据库的不同是将事务交给一个存储引擎所决定,事务就是为了解决一组更新操作要不全部成功,要不全部失败
mysql默认采用的是自动提交事务,除非显示开始一个事务
SHOW VARIABLES LIKE 'AUTOCOMMIT';修改自动提交模式,0=OFF,1=ON
注意:修改自动提交非事务型表是无效的,因为他们本身就没有事务提交和回滚的概念
9、事务的四大特征
A
原子性:事务一旦提交,要么全部成功,要么全部失败;不可能停滞在中间某个环节,一旦发生错误,回回滚到事务提交之前的状态,就像这个事务从来没有被提交一样
C
一致性:事务开始结束直接,数据库的完整约束性不能被破坏
I
隔离性:隔离状态下执行事务,使他们在同一时间内执行的位移操作;就是说,如果在相同时间内,同时执行相同的功能,事务的隔离性只能等待第一个事务执行完毕才能去执行第二个
D
持久性:当事务执行完毕后,事务所进行的操作会永久保存在数据库中,不会发生回滚操作
10、mysql中的四种隔离级别
读已提交
脏读、不可重复读、幻读
读未提交
不可重复读、幻读
可重复度
幻读
串行读
11、mysql的存储过程
存储过程是mysql5增加的新功能,其优点有一箩筐,主要还是sql代码封装和运行效率,且容易维护,执行效率高
语法:下面代码创建了一个叫 pr_add 的 MySQL 存储过程,这个 MySQL 存储过程有两个 int 类型的输入参数“a”、
“b”,返回这两个参数的和
“b”,返回这两个参数的和
create procedure pr_add ( a int, b int ) begin declare c int;
if a is null then set a = 0;
end if;
if b is null then set b = 0;
end if;
set c = a + b;
select c as sum;
if a is null then set a = 0;
end if;
if b is null then set b = 0;
end if;
set c = a + b;
select c as sum;
调用存储过程:call pr_add(10, 20);
12、mysql之触发器
mysql对触发器的支持:触发器是一种与表操作有关的数据库对象,当触发器所在表发生指定事件时,将调用该对象,即表操作事件上的触发器去执行。
mysql中创建触发器的语法:
CREATE TRIGGER trigger_name
trigger_time
trigger_event ON tbl_name
FOR EACH ROW
trigger_stmt
trigger_time
trigger_event ON tbl_name
FOR EACH ROW
trigger_stmt
trigger_name:标识触发器名称,用户自行指定;
trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
trigger_event:标识触发事件,取值为 INSERT、UPDATE 或 DELETE;
tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
trigger_stmt:触发器程序体,可以是一句 SQL 语句,或者用 BEGIN 和 END 包含的多条语句。
由此可见,可以建立 6 种触发器,即:BEFORE INSERT、BEFORE UPDATE、BEFORE DELETE、AFTER INSERT、
AFTER UPDATE、AFTER DELETE
trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
trigger_event:标识触发事件,取值为 INSERT、UPDATE 或 DELETE;
tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
trigger_stmt:触发器程序体,可以是一句 SQL 语句,或者用 BEGIN 和 END 包含的多条语句。
由此可见,可以建立 6 种触发器,即:BEFORE INSERT、BEFORE UPDATE、BEFORE DELETE、AFTER INSERT、
AFTER UPDATE、AFTER DELETE
13、mysql中where可以对null值进行判断吗
可以的,select * from user where num is null;这样的语句可以是可以,但是不建议数据库中有null值,因为null可以也会占空间的,因为char(100),在表建立的时候空间就已经确定了
14、mysql中的中文乱码完美解决方案
不管什么数据库或者jsp页面等,解决乱码的核心思想就是同一编码
1、首先在建数据库或者建表时候,我们就同一编码UTF-8,因为该编码几乎兼容了世界上大部分字符
2、数据库在安装的时候就设置UTF-8,安装时候我好像记得默认就是UTF-8
15、mysql中哪些方法可以代替in
在项目中数据量大的话,其实用in查询效率极低,
代替他的方法 exists
将in改为连接查询
16、左连接查询中,left jion on 后面再加条件的话,用什么?where和and的区别是什么
一般我用连接查询的话,条件用的and,但是今天朋友面试遇到了,仔细查了一下是and。。。
1、and是在生成临时表时使用的条件,不管on的条件是否为真,都会返回左表的记录,和右表关联不上的,右边的表则会显示null
2、where是在临时表生成后,在进行条件过滤的,此时已经失去了left join on(必须返回左表表的记录)的意义了,条件不为真就过滤掉了
Orcale
1、什么是存储过程?他的优点
存储过程是一组完整的sql语句集,经过编译后存储在数据库中,用户根据存储过程名字并给出指定的参数来执行他
优点
允许模块化设计,只需要创建一次,以后你只管调用就完了
允许更快执行,如果要进行大量重复操作,存储过程要比执行sql要快
减少网络流量,比如执行上百行的sql,不需要再网络上发送数千行代码
更安全
2、如何使用游标?
1、orcale中的游标分为显示游标和隐士游标
2、显示游标是通过cursor...is命令来定义游标的,他可以对select语句的查询记录进行处理
3、隐士游标是在执行insert 、update、delete和返回单条select语句中由pl/sql自动定义的
4、显示游标的操作:打开游标,关闭游标,操作游标
3、orcale中怎样进行字符串拼接的
orcale中通过 || 进行字符串拼接的
例如 “ab”|| "cd" 返回结果是abcd
4、orcale中是如何进行分页的
与mysql的分页函数limit不同,orcale中使用rownum进行分页的,这是效率最好的分页方法,hirbarnate也是用rownum分页的
语句:select * from
( select rownum r,a from tabName where rownum <= 20 )
where r > 10
( select rownum r,a from tabName where rownum <= 20 )
where r > 10
5、orcale数据库中有没有自增?除了uuid,还有什么办法给id赋值
orcale数据库中没有自增,一般在项目中我是通过UUID插入时让其id自增,除了这种方法还有其他方法
序列化+触发器
第一步:创建序列化sequence
create sequence seq_t_dept
minvalue 1
maxvalue 99999999
start with 1
increment by 1
cache 50
create sequence seq_t_dept
minvalue 1
maxvalue 99999999
start with 1
increment by 1
cache 50
第二步:建立触发器
create or replace trigger "dept_trig"
before insert on dept_p
referencing old as old new as new for each row
declare
begin
select seq_t_dept.nextval into :new.dept_sort from dual;
end dept_trig;
create or replace trigger "dept_trig"
before insert on dept_p
referencing old as old new as new for each row
declare
begin
select seq_t_dept.nextval into :new.dept_sort from dual;
end dept_trig;
子主题
web
常用设计模式
J2se
java历史
1991 年Sun公司的James Gosling等人开始开发名称为 Oak 的语言,希望用于控制嵌入在有线电视交换盒、PDA等的微处理器;
1994年将Oak语言更名为Java;
Java的三种技术架构:
JAVAEE:Java Platform Enterprise Edition,开发企业环境下的应用程序,主要针对web程序开发;
JAVASE:Java Platform Standard Edition,完成桌面应用程序的开发,是其它两者的基础;
JAVAME:Java Platform Micro Edition,开发电子消费产品和嵌入式设备,如手机中的程序;
1994年将Oak语言更名为Java;
Java的三种技术架构:
JAVAEE:Java Platform Enterprise Edition,开发企业环境下的应用程序,主要针对web程序开发;
JAVASE:Java Platform Standard Edition,完成桌面应用程序的开发,是其它两者的基础;
JAVAME:Java Platform Micro Edition,开发电子消费产品和嵌入式设备,如手机中的程序;
JDK
Java Development Kit:java的开发和运行环境,java的开发工具和jre。
JRE
JRE:Java Runtime Environment:java程序的运行环境,java运行的所需的类库+JVM(java虚拟机)
javac命令和java命令做什么事情呢?
javac
负责的是编译的部分,当执行javac时,会启动java的编译器程序。对指定扩展名的.java文件进行编译。 生成了jvm可以识别的字节码文件。也就是class文件,也就是java的运行程序。
java
负责运行的部分.会启动jvm.加载运行时所需的类库,并对class文件进行执行.一个文件要被执行,必须要有一个执行的起始点,这个起始点就是main函数.
数据类型
类型转换:
自动类型转换
byte->int->->long->float->double
强制类型转换
范围大的->范围小的
需要加强制转换符
数值型
byte
1字节
8位
-128~127
short
2字节
16位
-32768~32767
int
4字节
32位
-2^32~2^31-1
Long
8字节
64位
-2^64~2^63-1
浮点型
float
4字节
32位
double
8字节
64位
字符型
char
2字节
16位
0~65535
boolean
true
false
引用类型
字符串:String
类:Class
枚举:enum
接口:interface
二进制普及
计算机的数据都是以二进制保存
计算机的存储单位
位(bit):是计算机存储信息的最小单位
字节(byte):一个字节有8个位组成
java中的转义字符
\n(换行)
\r(回车)
\t(水平制表)
‘(单引号)
“(双引号)
\(斜杠)
运算符
算数运算符
+
可以作为连接符
-
*
/
%
任何数%2不是0就是1,所以改变模数就可以实现开关运算
赋值运算符
=
+=
-=
*=
/=
%=
比较运算符
特点:运算完结果要不是true,要不是false
逻辑运算符
&
两边为true,则true,一边为false,则都false
|
一边为true则true,false一样
^
相当为false,不同为true
!
条件为true,返回false,取反
&&
&&和&的区别:
&
无论左边结果是什么,右边都参与运算
&&
短路与,若左边为false,则右边不会参数运算,所以开发中用的多,性能高
||
|和||的区别:
|:
无论左边什么结果,右边都参与运算
||:
短路或,若左边为true,则右边不参与运算
位运算运算符
&
两个操作数中位都为1,结果才为1,否则结果为0
|
两个位只要有一个为1,那么结果就是1,否则就为0
^
两个操作数的位中,相同则结果为0,不同则结果为1。
~
如果位为0,结果是1,如果位为1,结果是0,取反
位移运算符
<<左移
使指定值的所有位都左移规定的次数。
>>右移
使指定值的所有位都右移规定的次数。
>>>无符号右移
无符号右移规则和右移运算是一样的,只是填充时不管左边的数字是正是负都用0来填充,无符号右移运算只针对负数计算,因为对于正数来说这种运算没有意义
无符号右移运算符>>> 只是对32位和64位的值有意义
无符号右移运算符>>> 只是对32位和64位的值有意义
三目运算符
x ? y : z
X为boolean类型表达式,先计算x的值,若为true,整个三目运算的结果为表达式Y的值,否则整个运算结果为表达式Z的值。
基本语法
if
当判断固定值时,可以用if,也可以用switch,建议switch,效率高
switch
当判断数据范围,获取判断运算结果boolean类型时,需要使用if
if和switch区别
if
if可以判断范围,也可以判断一个值
对数据判断灵活,自身格式也灵活
switch
switch只能判断指定的值
若需要判断指定的值用switch,效率高
while
不知道循环次数时,用while
while(true)死循环
for
知道循环次数用for
do while
while和dowhile的区别
while
先判断后执行,第一次false后面都不执行
do while
先执行一次,再判断至少执行一次
break和continue的区别
break
用于switch语句和循环语句,跳出循环,结束循环(跳出循环)
continue
结束本次循环,继续下次循环(跳过循环)
方法
为什么使用方法
减少重复代码,可以将重复代码提取出来
写在类中
void关键字
如果方法的返回值类型是void,不加return
return的作用
结束函数,结束功能
将数据返回给使用者
数组:
数组是相同类型数据的有序集合(大小,顺序都有序),数组中可以存基本类型元素,也可以存引用类型的元素,数组的length是固定的一旦确定,不能修改;
面向对象
什么是面向对象?
面向是:对的一种事务的一切操作。对象就是这种事务。面向对象就是对对象的一系列操作。java中的对象是通过new关键字进行实现的。
什么是类?
类是具备某些共同特征的实体的集合,它是一种抽象的概念,用程序设计的语言来说,类是一种抽象的数据类型,它是对所具有相同特征实体的抽象。
类是抽象化的概念
什么是对象?
看得见,摸得着的具体事物
类和对象的关系?
类是对象的模板/抽象化概念,对象是类的实例
类加载机制
子主题
栈
先进后出,存放基本类型的变量名和变量值,引用类型的变量名,方法执行时入栈
堆
先进先出,new出来的对象和实例,包括类的属性和方法
关键字static(静态)
- static可以修饰属性、方法,代码块,不可以修饰类和构造方法
静态方法随类的加载而加载
在静态方法区内的东西只有一份,所有的对象共享这一份空间,只要有一个对象对属性进行修改,所有的对象调用都是修改后的数据。
代码块的执行顺序:静态代码块(只被调用一次)>构造代码块{}>构造方法>普通方法(需调用)
面向对象思想特征及理解
继承
概念:让类与类产生父子关系,子继承父,子类可以用于父类非私有的成员变量和方法
特征:java是单继承,没有继承的类都默认继承超类,Object
可以提高代码的复用性,减少代码的重复性
封装
概念:将类的某些信息隐藏在类的内部,不允许外部程序直接访问,留出对外访问的接口
理解:对成员变量的把控更加准确,减少代码的耦合性,便于修改,提现代码可维护性
说白了,将对象私有化,并提供对外接口
多态
概念:同一对象在不同状态下产生的状态或行为
特征:必需要有继承或者实现,要有方法的重写,父类引用指向子类引用
抽象类(abstract)
抽象类格式:访问权限修饰符 abstract 类名{}
抽象方法格式:访问权限修饰符 abstract 返回值类型 方法名(形式参数列表);
注意点
如果一个类中有抽象方法,那么这个类必须声明为抽象类
类继承抽象类
把子类也用abstract修饰,变成抽象类
子类重写父类的抽象方法
抽象类不能创建对象
抽象类可以有构造方法,在创建子类的时候,super隐式调用父类的构造方法,将父类的属性和方法放到子类的对象空间里。
在继承关系中,子类可以继承抽象类的非私有的对象和方法
只有公开的才可以和abstract连用,static final private 都不可以。
static属于类方法,不允许覆盖,abstract必须被覆盖。final不能被重写。
static属于类方法,不允许覆盖,abstract必须被覆盖。final不能被重写。
接口(interface)
作用
规范了代码,提高了代码扩展性
格式:表示访问权限的修饰符 interface 接口名称{}
实现类格式
访问权限的修饰符 class 类名 implements 接口名称{必须实现此接口下的所有抽象方法}
接口中只有全局变量和抽象方法
接口在实现的同时要继承,extends在implements前面,先继承后实现
接口可以多实现,但继承技能单继承,
抽象和接口的区别
抽象abstract
关键字abstract
抽象类继承extends
子类继承抽象类和实现接口方式不同
抽象类中有各种属性和方法
抽象类只能单继承
抽象类的子类只能继承一个父亲
抽象类的作用是提高代码的复用性
接口interface
关键字interface
接口实现implements
接口中只有全局变量和抽象方法
接口可以多实现
实现类不仅可以实现多个接口,还可以继承父类
接口作用:1、规范代码2、提高代码拓展性
访问权限的修饰符
public(公共的)
同一个类中、同一个包中、具有继承关系的不同包、不同包
protected(保护)
同一个类中、同一个包中、具有继承关系的不同包、不同包
defalut(默认)
同一个类中、同一个包中
private(私有)
同一类中
方法的重写和重载
重写
在具有父子关系的两个类中,方法的名字一样,参数一样,返回值一样,表示访问范围的关键字越来越大
重载
在一个类中,方法的名字一样,参数不同,与返回值和表示访问范围的关键字没有关系
this和super关键字
this
this表示当前类的对象,调用当前类的构造函数
this可以调用属性,方法,构造器
this调用属性方法时,调用本类的属性和方法,如果没有,那就用super去父类中找
this调用构造方法时,调用的是本类的构造方法
this和super调用构造方法时, 必须放在第一行
this和super不能同时存在
super
super表示当前父类对象,调用当前父类的构造函数
super也可以调用对象,方法,构造器
super调用父类的构造方法
final、finally、finalize的区别
final
final修饰的变量为常量,变量名需要大写,final修饰的类为完美类,不能被继承,final修饰的方法不能被重写
finally
finally是异常处理时,在finally块执行的清除操作(关闭流、关闭连接池等),无论是否发生异常,finally语句块中的代码都会被执行
finalize
finalize()方法是垃圾收集器在删除对象之前调用的方法,在Obj中定义,所有类都继承他,子类覆写finalize()方法整理系统资源或其他清除工作,一般由jvm调用,程序员一般不要去调用
==和equals的区别(都返回boolean)
==
比较运算符
比较基本类型是比较值得大小
比较引用类型比较的是地址
equals
equals比较的是两个对象的内容是否相等
equals内部实现的三部
1、比较引用是否相同(比较是否为同一对象)
2、比较是否为同一对象
3、最后比较内容是否相等
内部类
成员内部类
1.可以使用四种访问权限修饰符
2.可以有自己的属性和方法,非静态的
3.可以使用外部类所有的属性和方法,包括私有的
4.创建对象
子主题
1、通过创建外部类对象的方式创建对象
外部类 外部类对象=new 外部类();
内部类 对象名=外部类对象.new 内部类();
外部类 外部类对象=new 外部类();
内部类 对象名=外部类对象.new 内部类();
2、内部类 对象名=new 外部类.new 内部类();
静态内部类
1、格式:static class 类名{}
2、可以声明静态的属性和方法
3、可以使用外部的静态属性和方法
4、创建对象
内类名 对象名=new 内类名();(可以直接创建)
外部类名.内部类 对象名=new 外部类.内部类();
包名.外部类名.内部类 对象名=new 包名.外部类.内部类();
外部类名.内部类 对象名=new 外部类.内部类();
包名.外部类名.内部类 对象名=new 包名.外部类.内部类();
5、外部类和内部类同名时,默认使用内部类对象调用外部类属性,this代表内部类对象
6、要是用外部类属性,需要使用外部类对象调用
局部内部类
1、在方法中声明
2、只能用deflault修饰
3、可以声明,属性和方法,但不能是静态的
4、创建对象,必须在内部类方法内创建
5、调用方法时,内部类才会被执行
匿名内部类
1、匿名内部类只使用一次
2、格式
父类或接口名 对象名=new 父类或接口名(参数列表){
重写抽象方法
} 调用抽象方法:对象名.方法名
父类或接口名 对象名=new 父类或接口名(参数列表){
重写抽象方法
} 调用抽象方法:对象名.方法名
数组
概念:
数组是相同类型数据的有序集合(大小,顺序都有序),数组中可以存基本类型元素,也可以存引用类型的元素,数组的length是固定的一旦确定,不能修改;
声明:
动态初始化:1、a=new int[2]; int[0]=1;...
动态初始化:2、b=new b[]{3,4};
静态初始化:int [] c={5,6};
动态初始化:2、b=new b[]{3,4};
静态初始化:int [] c={5,6};
常用方法:
排序:Array.sort();
查找:Array.binarySearch();
打印:Array.toString();
复制:Array.copyof()
查找:Array.binarySearch();
打印:Array.toString();
复制:Array.copyof()
空指针异常
1.声明了这个对象名,没有给这个对象初始化,使用了这个对象
2.遇到了类类型作为属性的时候,就必须初始化,否则就会报错
递归
有返回值
有参数
能够跳出循环的控制语句
方法自己调用自己
装箱拆箱
装箱:
把基本数据类型转成包装类类型。
拆箱
把包装类类型转成基本数据类型
为什么要装箱拆箱?
八种基本数据类型不满足面向对象的思想,不包括属性和方法。如果给基本数据类型添加功能,只能创建其包装类,将方法和属性封装进去。
jdk5.0以后出现了自动拆箱,装箱。
jdk5.0以后出现了自动拆箱,装箱。
Integer
Integer支持字符串,但字符串必须是数字
String常用API
== 比较地址
.equals() 比较内容
.charAt()字符串截取从指定下表开始
.equalsIgnoreCase() 忽略字母大小写
.compareTo() 比较大小
.compareToIgnore() 忽略比较大小
.concat() 将字符串拼接到指定字符串后面
.contains() 是否包含字符串
.startsWith() 以指定前缀开头
.endsWith() 以指定后缀结尾
.indexOf("/") 第一次出现
.indexOf("/", 3) 指定位置开始索引
.lastIndexOf("/") 最后一次出现
.substring(string11.lastIndexOf("/")+1);截取指定位置
.substring(string11.lastIndexOf("/")+1, string11.lastIndexOf("."));//截取字符串,指定开始位置和结束位置
.replace('a', 'b') 替换指定字符串,替换所有的
.toUpperCase() 全部转为大写
.toLowerCase() 全部转成小写
.trim() 去掉字符串前后的空格,中间的去不掉
StringBuffer常用API
.append("abckjc"); 追加
.insert(2, "mmm"); 插入
.delete(2, 4); 删除,参数1是起始下标,参数2是结束下标,左闭右开
.reverse(); 逆顺反转
String、Stringbuilder、StringBuffer区别
String
长度不可变得
StringBuilder
长度可变 线程不安全 (里面方法没有synchronized修饰)效率高
StringBuffer
长度可变,线程安全的 效率比Stringbuilder效率低
时间类相关的
1、Date
.getTime();计算毫秒
2、SimpleDateFormat类 格式化时间
.format();返回的是String字符串(date转字符串)
3、Calendar接口 日历字段之间的转换提供了一些方法
.get(Calendar.YEAR);
.get(Calendar.MONTH);// 默认是当前月份减一 从0开始的
.get(Calendar.DAY_OF_MONTH);
.get(Calendar.DAY_OF_WEEK);
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
4、Runtime运行时时间
.freeMemory(); 当前的系统剩余空间
5、System.exit(0);退出程序,参数是0 是正常退出
System.gc();调用垃圾回收器 ,不一定能够起来 ,只是起到一个促进的作用
Java异常处理机制
异常
在运行期出现的不正常的事件,从继承角度来看,throwable是错误和异常的超累
java中都的异常处理机制主要依赖于try、catch、finally、throw、throws五个关键字
错误Error
程序员无法处理的严重性问题,资源耗尽,JVM系统内部出错
异常Exception
程序员可以处理的一般性问题,偶然的外界因素,编程的逻辑性错误
处理的必要性
受检异常
编译期就能发现的异常,必须要去处理的异常,继承Exception
非受检异常
运行期发现的异常,不是必要去处理的,继承自RuntimeException
异常处理的机制
当代吗运行时碰到异常,首先会创建异常对象,抛出给JVM,jvm会携带异常对象,去找能够处理或者捕获异常的代码,若找到了交给这个代码去处理,若未找到,则程序停止运行。
为什么出现?
提高代码强壮性,不是降低代码错误率,而是代码错误能作出一定的处理;代码错了,不会停止运行,而是对于错误作出一定的处理
处理方式
抛出异常
产生异常的位置不去处理异常,由调用此方法的调用者去处理异
捕获异常
try{可能会产生异常的代码}catch(异常类 异常对象){处理异常的代码}finally{一定会执行的代码块}
如果不去捕获异常,发生异常后,后面的代码都不会去执行
如果捕获异常 try/catch后面的代码会被执行到
捕获异常,try块中异常后面的代码不会被执行到
throw和throws的区别
throw在方法体内抛出的异常,由方法体内语句执行
throws是用在方法声明的后面,表示如果抛出,由该方法的调用者处理
自定义异常
受检异常Exception
非受检异常RuntimeException
java中的集合
数组和集合的区别
数组
长度固定,数据类型相同
集合
长度不固定,数据类型不同,可以存对象
集合框架
单列集合接口collection
list
ArrayList
排列有序,可重复
底层使用的数组
查询速度快,增删慢,getter和setter速度快
线程不安全
当容量不够时,ArrayList是当前容量*1.5+1
Vector
排列有序,可重复
底层是数组
增删慢,删除也慢
线程安全,但效率低
LinkedList
排列有序,可重复
底层使用双向循环列表数据结构
查询速度慢,增删快,add()和remove()方法快
线程不安全
set
HashSet
排列无序,且不可重复,不允许有重复值
底层使用Hash表实现
存取速度快
内部是HashMap
TreeSet
排列无序,不可重复
底层使用二叉树实现
排序存储
内部是TreeMap和SrotedSet
LinkedHashSet
采用Hash表存储,并用双向链表插入顺序
内部是LinkedHashMap
Queue
在两端出现的List,所以也可以用数组加链接实现
双列集合接口map
HashMap
键值唯一的,不可重复,value值可以重复
底层是哈希表
线程不安全
key值可以为null,value也可以为null
效率高
HashTable
键不可重复,值可以重复
底层是哈希表
线程安全的
key、value都不可为null
TreeMap
键不可重复,值可以重复
底层是二叉树
java集合常见的面试题
1、ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?
Vector和HashTable是线程同步(synchronized)的。
性能上ArrayList和HashMap要比Vector和HashTable性能高
2、大致讲讲java集合的体系结构
List、Set、Map是这个集合体系中的主要接口。
其中List和Set都实现collection接口
Set不允许有重复的元素。HashSet和TreeSet是主要实现的两个类
List是有序都而且可以重复,底层是数组。ArrayList、LinkedList、Vector是主要实现类
Map也属于集合系统,但和collection接口不同。Map是key对value的映射集合,其中key值就是一个集合,key值不能重复,value可以重复。其中HashMap、TreeMap、HashTable是主要实现类
SrotedSet和SrotedMap是对元素按指定规则排序,SrotedMap是对key值进行排序
3、Comparable和Comparator的区别
Comparable和Comparator都是用于比较数据的大小的,实现Comparable接口需要重写compareTo方法,实现Comparator接口需要重写compare方法,这两个方法的返回值都是int,用int类型的值来确定比较结果,在Collections工具类中有一个排序方法sort,此方法可以之传一个集合,另一个重载版本是传入集合和比较器,前者默认使用的就是Comparable中的compareTo方法,后者使用的便是我们传入的比较器Comparator,java的很多类已经实现了Comparable接口,比如说String,Integer等类,而我们其实也是基于这些实现了Comparator或者Comparab接口的原生类来比较我们自己的类,比如说自定义一个类User,属性有name和age,俩个user之间的比较无非就是比较name和age的大小。
4、简述hashcode()方法
hashcode来源
hashcode方法是基于Object中的实例native()方法,因此所有类都继承该方法
在Object类中声明(native()方法暗示这些方法都是有实现体的,但不提供实现体,因为实现体是由非java语言在外面实现的)
在 Java 中,由 Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数。(这是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧)。
5、Set集合中如何保证元素不重复
要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢? 这就是 Object.equals 方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。 也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。于是,Java采用了哈希表的原理。 这样,我们对每个要存入集合的元素使用哈希算法算出一个值,然后根据该值计算出元素应该在数组的位置。所以,当集合要添加新的元素时,可分为两个步骤:
先调用这个元素的 hashCode 方法,然后根据所得到的值计算出元素应该在数组的位置。如果这个位置上没有元素,那么直接将它存储在这个位置上;
如果这个位置上已经有元素了,那么调用它的equals方法与新元素进行比较:相同的话就不存了,否则,将其存在这个位置对应的链表中(Java 中 HashSet, HashMap 和 Hashtable的实现总将元素放到链表的表头)。
6、equals 与 hashCode
前提: 谈到hashCode就不得不说equals方法,二者均是Object类里的方法。由于Object类是所有类的基类,所以一切类里都可以重写这两个方法。
原则 1 : 如果 x.equals(y) 返回 “true”,那么 x 和 y 的 hashCode() 必须相等 ;
原则 2 : 如果 x.equals(y) 返回 “false”,那么 x 和 y 的 hashCode() 有可能相等,也有可能不等 ;
原则 3 : 如果 x 和 y 的 hashCode() 不相等,那么 x.equals(y) 一定返回 “false” ;
原则 4 : 一般来讲,equals 这个方法是给用户调用的,而 hashcode 方法一般用户不会去调用 ;
原则 5 : 当一个对象类型作为集合对象的元素时,那么这个对象应该拥有自己的equals()和hashCode()设计,而且要遵守前面所说的几个原则。
原则 2 : 如果 x.equals(y) 返回 “false”,那么 x 和 y 的 hashCode() 有可能相等,也有可能不等 ;
原则 3 : 如果 x 和 y 的 hashCode() 不相等,那么 x.equals(y) 一定返回 “false” ;
原则 4 : 一般来讲,equals 这个方法是给用户调用的,而 hashcode 方法一般用户不会去调用 ;
原则 5 : 当一个对象类型作为集合对象的元素时,那么这个对象应该拥有自己的equals()和hashCode()设计,而且要遵守前面所说的几个原则。
总结:
hashcode是系统用来快速检索对象而使用
equals方法本意是用来判断引用的对象是否一致
重写equals方法和hashcode方法时,equals方法中用到的成员变量也必定会在hashcode方法中用到,只不过前者作为比较项,后者作为生成摘要的信息项,本质上所用到的数据是一样的,从而保证二者的一致性
equals方法本意是用来判断引用的对象是否一致
重写equals方法和hashcode方法时,equals方法中用到的成员变量也必定会在hashcode方法中用到,只不过前者作为比较项,后者作为生成摘要的信息项,本质上所用到的数据是一样的,从而保证二者的一致性
Java I/O
1.File类
File类是文件或目录路径的抽象表现形式,可以用来表示目录或者文件
File(String pathname)是最常用的根据一个路径获取file对象
file类对文件及目录提供的操作方法
creatNewFile()创建文件,mkdir()或mkidrs()创建目录,三种方法返回值均为Boolean类型,先去判断该文件是否存在,不存在则去创建,mkidrs()为创建父级文件
delete(),删除方法,返回也是Boolean类型,可以删除文件也可以删除目录,注意:该方法删除不是放入回收站,而是直接删除(谨慎使用)
renameTo(File dest)方法重命名
isDirectory(),isFile(),判断类型,判断是文件或者目录
canRead()是否可读
canWrite(): \是否可写
isHidden() 是否隐藏
exists()文件是否存在
file类的获取功能
getAbsolutePath()绝对路径
getPath()相对路径
getParent()父级目录路径
getName()或者文件名
getParentFile()获取父级目录文件名
lastModified()获取最后一次修改时间
length()或者文件大小(字节大小)
2.流
流
一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象
Java中的流
按照流的方向分
输入流InputStream
输入流 OutputStream
输入流和输出流是站在内存的角度上来讲的
按照实现的功能来分
节点流
节点流(可以从或向一个特定的地方(节点)读写数据。例如FileReader)
处理流
是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写,如 BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接);
按照数据的处理单元来分
字节流
字节流继承OutputStream和InputStream
字符流
字符流继承OutputStreamWrite和InputStreamRead
3.字节流和字符流的区别?
字节流在读取时,读到一个字节就返回一个字节;
字符流可以读到多个字节所以效率高;
字节流可以处理所有类型的数据,如图片,mp3,视频等;
字符流只能处理字符数据,所以纯文本优先使用字符流。
4.如何把一个java对象序列化到文件中?
在java中能够被序列化必须实现serializable接口,该接口没有任何方法,只有标记作用
5.如何实现对象的克隆
1.实现cloneable接口,重写clone()方法。但是这是浅克隆,被克隆的对象在内存中还是使用的原有对象内存
2.实现serialzable接口,通过序列化和反序列化来实现真正意义上的克隆
6.什么是序列化和反序列化?
序列化:java序列化是指吧java对象转换为字节序列的过程;
反序列化:是指将字节序列恢复java对象的过程。
7.序列化的作用
1.可以把对象字节永久的保存到硬盘上,通常放在一个文件中。
2.序列化后对象可以进行网络传输
8.如果不希望某些变量被序列化,怎么做?
如果不希望某一个变量被序列化(例如银行卡密码),就要将其变量声明为镜头变量(static)或者瞬态变量(transient),该变量就不会被序列化,在被饭序列化后就返回打印null值。
9.自定义序列化过程
实现Externalizable接口,重写writeExternal()和readExternal()方法可以自定义序列化过程
10.SerialzableUID的作用
在我们实现Serialzable接口后,若为手动设置SerialzableUID的值,java会自动给我们类标记UID;若我们手动设置的Uid值,第一次与第二次不一致时,进行序列化或者饭序列化操作时,会抛出UID版本不一致错误,所以务必保证UID值一致。
11.标准输入/输入/错误
输入
System in
会阻止程序运行,等待用户输入
输出
System out
将内容打印到控制台。。。sout。。。
错误流
System err
将内容打印到控制台,但是颜色是红色的,醒目
Java中的垃圾回收机制
C++和Java垃圾回收的比较
C++需要程序员手动的回收垃圾
Java语言不需要程序员手动回收垃圾,由jre在后台来自动回收不再使用的内容,简称垃圾啊回收机制,即GC
特点
1.只会回收堆内存中的对象空间,不会回收栈内存的数据
2.对于物理连接,如jdbc,输入输出流无能为力
3.存在不可知性,程序无法精确的控制垃圾回收
4.可以将对象的变量设置为null,暗示jvm该来收垃圾了
程序员可以通过system.gc()或者Runtime.getRuntime()方法,来通知系统回收垃圾了,但是不会立即执行的;不建议这么做
垃圾回收机制的算法
内容太多,这里就简单总结一个
根据内存中对象的存活周期不同,将内存划分为几块,java的虚拟机中一般把内存划分为新生代和年老代,当新创建对象时一般在新生代中分配内存空间,当新生代垃圾收集器回收几次之后仍然存活的对象会被移动到年老代内存中,当大对象在新生代中无法找到足够的连续内存时也直接在年老代中创建。
现在的Java虚拟机就联合使用了分代复制、标记-清除和标记-整理算法
Java中的多线程
进程和线程
进程
每个进程都有独立的代码和资源空间(进程上下文),进程之前切换有较大的资源消耗,一个进程中包含1-n个线程(进程是最小的资源分配单位)
线程
同一线程共享代码和数据空间,每个线程都有独立的运行栈和程序计数器(pc),线程之间切换资源消耗小,线程是cup调度的最小单位
创建线程的三种方式
1、继承Thread类,重写run()方法
2、实现Runable接口,重写run()方法
3、通过callable<T>接口,实现多线程,比较繁琐,优点是有返回值
创建一个类实现callable<T>接口,其中泛型就是返回值类型,然后重写call()方法
借助执行调度工具ExecutorService,创建对应类型线程池。获取Future对象(submit方法中的参数是具体实现类对象)。然后通过Future的get方法即可获取到返回值(此处要做异常处理,将异常throws了)。
调用ExecutorService的shutdown方法停止服务
关于线程池的图解
线程的五种状态
new:新建状态
Runable:就绪状态
Running:运行状态
Blocked:阻塞状态
Dead:死亡状态
线程运行状态图
上面图是线程运行状态图
当我们创建线程后,线程进入new(新建)
当我们调用start()方法时,便进入Runable(就绪)状态
经过CPU调度后,它便进入Runing(运行)状态。
如果在运行完毕后,这个线程便后进入Dead(死亡)状态
如果在运行过程中因为某些因素导致了线程阻塞,那它便进入Blocked状态,接触Blocked状态后会重新排队进入Runable状态
线程的停止
1、当线程自然运行完毕后,会自动停止
2、外部干涉
Thread的stop()方法
该方法已经被弃用,从stop()方法字面意思上可以看出是停止线程的意思,但是这个方法并不是真正意义上的停止线程
调用stop()方法来停止线程是不安全的。会发生下面两种可能
1、即可抛出ThreadDeath异常,在线程的run()方法中,任何一点都可能抛出这个异常,包括在catch和finally语句内
2、会释放该线程所持有的所有锁,并且这种释放是不可控制的,非预期的。
线程的阻塞
1、join()合并线程
可以理解为将多条线程合并为一条线程
join()等待线程的终止
join(long millies)等待该线程最少多少毫秒终止
join(long millis, int nanos):等待该线程终止的时间最长为millis毫秒+nanos纳秒
2、yield()暂停该线程
yield()方法可以暂停该条线程,去执行其他线程
yield()方法是一个static方法,暂停的线程取决于他执行的地方
3、sleep()休眠当前线程
sleep方法可以让当前线程睡眠一定的毫秒数
每一个对象都会有一把锁,线程休眠的时候,不会释放该锁
sleep方法的作用
1、与时间相关,倒计时
2、模拟网络延时
线程的优先级
我们可以为线程通过setPriority方法设置优先级,优先级的范围为1-10。
注意,优先级并不能代表先后顺序,只能导致执行的概率不同。优先级大的线程执行的概率会更大。
线程的同步
概念介绍
同步也成为并发,由于现在有多个线程,就可能会导致多个线程访问同一资源的问题。我们要保证资源的安全,所以我们必须保证同步,保证线程的安全
也就是说,线程安全的资源就是指多个线程同时访问这个资源的时候,是同步的。这份资源是安全的。
原子性
原子是世界上的最小单位,具有不可分割性。
非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。
*在 Java 中 synchronized 和在 lock、unlock 中操作保证原子性
可见性
可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。 也就是一个线程修改的结果。另一个线程马上就能看到。
用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。
需要注意的是,**volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。 **
**在 Java 中 volatile、synchronized 和 final 实现可见性。 **
有序性
Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。
synchronized关键字
我们通过synchronized标识符可以保证某一部分的线程安全,它是通过等待来实现的。我们把使用synchronized的行为叫做‘加锁’。当几个线程同时访问一份资源的时候,先到达的线程拿到锁,然后再轮到其他线程来。这样能保证线程的安全
当我们加上synchronized后,就是为它加了一把锁。当多个线程同时来访问这份资源时,先到达的资源便可以得到这个锁,其他资源只能等待,等待结束后再执行。这样就保证了我们的线程安全。
由于线程安全是通过等待来进行,因此会造成效率的低下。为了减少这种效率损耗,我们应该尽量缩小加锁的范围,来提高效率。
同步块
我们都知道,{}及里面的语句表示一个同步块。在它前面加上**synchronized(引用类型)**标识符,就变成了一个同步块。
而synchronized锁 类.class 时,比较特殊。主要是用于给一些静态的对象加锁。(如线程安全的单例模式就会用到)
而synchronized锁 类.class 时,比较特殊。主要是用于给一些静态的对象加锁。(如线程安全的单例模式就会用到)
同步方法
在方法的前面加上synchronized,就称这个方法是同步方法。
volatile关键字
线程对于普通的共享对象的操作发生在本地内存中,有时可能来不及同步到主内存中,就开始了下一个线程的处理。因此我们就可以用volatile来保证这个共享对象的可见性,强制将内存刷新到主内存中。
volatile具备两种特性,第一就是保证共享变量对所有线程的可见性。将一个共享变量声明为volatile后,会有以下效应:
1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的变量强制刷新到主内存中去;
2.这个写会操作会导致其他线程中的缓存无效。
死锁
过多的同步会造成死锁
对一个对象多线程同步访问,容易造成死锁。我们可以通过信号量来解决这个问题。
HTML
spring
0 条评论
下一页
为你推荐
查看更多