全部面试笔记-1

​ Java面试的笔记,全面回忆

1.java基础

1-1.java的跨平台原理

​ 由于各操作系统支持的指令集,不是完全一致。不同的操作系统上要执行不同程序代码,但相同代码会使程序执行不了。所以,java开发了适用于不同操作系统及位数的java虚拟机(jvm)来屏蔽各个系统之间的差异,提供统一的接口(java API)。

​ 对于java开发者而言,只需要在不同系统上安装对应不同的虚拟机。只要java程序遵循java规范,可以在所有操作系统上运行java程序

1

1-2.搭建java开发环境的步骤

​ 1、适用于我们开发环境的jdk

​ 2、对应开发环境eclipse或idea

​ 3、还需要web服务器(tomcat)

1-3.int占几个字节

​ java有8个基本数据类型:byte,shot,int,long,float,double,char,boolean

byte:8位 shot:16位 int:32位,占4个字节

long:64位 float:32位 double:64位

char:16位 boolean:1位

1-4.面向对象的特征有哪些方面

​ 四大基本特征:封装,抽象,继承,多态

  • 封装:将对象封装成一个高度自治和相对封闭的个体,对象状态(属性由这个对象自己的行为(方法)来读取和改变。
  • 抽象:做出一些事物的相似和共性之处,归为一个类。(把现实生活中的对象,抽象为类)
  • 继承:在一个已经存在的类的基础之上进行,将其定义的内容作为自己的,可以加入若干新内容,或修改原来的方法,符合需求。
  • 多态:
    • 程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。
    • 即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
    • 引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

1-5.基本数据类型,为什么还需要包装类型

​ 每一个基本数据类型会对于一个包装类型:boolean–>Boolean int–>Integer

  • 基本数据类型,包装类型–>装箱和拆箱

​ 装箱:把基本的数据类型转换成对应的包装类型

​ Integer i = 1–>Integer .valueOf(1)

​ 自动装箱,实际上在编译时会调用Integer .valueOf方法来装箱

​ 拆箱:把包装类型转换为基本数据类型.基本数据类型

​ Integer i = 1;

​ int j = i–>自动拆箱

​ int j = i.intValue()i–>手动拆箱

​ 自动拆箱:实际上会在编译调用intValue (源码)

  • Java是一个面向对象的语言,而基本的数据类型,不具备面向对象的特性

    面向对象特性:null,max,min

    例子:Integer和int分别表示Person这个类的ID,可以null,判断一下

  • 包装类型:对象有缓存–>Integer i=1、Integer j= 1、i ==j

1-6.==和equals有什么区别

​ ==,用来判断两个变量之间的的值是否相等。

​ 变量就可以分为基本数据类型变量,引用类型。

​ 如果是基本数据类型的变量直接比较值,而引用类型要比较对应的引用的内存的首地址。

​ equals 用来比较两个对象长得是否一样。

​ 判断两个对象的某些特征是否一样。实际上就是调用对象的equals方法进行比较。

1-7.String和StringBuilder的区别?StringBuffer和StringBuilder的区别?

​ String、StringBuillder、StringBuffer三个类是来表示和操作字符串:字符串就是多个字符的集合。

​ String是内容不可变的字符串。String底层使用了一个不可变的字符数组(final char[])

2

​ StringBuillder、StringBuffer:是内容可以改变的字符串。StringBuillder、StringBuffer底层使用的可变的字符数组(没有使用final来修饰)

3

拼接字符串:

​ String进行拼接:String c = “a”+”b”

​ StringBuilder或者StringBuffer :

​ StringBuilder sb = new StringBuilder();

​ sb.apend(“a”).apend(“b”)

​ 拼接字符串不能使用String进行拼接,要使用StringBuilder或者StringBuffer

区别:

​ StringBuilder是线程不安全的,效率较高 而StringBuffer是线程安全的,效率较低。

1-8.java中的集合?

​ Java中的集合为两种:Conllection:value,Map:key–vale

Conllection:存储值有分为List 和Set

  • List是有序的,可以重复的。
  • Set是无序的,不可以重复的。根据equals和hashcode判断,也就是如果一个对象要存储在Set中,必须重写equals和hashCode方法。

map:存储key-value

1-9.ArrayList和LinkedList的区别?

  • ArrayList底层使用时数组。LinkedList使用的是链表。

  • 数组查询具有所有查询特定元素比较快,而插入和删除和修改比较慢(数组在内存中是一块连续的内存,如果插入或删除是需要移动内存)。

  • 链表不要求内存是连续的,在当前元素中存放下一个或上一个元素的地址。查询时需要从头部开始,一个一个的找。所以查询效率低。插入时不需要移动内存,只需改变引用指向即可。所以插入或者删除的效率高。

区别:

​ ArrayList使用在查询比较多,但是插入和删除比较少的情况

​ 而LinkedList使用在查询比较少而插入和删除比较多的情况。

1-10.HashMap哈HashTable的区别?HashTable和ConcurrentHashMap的区别?

  • HashMap和HasheTalbe都可以使用来存储key–value的数据。
  • HashMap是可以把null作为key或者value的,而HashTable是不可以的。
  • HashMap是线程不安全的,效率较高。而HashTalbe是线程安全的,效率较低。

提高:

​ 我想线程安全但是我又想效率高?

​ 通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。

1-11.实现一个拷贝文件的工具类使用字节流还是字符流?

​ 拷贝的文件不确定是只包含字符流,有可以能有字节流(图片、声音、图像等),为考虑到通用性,要使用字节流。

1-12.线程的几种实现方式?启动方式?区分方式?

  1. 实现方式

    • 通过继承Thread类实现一个线程
    • 通过实现Runnable接口实现一个线程:继承扩展性不强,java总只支持单继承,如果一个类继承Thread就不能继承其他的类了。
  2. 启动方式

1
2
3
4
5
Thread thread = new Thread
//(继承了Thread的对象/实现了Runnable的对象)
thread.setName(“设置一个线程名称”);
thread.start();
//启动线程使用start方法,而启动了以后执行的是run方法。
  1. 区分方式

​ 在一个系统中有很多线程,每个线程都会打印日志,我想区分是哪个线程打印的怎么办?

​ thread.setName(“设置一个线程名称”);

​ 这是一种规范,在创建线程完成后,都需要设置名称。

1-13.线程并发库?

​ JDK5中增加了Doug Lea的并发库,这一引进给Java线程的管理和使用提供了强大的便利性。

​ java.util.current包中提供了对线程优化、管理的各项操作,使得线程的使用变得的心应手。该包提供了线程的运行,线程池的创建,线程生命周期的控制.

​ Java通过Executors提供四个静态方法创建四种线程池,分别为:

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

  • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

  • newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

  • newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

1-14.线程池的作用?

1、限定线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃

2、线程池不需要每次都去创建或销毁,节约了资源、

3、线程池不需要每次都去创建,响应时间更快。

1-15.什么是设计模式?常用的设计模式有哪些?

​ 设计模式就是经过前人无数次的实践总结出的,设计过程中可以反复使用的、可以解决特定问题的设计方法。

常用的设计模式:

  • 单例(饱汉模式、饥汉模式)

    • 构造方法私有化,让出了自己类中能创建外其他地方都不能创建
    • 在自己的类中创建一个单实例(饱汉模式是一出来就创建创建单实例,而饥汉模式需要的时候才创建)
    • 提供一个方法获取该实例对象(创建时需要进行方法同步)
  • 工厂模式:Spring IOC就是使用了工厂模式.

    • 对象的创建交给一个工厂去创建。
  • 代理模式

    • Spring AOP就是使用的动态代理。

2.javaweb

2-1.http中get和post请求的区别?

​ GET和POST请求都是http的请求方式,用户通过不同的http的请求方式完成对资源(url)的不同操作。

​ GET,POST,PUT,DELETE就对应着对这个资源的查 ,改 ,增 ,删 4个操作,具体点来讲GET一般用于获取/查询资源信息,而POST一般用于更新资源信息

  • Get请求提交的数据会在地址栏显示出来,而post请求不会再地址栏显示出来.

    • GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,多个参数用&连接。
    • POST提交:把提交的数据放置在是HTTP包的包体中。 因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变
  • 传输数据的大小

    • Get请求由于浏览器对地址长度的限制而导致传输的数据有限制
    • POST请求不会因为地址长度限制而导致传输数据限制
  • 安全性

    • POST的安全性要比GET的安全性高:由于数据是会在地址中呈现,所以可以通过历史记录找到密码等关键信息

2-2.对servlet的理解?或者servlet是什么?

Servlet(Server Applet),全称Java Servlet, 是用Java编写的服务器端程序。而这些Sevlet都要实现Servlet这个借口。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。Servlet运行于支持Java的应用服务器中。

​ HttpServlet 重写doGet和doPost方法,或者你也可以重写service方法完成对get和post请求的响应。

2-3.servlet的生命周期?

​ servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。

​ 这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。

加载Servlet的class—->实例化Servlet—–>调用Servlet的init完成初始化

—->响应请求(Servlet的service方法)—–>Servlet容器关闭时(Servlet的destory方法)

  • Servlet启动时,开始加载servlet生命周期开始。
  • Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法
  • service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等。
  • 当服务器决定将实例销毁的时候(服务器关闭)调用其destroy方法。

2-4.Servlet API中forward() 与redirect()的区别?

1、forward是服务器端的转向而redirect是客户端的跳转。

2、使用forward浏览器的地址不会发生改变。而redirect会发生改变。

3、Forward是一次请求中完成。而redirect是重新发起请求。

4、Forward是在服务器端完成,而不用客户端重新发起请求,效率较高。

2-5.JSP和Servlet有哪些相同点和不同点?

​ JSP是Servlet技术的扩展,所有的jsp文件都会被翻译为一个继承HttpServlet的类。也就是jsp最终也是一个Servlet.这个Servlet对外提供服务。

​ JSP是Servlet技术的扩展,所有的jsp文件都会被翻译为一个继承HttpServlet的类。也就是jsp最终也是一个Servlet.这个Servlet对外提供服务。

​ Servlet如果要实现html的功能,必须使用Writer输出对应的html,比较麻烦。

​ JSP的情况是Java和HTML,可以组合成一个扩展名为.jsp的文件,做界面展示比较方便而嵌入逻辑比较复杂。

4

2-6.jsp有哪些内置对象?作用分别是什么?

9个内置的对象:

  • request 用户端请求,此请求会包含来自GET/POST请求的参数

  • response 网页传回用户端的回应

  • pageContext 网页的属性是在这里管理

  • session 与请求有关的会话期

  • application servlet正在执行的内容

  • out 用来传送回应的输出

  • config servlet的构架部件

  • page JSP网页本身

  • exception 针对错误网页,未捕捉的例外

    四大作用域:pageContext 、request 、session 、application 可以通过jstl从四大作用域中取值.

    Jsp传递值request、session 、application 、cookie也能传值

2-7.session和cookie的区别?你在项目中都有哪些地方使用了?

​ Session和cookie都是会话(Seesion)跟踪技术。

​ Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

​ 但是Session的实现依赖于Cookie,sessionId(session的唯一标识需要存放在客户端).

区别:

​ 1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

​ 2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。

​ 3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。

​ 4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

​ 5、建议:将登陆信息等重要信息存放为SESSION、 其他信息如果需要保留,可以放在COOKIE中,比如购物车

​ 购物车最好使用cookie,但是cookie是可以在客户端禁用的,这时候我们要使用cookie+数据库的方式实现,当从cookie中不能取出数据时,就从数据库获取。

2-8.MVC的各个部分都有那些技术来实现?

  • M(Model) 模型 javabean

  • V(View) 视图 html jsp volicity freemaker

  • C(Control) 控制器 Servlet,Action

    Jsp+Servlet+javabean 最经典mvc模式,实际上就是model2的实现方式,就是把视图和逻辑隔离开来

3.数据库

3-1.数据库的分类及常用的数据库

关系型数据库和非关系型数据库

  • 关系型:mysql oracle sqlserver等
  • 非关系型:redis,memcache,mogodb,hadoop等

3-2.关系数据库三范式?

​ 范式就是规范,就是关系型数据库在设计表时,要遵循的三个规范。

​ 要想满足第二范式必须先满足第一范式,要满足第三范式必须先满足第二范式。

  • 第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。列数据的不可分割
  • 二范式(2NF)要求数据库表中的每个行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。(主键)
  • 满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。(外键)
  • 反三范式,有的时候为了效率,可以设置重复或者可以推导出的字段:订单(总价)和订单项(单价)

3-3.事务四个基本特征或 ACID 特性

​ 事务是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。

​ 如:一个转账必须 A账号扣钱成功,B账号加钱成功,才算正真的转账成功

​ 事务必须满足四大特征:原子性、一致性、隔离性、持久性/持续性

  • 原子性:表示事务内操作不可分割。要么都成功、要么都是失败.
  • 一致性:要么都成功、要么都是失败.后面的失败了要对前面的操作进行回滚。
  • 隔离性:一个事务开始后,不能后其他事务干扰。
  • 持久性/持续性:表示事务开始了,就不能终止。

3-4.mysql数据库的默认的最大连接数?

​ 100

​ 为什么需要最大连接数?特定服务器上面的数据库只能支持一定数目同时连接,这时候我们一般都会设置最大连接数(最多同时服务多少连接)。在数据库安装时都会有一个默认的最大连接数为100

1
max_connections=100

3-5.msyql的分页?Oracle的分页?

​ Mysql是使用关键字limit来进行分页的:limit、offset、size 表示从多少索引去多少位.

​ Oracle的分页,大部分情况下,我们是记不住了。说思路,要使用三层嵌套查询。

1
2
3
4
5
6
7
8
mysql:
String sql = "select * from students order by id limit " + pageSize*(pageNumber-1) + "," + pageSize;

oracle:
String sql = "select * from "
+ (select *,rownum rid from (select * from students order by postime desc) where rid<="
+ pagesize*pagenumber + ") as t" + "where t>"
+ pageSize*(pageNumber-1);

3-6.数据库的触发器的使用场景?

​ 触发器,需要有触发条件,当条件满足以后做什么操作。

​ 就是在增加日志时做一个后触发,再向通知表中写入条目。因为触发器效率高,而UCH没有用触发器,效率和数据处理能力都很低。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
create table board1(id int primary key auto_increment,name varchar(50),articleCount int);

create table article1(id int primary key auto_increment,title varchar(50),bid int references board1(id));

delimiter |#把分割符;改成|

create trigger insertArticle_Trigger after insert on article1 for each row begin
-> update board1 set articleCount=articleCount+1 where id= NEW.bid;
-> end;
-> |

delimiter ;

insert into board1 value (null,'test',0);

insert into article1 value(null,'test',1);

3-7.数据库的存储过程的使用场景?

数据库存储过程具有如下优点:

​ 1、存储过程只在创建时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,因此使用存储过程可以大大提高数据库执行速度。

​ 2、通常,复杂的业务逻辑需要多条 SQL 语句。这些语句要分别地从客户机发送到服务器,当客户机和服务器之间的操作很多时,将产生大量的网络传输。如果将这些操作放在一个存储过程中,那么客户机和服务器之间的网络传输就会大大减少,降低了网络负载。

​ 3、存储过程创建一次便可以重复使用,从而可以减少数据库开发人员的工作量。

​ 4、安全性高,存储过程可以屏蔽对底层数据库对象的直接访问,使用 EXECUTE 权限调用存储过程,无需拥有访问底层数据库对象的显式权限。

​ 正是由于存储过程的上述优点,目前常用的数据库都支持存储过程,例如 IBM DB2,Microsoft SQL Server,Oracle,Access 等,开源数据库系统 MySQL 也在 5.0 的时候实现了对存储过程的支持。

1
2
3
4
5
6
7
8
create procedure insert_Student (_name varchar(50),_age int ,out _id int)
begin
insert into student value(null,_name,_age);
select max(stuId) into _id from student;
end;

call insert_Student('wfz',23,@id);
select @id;

3-8.用jdbc怎么调用存储过程?

​ 加载驱动 获取连接 设置参数 执行 释放连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class JdbcTest {
public static void main(String[] args) {
Connection cn = null;
CallableStatement cstmt = null;
try {
//这里最好不要这么干,因为驱动名写死在程序中了
Class.forName("com.mysql.jdbc.Driver");
//实际项目中,这里应用DataSource数据,如果用框架,
//这个数据源不需要我们编码创建,我们只需Datasource ds = context.lookup()
//cn = ds.getConnection();
cn = DriverManager.getConnection("jdbc:mysql:///test","root","root");
cstmt = cn.prepareCall("{call insert_Student(?,?,?)}");
cstmt.registerOutParameter(3,Types.INTEGER);
cstmt.setString(1, "wangwu");
cstmt.setInt(2, 25);
cstmt.execute();
//get第几个,不同的数据库不一样,建议不写
System.out.println(cstmt.getString(3));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
try {
if(cstmt != null)
cstmt.close();
if(cn != null)
cn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

3-9.对jdbc的理解?

​ Java database connection java:数据库连接

​ 数据库管理系统(mysql oracle等)是很多,每个数据库管理系统支持的命令是不一样的。

​ Java只定义接口,让数据库厂商自己实现接口,对于我们者而言。只需要导入对应厂商开发的实现即可。然后以接口方式进行调用.(mysql + mysql驱动(实现)+jdbc)

5

3-10.一个简单的jdbc的程序。写一个访问oracle数据的jdbc程序?

1
2
3
4
5
6
7
8
9
10
加载驱动
com.mysql.jdbc.Driver,oracle.jdbc.driver.OracleDriver
获取连接
DriverManager.getConnection(url,usernam,passord)
设置参数
Statement PreparedStatement cstmt.setXXX(index, value);
执行
executeQuery executeUpdate
释放连接
是否连接要从小到大,必须放到finnaly

3-11.JDBC中的PreparedStatement相比Statement的好处

  1. PreparedStatement是预编译的,比Statement速度快
  2. 代码的可读性和可维护性
  1. 安全性

​ 虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次:

1
2
3
4
5
6
7
8
9
两种比较:
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");

perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();

​ PreparedStatement可以防止SQL注入攻击,而Statement却不能。比如说:

1
2
3
4
5
6
7
8
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";

如果我们把[' or '1' = '1]作为varpasswd传入进来.用户名随意,看看会成为什么?
select * from tb_name = '随意' and passwd = '' or '1' = '1';

因为'1'='1'肯定成立,所以可以任何通过验证,更有甚者:
把[';drop table tb_name;]作为varpasswd传入进来,则:
select * from tb_name = '随意' and passwd = '';drop table tb_name;

​ 有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行。

​ 而如果你使用预编译语句你传入的任何内容就不会和原来的语句发生任何匹配的关系,只要全使用预编译语句你就用不着对传入的数据做任何过虑。而如果使用普通的statement,有可能要对drop等做费尽心机的判断和过虑。

-------------本文结束感谢您的阅读-------------

本文标题:全部面试笔记-1

文章作者:Linhuide

发布时间:2020年03月21日 - 14:03

最后更新:2020年03月25日 - 22:03

原始链接:https://linhuide.github.io/post/448efa24.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!