Java基础中常见的一些问题(持续更新中)

1.String,StringBuilder,StringBuffer有什么区别?

String是不可变的,例如String s1 = “abc”; s1 = “bc”;

此时s1其实并没有发生变化。但StringBuilder和StringBuffer的内容是可变的。创造String实例有两种方式:new String()或String s = “xxx”。StringBuffer是线程安全的,StringBuilder是线程不安全的,但StringBuilder效率高,在单线程情况下推荐使用

2.接口和抽象类有什么区别

接口不能有方法实现,也就是说接口的方法都是抽象方法,但抽象类可以有方法实现。

接口要用implements实现,抽象类要用extends继承

一个类可以实现多个接口,但只能继承一个抽象类

接口不能有构造器,抽象类可以有构造器

 3.IO流分为几种

       按功能来分:输入流和输出流

       按类型来分:字节流和字符流

       字节流是按8位以字节为单位传输,字符流是按16位以字符为单位传输

 4.序列化与反序列化

什么是序列化和反序列化?

序列化是指通过某种方式把对象存储到磁盘文件中或传输给其他网络节点的过程。通常是将对象转换成二进制数据。

反序列化就是序列化的逆过程,把磁盘文件中或网络节点的二进制数据恢复成java对象的过程,通常是将二进制数据转换为对象。

序列化的应用场景:将对象存储在文件或数据库中,利用套接字在网络上进行对象传输,RMI(远程方法调用)传输对象。

序列化的实现一般是通过实现Serializable接口,并且会有一个serialVersionUID,这个ID叫做序列化ID,它决定着是否可以进行反序列化,在反序列的过程中,JVM会判断传过来的字节流中的序列化ID和实体类中的ID是否一致,如果一致则进行反序列化,否则会报序列化版本不一致的异常。当我们没有显式地指定这个序列化ID时,在类编译时会自动生成一个序列化ID,但如果类的数据发生了变动,例如添加了字段,那么此时的序列化ID也会发生改变,此时再反序列化就会发生错误。

注意:静态变量不会被序列化,被transient修饰的变量也不会被序列化

5.什么是动态代理

代理是一种常见的设计模式,其目的就是为了控制对被代理类的访问。通过代理类能够有效控制对被代理类的直接访问,也可以很好地隐藏和保护被代理类对象。

怎么实现动态代理?

我们需要先了解两个类,InvocationHandler和Proxy。

InvocationHandler是一个接口,它里面仅定义了一个方法

第一个参数是代理类,第二个是方法对象,第三个是参数列表

Proxy即为动态代理类,我们需要知道其中一个方法

他返回代理类的实例,这个实例可以被当作被代理类对象实例使用

动态代理步骤:

1.创建一个实现InvocationHandler的类,并实现invoke方法

2.创建被代理类及接口

3.创建一个代理对象,通过上述Proxy的静态方法

4.通过代理对象调用方法。它的底层实现是反射,通过代理对象调用真是对象的方法时,会自动跳转到代理对象关联的handler对象的invoke方法来进行调用

6.对象克隆

为什么要使用克隆?

当我们需要两个属性值一样但地址值不一样的对象时,就需要用到克隆

如何实现克隆?

实现cloneable接口并重写Object类中的clone()方法

深拷贝和浅拷贝

浅拷贝:简单调用Object的clone方法,只会将对象的基本类型数据和string进行克隆,而引用类型的数据没有进行深度克隆。比如一个的成员变量中包含另一个自定义类类型,那么此时进行浅拷贝的话,只会改变最外层对象的地址,而这个内层对象地址不会进行改变

深拷贝:利用序列化机制,先用IO流读取对象,再把对象写出来,就相当于实现了一次复制,解决了上述引用对象未进行克隆的问题

7.什么是Servlet?

Servlet是javaEE的接口之一,也是JavaWeb的三大组件之一,他们分别是Servlet,filter过滤器,listener监听器。Servlet是运行在服务器上的一个Java程序,可以接收客户端发来的请求并相应数据给客户端

如何实现Servlet?

  1. 编写一个类实现Servlet接口,并重写service方法处理请求。
  2. 在WEB-INF目录下的web.xml文件中配置Servlet程序的访问地址

或(常用)

  1. 编写一个类继承HttpServlet类、
  2. 重写doGet()或doPost()方法
  3. 配置访问地址

Servlet的生命周期?

实例化,初始化,响应请求,销毁

实例化:当客户端第一次发送请求时,由Servlet容器去解析请求,根据请求找到是否有对应的Servlet对象,如果有则直接使用,如果没有Servlet容器就会通过反射就会实例化一个。

初始化:调用init()方法。在servlet生命周期内只会调用一次init方法去初始化实例

请求响应:当有请求过来时,调用service()方法判断客户端的请求方式,如果是get请求,则执行doGet()方法;如果是post,则执行doPost()方法

销毁:服务器关闭时,调用destroy()方法

Servlet接口的继承体系

自定义Servlet->Class HttpServlet->Class GenericServlet-> interface Servlet

8.什么是sql注入?

是指将http请求中的参数插入到sql语句中时,参数被解析成sql语句的结构执行,影响了原sql的逻辑,形成注入。通过这种漏洞攻击者可以对数据库结构,数据等造成威胁

发生sql注入的情况?

1.JDBC拼接不当造成sql注入

JDBC有两种方法执行sql语句,分别是PrepareStatement和Statement。前者会对sql语句进行预编译,它允许数据库做参数化查询,而后者在每次执行时都需要编译,增大系统开销。前者的效率和安全性较好,但也有可能产生sql注入。

预编译:在statement发送sql到DBMS之前就对sql语句进行编译,这样在sql传到DBMS后就不需要再次编译了

参数化查询:数据库不会把传过去的参数看做sql结构语句的一部分,只是把它当做参数执行,所以就算有“or 1=1”这样的破坏性语句也不会被当做结构执行

PrepareStament使用?占位符对参数位置进行占位,在预编译阶段就填入相应的值构造出完整的sql语句,此时可以避免sql注入问题。但如果直接采取拼接的方式构造sql,那么仍然无法避免sql注入

2.使用框架不当导致sql注入

在我们使用mybatis框架时,将sql语句写入配置文件中,使用parameterType判断参数类型,搭配

#{parameter}或${parameter}传参,他们两个的传参方式不同

使用#{parameter}采用预编译的方式,会使用?进行占位,因此不存在sql注入。

使用${parameter}采用拼接的方式构造sql,因此不能避免sql注入

9.throw和throws的区别?

Throw是真的抛出一个异常,通常throw new xxxException

Throws通常声明在方法名之后,表示可能会抛出某种异常

10.Final,finally,finalize三个关键字的区别?

Final : 通常用来修饰类,成员变量,方法。类不可继承,变量值不可变,方法不可被重写

Finally: 通常放在try catch代码块之后,表示一定会执行的代码,除非在try中声明了System.exit(0)退出程序。

Finalize: object类中定义的方法,它在gc工作时调用,通过重写该方法可以整理系统资源和执行其他操作

11.说一下常见的异常?

空指针(NullPointerException)

指定类不存在(ClassNotFoundException)

字符串转换为数字异常(NumberFormatException)

数组下标越界异常(IndexOutOfBoundsException )

12.说几个常见的设计模式?

1.建造者模式

将一个复杂的对象拆分成若干个相对简单的部分,然后根据需要把这些拆分的部分组装起来,就形成了复杂的对象。这种模式下,用户只需要指定需要被创建的对象的类即可获得对象,至于怎么创建的不需要了解

代码

 

我们定义了一个目标对象类Car和一个建造者类carBuilder,在carBuilder中提供了三个方法用于组装车的不同位置,当按一定顺序组装完成后,就可以用build方法获得一辆车了

该模式的应用场景:

  1. 目标对象具有复杂的内部结构
  2. 目标对象的属性间存在相互依赖的关系,所以需要按顺序设置属性
  3. 隔离复杂对象的创建和使用,并使得相同的创建过程可以获得不同的产品

2.工厂模式

工厂模式分为简单工厂模式,工厂方法模式,抽象工厂模式

简单工厂模式

工厂类里有一个静态方法用于根据参数产生对象,这种模式仅需一个工厂类对象,就可以实现不同对象的创建

工厂方法模式

此时不仅有一个工厂,而是由子父类工厂,父类工厂负责定义创建目标对象的公共接口,而子类工厂负责实现这些接口生成具体的对象,这样就将对象的实例化过程延迟到了子类工厂中完成。

 

以该图举例,用户的不同需求由不同的子类工厂来完成,而不是同一个工厂。(图来自知乎阿宝哥)

抽象工厂模式

提供一个创建一系列解决需求的接口,不需要各种子类工厂来实现

抽象工厂

为每一种具有某种相同属性的对象创建一个工厂,允许在工厂中增加产品

工厂方法模式和抽象工厂的区别?

工厂模式是为每一种具有不同属性的实例创建一个工厂,这个工厂专门用于生产这个实例,不支持在工厂中新增产品

3.单例模式

它保证一个类只有一个实例可用,并提供一个全局访问点

单例模式可以省去很多对象实例化然后销毁的资源消耗

4.观察者模式

它定义了一种一对多的关系,让多个观察者同时监听某一个对象,当这个对象的状态发生了改变,就会通知所有的观察者,使得观察者可以及时更新自己

5.发布订阅模式

和观察者模式不同,订阅者(可以理解为上述的观察者)接收的消息不再是统一的,而是自己感兴趣的,所以这个模式下引入了一个Channel通道来将发布者发布的内容进行分类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Superzl1002

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

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

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

打赏作者

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

抵扣说明:

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

余额充值