您的位置:首页 > 编程语言 > Java开发

2020春季Java面试题(三)

2020-03-20 12:11 274 查看

v 接口与协议

² RESTful 接口规范

Ø RESTful的概念RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务使能接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源。

Ø URL定义
RESTful 的核心思想就是,客户端发出的数据操作指令都是"动词 + 宾语"的结构。比如,GET /articles这个命令,GET是动词,/articles是宾语。

动词通常就是五种 HTTP 方法,对应 CRUD 操作。

  1. GET:读取(Read)

  2. POST:新建(Create)

  3. PUT:更新(Update)

  4. PATCH:更新(Update),通常是部分更新

  5. DELETE:删除(Delete)

Ø 状态码
客户端的每一次请求,服务器都必须给出回应。回应包括 HTTP 状态码和数 据两部分。

HTTP 状态码就是一个三位数,分成五个类别。

  1. GET: 200 OK
  2. POST: 201 Created
  3. PUT: 200 OK
  4. PATCH: 200 OK
  5. DELETE: 204 No Content
    ² Http与Https区别

Ø 传输信息安全性不同

  1. http协议:是超文本传输协议,信息是明文传输。如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息。

  2. https协议:是具有安全性的ssl加密传输协议,为浏览器和服务器之间的通信加密,确保数据传输的安全。

Ø 连接方式不同

  1. http协议:http的连接很简单,是无状态的。

  2. https协议:是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议。

Ø 端口不同

  1. http协议:使用的端口是80。

  2. https协议:使用的端口是443.

Ø 证书申请方式不同

  1. http协议:免费申请。

  2. https协议:需要到ca申请证书,一般免费证书很少(国内像腾讯ssl证书可以免费申请一年),需要交费。

² TCP和UDP

Ø TCP和UDP的概念
UDP协议和TCP协议都是传输层协议。

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。即客户和服务器交换数据前,必须现在双方之间建立一个TCP连接,之后才能传输数据。并且提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

UDP(User Data Protocol,用户数据报协议)是一个无连接的传输层协议。它不提供可靠性,只是把应用程序传给IP层的数据报发送出去,但是不能保证它们能到达目的地。由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,所以传输速度很快。

Ø TCP与UDP区别

  1. TCP面向连接(如打电话要先拨号建立连接),可靠性高;UDP是无连接的,即发送数据之前不需要建立连接,可靠性低。

  2. 由于TCP是连接的通信,需要有三次握手、重新确认等连接过程,会有延时,实时性差,同时过程复杂,也使其易于攻击;UDP没有建立连接的过程,因而实时性较强,也稍安全。

  3. 在传输相同大小的数据时,TCP首部开销20字节;UDP首部开销8字节,TCP报头比UDP复杂,故实际包含的用户数据较少。TCP在IP协议的基础上添加了序号机制、确认机制、超时重传机制等,保证了传输的可靠性,不会出现丢包或乱序,而UDP有丢包,故TCP开销大,UDP开销较小。

  4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

  5. TCP对系统资源要求较多,UDP对系统资源要求较少。

u UDP报头

u TCP报头

Ø 应用场景选择

1)对实时性要求高和高速传输的场合下使用UDP;在可靠性要求低,追求效率的情况下使用UDP;

2)需要传输大量数据且对可靠性要求高的情况下使用TCP

v 设计模式

² 设计模式类型设计模式分为三大类:

  1. 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

  2. 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

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

² 设计模式的七大原则

  1. 开闭原则(Open Close Principle)
    开闭原则就是对功能扩展开放,对修改代码关闭。系统扩展功能是,不需要修改原来的代码,只需新增代码便可。
  2. 单一职责原则(Single Responsibility Principle)

一个类只负责一个功能领域的职责

降低类的复杂度,当修改一个功能时,降低对其他功能的影响,提供类的可读性

  1. 里氏代换原则(Liskov Substitution Principle)
    里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。里氏代换原则中说,能使用父类的地方一定可以使用子类替代。LSP是继承复用的基石,里氏代换原则是对“开-闭”原则的补充。

  2. 依赖倒转原则(Dependence Inversion Principle)
    是开闭原则的基础,具体内容:实现接口编程,依赖于抽象类或接口而不依赖于具体类,系统功能扩展时可以使用具体类扩展。

  3. 接口隔离原则(Interface Segregation Principle)
    使用多个隔离的接口,比使用单个接口要好,原则是:降低依赖,降低耦合。

  4. 迪米特法则(最少知道原则)(Demeter Principle)
    最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

  5. 合成复用原则(Composite Reuse Principle)
    原则是尽量使用合成/聚合的方式,而不是使用继承。

² 单例模式

Ø 单例模式的概念 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

Ø 单例的实现

将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;

在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。

饿汉式

// 饿汉式单例
public class Singleton1 {

// 指向自己实例的私有静态引用,主动创建
private static Singleton1 singleton1 = new Singleton1();

// 私有的构造方法
private Singleton1(){}

// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton1 getSingleton1(){
return singleton1;
}
}

我们知道,类加载的方式是按需加载,且加载一次。。因此,在上述单例类被加载时,就会实例化一个对象并交给自己的引用,供系统使用;而且,由于这个类在整个生命周期中只会被加载一次,因此只会创建一个实例,即能够充分保证单例。

优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

懒汉式

// 懒汉式单例
public class Singleton2 {

// 指向自己实例的私有静态引用
private static Singleton2 singleton2;

// 私有的构造方法
private Singleton2(){}

// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton2 getSingleton2(){
// 被动创建,在真正需要使用时才去创建
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}

我们从懒汉式单例可以看到,单例实例被延迟加载,即只有在真正使用的时候才会实例化一个对象并交给自己的引用。

这种写法起到了Lazy Loading的效果,但是只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

双重加锁机制

//双重加锁机制
public class Singleton
{
private static Singleton instance;
//程序运行时创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
private Singleton() { }
public static Singleton GetInstance()
{
//先判断是否存在,不存在再加锁处理
if (instance == null)
{
//在同一个时刻加了锁的那部分程序只有一个线程可以进入
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}

Double-Check概念对于多线程开发者来说不会陌生,如代码中所示,我们进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。

使用双重检测同步延迟加载去创建单例的做法是一个非常优秀的做法,其不但保证了单例,而且切实提高了程序运行效率

优点:线程安全;延迟加载;效率较高。

静态初始化

//阻止发生派生,而派生可能会增加实例
public sealed class Singleton
{
//在第一次引用类的任何成员时创建实例,公共语言运行库负责处理变量初始化
private static readonly Singleton instance=new Singleton();

private Singleton() { }
public static Singleton GetInstance()
{
return instance;
}
}

在实际应用中,C#与公共语言运行库也提供了一种“静态初始化”方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决多线程环境下它是不安全的问题。

总结当然,单例模式的实现方法还有很多。但是,这四种是比较经典的实现,也是我们应该掌握的几种实现方式。

从这四种实现中,我们可以总结出,要想实现效率高的线程安全的单例,我们必须注意以下两点:

  1. 尽量减少同步块的作用域。

  2. 尽量使用细粒度的锁。

² 简单工厂模式

Ø 简单工厂的概念

简单工厂模式又称为静态工厂模式,实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

其实就是将一个具体类的实例化交给一个静态工厂方法来执行,它不属于GOF的23种设计模式,但现实中却经常会用到,而且思想也非常简单。

Ø 简单工厂模式的结构

简单工厂模式包含如下角色:Factory:工厂角色Product:抽象产品角色ConcreteProduct:具体产品角色
|

工厂角色(Creator) 是简单工厂模式的核心,它负责实现创建所有具体产品类的实例。工厂类可以被外界直接调用,创建所需的产品对象。
抽象产品角色(Product) 是所有具体产品角色的父类,它负责描述所有实例所共有的公共接口。
具体产品角色(Concrete Product) 继承自抽象产品角色,一般为多个,是简单工厂模式的创建目标。工厂类返回的都是该角色的某一具体产品。

Ø 简单工厂模式的应用场景

苹果公司刚发布IPhone 11和iPhone 11Pro,那么问题来了,苹果公司的代工厂到底生产多少种尺寸的手机呢?

由工厂决定生产哪种型号的的手机,苹果公司的工厂就是一个工厂类,是简单工厂模式的核心类。

iPhone 11、iPhone 11、iphone 11 Max都是苹果手机,只是型号不同。苹果手机类满足抽象的定义,各个型号的手机类是其具体实现。

如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。

在以下情况下可以使用简单工厂模式:

工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

Ø 简单工厂模式和工厂方法模式区别

简单工厂模式:

① 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。

② 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

工厂方法模式:

① 客户端不知道它所需要的对象的类。

② 抽象工厂类通过其子类来指定创建哪个对象。

Ø 简单工厂模式和策略模式的异同

策略模式和简单工厂模式看起来非常相似,都是通过多态来实现不同子类的选取,这种思想应该是从程序的整体来看得出的。

如果从使用这两种模式的角度来看的话,我们会发现在简单工厂模式中我们只需要传递相应的条件就能得到想要的一个对象,然后通过这个对象实现算法的操作。

而策略模式,使用时必须首先创建一个想使用的类对象,然后将该对象最为参数传递进去,通过该对象调用不同的算法。

在简单工厂模式中实现了通过条件选取一个类去实例化对象,策略模式则将选取相应对象的工作交给模式的使用者,它本身不去做选取工作。

结合下面的代码和下面的释义不难看出,其实两个的差别很微妙,Factory是直接创建具体的对象并用该对象去执行相应的动作,而Context将这个操作给了Context类,没有创建具体的对象,实现的代码的进一步封装,客户端代码并不需要知道具体的实现过程。

Ø 简单工厂模式的优缺点

u 优点:

工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.

通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。

而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。

u 缺点:

由于工厂类集中了所有实例的创建逻辑,违反了开闭原则,将全部创建逻辑集中到了一个工厂类中;

它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。

当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.

这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;

开闭原则定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

开放-封闭原则的意思就是说,你设计的时候,时刻要考虑,尽量让这个类是足够好,写好了就不要去修改了,如果新需求来,我们增加一些类就完事了,原来的代码能不动则不动。这个原则有两个特性,一个是说“对于扩展是开放的”,另一个是说“对于更改是封闭的”。面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。这就是“开放-封闭原则”的精神所在。

Ø 简单工厂模式的实现

首先创建一个"苹果手机"类,定义一个获取手机尺寸的方法

//苹果手机
public abstract class ApplePhone {
//获取尺寸
protected abstract void getSize();

}

苹果手机不同型号的手机类。

public class Iphone11:ApplePhone{
public void getSize() {
Console.WriteLine("iPhone11屏幕:6.1英寸");
}
}
public class Iphone11Pro:ApplePhone{
public void getSize() {
Console.WriteLine("iphone11Pro屏幕:5.8英寸");
}
}
public class Iphone11ProMax:ApplePhone{
public void getSize() {
Console.WriteLine("iphone11ProMax屏幕:6.5英寸");
}
}

建立一个工厂类生产不同型号的手机对象。

//苹果工厂
public class AppleFactory {
public static ApplePhone createPhone(String model){
ApplePhone applePhone = null;
switch (model) {
case"iPhone11":
applePhone = new Iphone11();
break;

case"iphone11Pro":
applePhone = new Iphone11Pro();
break;

case"iphone11ProMax":
applePhone = new Iphone11ProMax();
break;

default:
break;
}
returnapplePhone;
}
}

最后是客户端测试类

public class Client {
public static void main(String[] args) {
ApplePhone applePhone ;
applePhone = AppleFactory.createPhone("iPhone11");
applePhone.getSize();
applePhone = AppleFactory.createPhone("iphone11Pro");
applePhone.getSize();
applePhone = AppleFactory.createPhone("iphone11ProMax");
applePhone.getSize();
}
}

总结
创建型模式对类的实例化过程进行了抽象,能够将对象的创建与对象的使用过程分离。

简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。

简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

简单工厂模式包含三个角色:工厂角色负责实现创建所有实例的内部逻辑;抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口;具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。

简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。

简单工厂模式适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
qq_41490913 发布了0 篇原创文章 · 获赞 0 · 访问量 463 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: