关于面试的基础知识
Xml/Json:
1.定义介绍
(1).XML定义
扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML使用DTD(document type definition)文档类型定义来组织数据;格式统一,跨平台和语言,早已成为业界公认的标准。
XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。
(2).JSON定义
JSON(JavaScript Object Notation)一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。可在不同平台之间进行数据交换。JSON采用兼容性很高的、完全独立于语言文本格式,同时也具备类似于C语言的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)体系的行为。这些特性使JSON成为理想的数据交换语言。
JSON基于JavaScript Programming Language , Standard ECMA-262 3rd Edition - December 1999 的一个子集。
2.XML优缺点
<1>.XML的优点
A.格式统一,符合标准;
B.容易与其他系统进行远程交互,数据共享比较方便。
<2>.XML的缺点
A.XML文件庞大,文件格式复杂,传输占带宽;
B.服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;
C.客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
D.服务器端和客户端解析XML花费较多的资源和时间。
(2).JSON优缺点
<1>.JSON的优点:
A.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;
B.易于解析,客户端JavaScript可以简单的通过eval()进行JSON数据的读取;
C.支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服务器端语言,便于服务器端的解析;
D.在PHP世界,已经有PHP-JSON和JSON-PHP出现了,偏于PHP序列化后的程序直接调用,PHP服务器端的对象、数组等能直接生成JSON格式,便于客户端的访问提取;
E.因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。
<2>.JSON的缺点
A.没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;
B.JSON格式目前在Web Service中推广还属于初级阶段。
(3)Json/Xml比较
(1)数据可读性:JSON和XML的数据可读性基本相同,JSON和XML的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,XML可读性较好些。
(2)可扩展性:XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。
(3)编码难易度:XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是要写好XML就不太容易了。
(4)解码难易度:XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。
(5)推广程度:XML已经被业界广泛的使用,而JSON才刚刚开始,但是在Ajax这个特定的领域,未来的发展一定是XML让位于JSON。到时Ajax应该变成Ajaj(Asynchronous Javascript and JSON)了。
(6)解析手段:JSON和XML同样拥有丰富的解析手段。
(7)数据体积:JSON相对于XML来讲,数据的体积小,传递的速度更快。
(8)数据交互:JSON与JavaScript的交互更加方便,更容易解析处理,jsom据交互优于xml
(9)数据描述:SON对数据的描述性比XML较差。
(10)传输速度:JSON的速度要远远快于XML。
XML创建对象:
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user>
<name>张三</name>
<age>18</age>
<sex>男</sex>
<addresses>
<address>北京</address>
<address>上海</address>
<address>广州 </address>
</addresses>
<email>125802</email>
</user>
<user>
<name>李四</name>
<age>28</age>
<sex>男</sex>
<addresses>
<address>天津</address>
<address>云南</address>
<address>广州 </address>
</addresses>
<email>156982</email>
</user>
<user>
<name>小红</name>
<age>18</age>
<sex>女</sex>
<addresses>
<address>北京</address>
<address>广东</address>
<address>广州 </address>
</addresses>
<email>156982</email>
</user>
</users>
Json对应格式
[
{
"name": "张三",
"age": "18",
"sex": "男",
"addresses": ["北京","上海","广州 "],
"email": "125802"
},
{
"name": "李四",
"age": "28",
"sex": "男",
"addresses": ["天津","云南", "广州 "],
"email": "156982"
},
{
"name": "小红",
"age": "18",
"sex": "女",
"addresses": ["北京","广东","广州 "],
"email": "156982"
}
]
数据库的索引:
XML文件约束dtd约束和escame约束:
dtd约束:
假设:先自己定义一个xml:
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user>
<name>zhangsan</name>
<age>23</age>
<addr>shanghai</addr>
</user>
<user>
<name>lisi</name>
<age>24</age>
<addr>beijing</addr>
</user>
</users>
自定义dtd文件约束:
DTD文件在定义的时候,文件的扩展名就是dtd。
在xml文件中有多少个标签,就在dtd中书写多少个ELEMENT标签,记住前面有“ !”
[PCDATA] 表示包含字符或文本数据
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT users (user+) >
<!--表示user标签定义-->
<!ELEMENT user (name,age,addr) >
<--表示在user标签下有三个属性 :name ,age,addr-->
<!ELEMENT name (#PCDATA) >
<!ELEMENT age (#PCDATA)>
<!ELEMENT addr (#PCDATA)>
引入dtd约束
引入方式:
单独写在文件中:
外部DTD的引入方式:外部DTD主要指的一个独立的DTD文件。首先要书写DTD文件, 然后在要被约束的xml文件中引入。 <!DOCTYPE 文档根结点 SYSTEM "DTD文件的 URL">,文档根结点 指的是当前xml中的根标签。SYSTEM 引入的系统中存在文 件,"DTD文件的URL" DTD存放的位置。
直接定义在xml中:
引入公共的DTD:<!DOCTYPE 文档根结点 PUBLIC "DTD名称" "DTD文件的URL">
文档根结点 指的是当前xml中的根标签。PUBLIC 表示当前引入的DTD是公共的DTD
在xml中引入第三方的公共DTD。
在xml中直接书写DTD,<!DOCTYPE 根标签名 [具体的标签的约束]>
Schema约束:
Schema它也来约束xml文件的,DTD在约束xml的时候一个xml中只能引入一个DTD,同时DTD它无法对属性以及标签中的数据做数据类型的限定。
Schema它是用来代替DTD来约束xml。
Schema文件本身就是使用xml文件书写的,同时它对需要约束的xml中的数据有严格的限定。学习Schema主要来学习W3C组织定义的如何在Schema中去约束xml的标签以及属性,还有属性的数据类型,以及标签中子标签的顺序。
要定义一个Schema文件,这时它的扩展名必须是.xsd。在这个文件中根元素必须是schema。
使用Schema来约束xml,Schema在书写的时候,只需要使用W3C组织提前定义的限定标签的,以及限定的属性的那个标签即可。
包装类的装箱与拆箱:
数据读取状态
脏读:当一个事务正在访问数据并对数据进行了修改,而另一个事务在该数据提交前使用了该数据.
幻读:事务不是独立执行时发生的一种现象.
不可重复读:在一个事务中多次读取一个数据,一个事务还没结束另一个事务也访问了该数据
事务隔离\属性 | 脏读 | 不可重复读 | 幻读 | 状态码 |
---|---|---|---|---|
Read Uncommited | √ | √ | √ | 1 |
Read commited | × | √ | √ | 2 |
Repeatable Read(Mysql默认) | × | × | √ | 4 |
Serializable | × | × | × | 8 |
面向对象(封装|继承|多态,oop|ood|ooa:):
封装
指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其他对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互。
对于封装而言,一个对象它所封装的是自己的属性和方法,所以它是不需要依赖其他对象就可以完成自己的操作。使用封装的好处:
1、良好的封装能够减少耦合。
2、类内部的结构可以自由修改。
3、可以对成员进行更精确的控制。
4、隐藏信息实现细节。
封装无效化:封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果不想被外界方法,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。
继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。
继承所描述的是“is-a”的关系,如果有两个对象A和B,若可以描述为“A是B的子类”,则可以表示A继承B,其中B是被继承者称之为父类或者超类,A是继承者称之为子类或者派生类。
实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有自己独有得特性。例如猫有抓老鼠、爬树等其他动物没有的特性。同时在继承关系中,继承者完全可以替换被继承者,反之则不可以,例如我们可以说猫是动物,但不能说动物是猫就是这个道理,其实对于这个我们将其称之为“向上转型”。
诚然,继承定义了类如何相互关联,共享特性。对于若干个相同或者相识的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性、方法还可以定义自己独有的属性或者方法。
同时在使用继承时需要记住三句话:
1、子类拥有父类非private的属性和方法。
2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3、子类可以用自己的方式实现父类的方法。
在这里我们需要明确,继承存在如下缺陷:
1、父类变,子类就必须变。
2、继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。
3、继承是一种强耦合关系。
多态
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。
Java实现多态有三个必要条件:继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
多态实现形式
在Java中有两种形式可以实现多态:继承和接口。
基于继承实现的多态
基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
基于继承实现的多态可以总结如下:对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。
如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。
基于接口实现的多态
继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。
在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
OOA:
Object-Oriented Analysis,面向对象分析
分析阶段所做的主要工作是理解问题和需求构模,将现实世界中的问题映射到问题域。
面向对象分析利用面向对象的概念和原则,来分析、认识和理解客观世界,将客观世界中的实体抽象为问题域中的对象, 分析客观世界中问题的结构,明确为完成系统功能,对象间应具有的联系和相互作用,最后形成概念模型。
OOA阶段的工作:
1.确定整个系统的对象有哪些。
2.确定每一个对象的属性和方法。
3.确定对象关系。
OOD:
Object-Oriented Design,面向对象设计
主要是确定实现用户需求的方法,即怎样做才能满足用户需求,并构造出系统的整体框架。
OOD从OOA的结果开始,并将其从问题域映射到实现域,为满足实现的需要,还要增加一些类,并对原有类及属性进行调整。此外,还要完成应用控制、人机交互界面的设计等。
OOD的主要工作有:
1)问题域部分的设计主要是对OOA结果进行改进和精化,有以下几个方面:
属性:有些属性在分析阶段有助于问题的理解,而到了设计阶段则可以由其他属性导出或根本没必要保留,而且必要时需增加一些属性。
服务:OOA只给出了服务的接口,其具体实现算法要在OOD阶段完成,同样对于不合理的部分应予以调整。
类以及对象:在OOA阶段有助于问题理解的一些类在OOD阶段成为冗余,需要删除,而为了优化调整继承关系还要增加一些类。所有的类都确定以后还要明确哪些类的对象会引发哪些类创建新对象。
整体结构: 对类与类之间结构进行优化调整,以达到整体架构更加清晰明了。
2)人机交互与应用控制部分的设计
交互界面的设计:与界面有关的类及类间结构的设计,必要时需要画出界面原形。
应用控制部分的设计:这部分对象主要是便于程序控制,使程序结构更合理。
OOP:
OOP(object-oriented programming): 面向对象程序设计
把组件的实现和接⼝分开,并且让组件具有多态性。
( 抽象 , 继承 , 封装 , 多态 ) 面向接⼝编程。
拦截器和过滤器:
jdk1.7与1.8的新特性:
1.jdk7的新特性方面:
1.1二进制变量的表示,支持将整数类型用二进制来表示,用0b开头。
所有整数int、short、long、byte都可以用二进制表示:
byte aByte = (byte) 0b00100001;
1.2 Switch语句支持String类型。
1.3 Try-with-resource语句:
try-with-resources语句是一种声明了一种或多种资源的try语句。资源是指在程序用完了之后必须要关闭的对象。try-with-resources语句保证了每个声明了的资源在语句结束的时候都会被关闭。任何实现了java.lang.AutoCloseable接口的对象,和实现了java.io.Closeable接口的对象,都可以当做资源使用。
1.4 Catch多个异常:
在Java 7中,catch代码块得到了升级,用以在单个catch块中处理多个异常。如果你要捕获多个异常并且它们包含相似的代码,使用这一特性将会减少代码重复度。下面用一个例子来理解。
catch(IOException | SQLException | Exception ex){
logger.error(ex);
throw new MyException(ex.getMessage());
}
1.5 数字类型的下划线表示 更友好的表示方式,不过要注意下划线添加的一些标准。
字面常量数字里加下划线的规则:下划线只能在数字之间,在数字的开始或结束一定不能使用下划线。
public class UsingUnderscoreInNumericLiterals {
public static void main(String[] args) {
int int_num = 1_00_00_000;
System.out.println("int num:" + int_num);
long long_num = 1_00_00_000;
System.out.println("long num:" + long_num);
float float_num = 2.10_001F;
System.out.println("float num:" + float_num);
double double_num = 2.10_12_001;
System.out.println("double num:" + double_num);
}
}
1.6 泛型实例的创建可以通过类型推断来简化 可以去掉后面new部分的泛型类型,只用<>就可以了。
1.7 并发工具增强: fork-join框架最大的增强,充分利用多核特性,将大问题分解成各个子问题,由多个cpu可以同时解决多个子问题,最后合并结果,继承RecursiveTask,实现compute方法,然后调用fork计算,最后用join合并结果。
2.jdk8的新特性方面:
2.1 接口的默认和静态方法:
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法。
public interface JDK8Interface {
// static修饰符定义静态方法
static void staticMethod() {
System.out.println("接口中的静态方法");
}
// default修饰符定义默认方法
default void defaultMethod() {
System.out.println("接口中的默认方法");
}
}
2.2 Lambda 表达式:(例如: (x, y) -> { return x + y; } ;λ表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。)
[函数式接口和Lambda表达式深入理解]
在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
2.3 方法与构造函数引用:
Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:
converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);
2.4 函数式接口:
所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。
2.5 Annotation 注解:支持多重注解:
很多时候一个注解需要在某一位置多次使用。
@YourAnnotation
@YourAnnotation
public void test(){
//TODO
}
2.6 新的日期时间 API:
Java 8新的Date-Time API (JSR 310)受Joda-Time的影响,提供了新的java.time包,可以用来替代
java.util.Date和java.util.Calendar。一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的。
2.7 Base64编码:
Base64编码是一种常见的字符编码,可以用来作为电子邮件或Web Service附件的传输编码。
在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与解码器。
2.8 JavaScript引擎Nashorn:
Nashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。
2.9 Stream的使用:
Stream API是把真正的函数式编程风格引入到Java中。其实简单来说可以把Stream理解为MapReduce,当然Google的MapReduce的灵感也是来自函数式编程。她其实是一连串支持连续、并行聚集操作的元素。从语法上看,也很像linux的管道、或者链式编程,代码写起来简洁明了,非常酷帅!
2.10 Optional:
Java 8引入Optional类来防止空指针异常,Optional类最先是由Google的Guava项目引入的。Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了。
2.11 扩展注解的支持:
Java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解。
2.12 并行(parallel)数组:
支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。
2.13 编译器优化:
Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。
新的Java1.8对IO做了升级:
数据库的悲观锁和乐观锁:
乐观锁:
乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。
悲观锁:
悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
这里需要注意的一点是不同的数据库对select for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,mysql就没有no wait这个选项。另外mysql还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在mysql中用悲观锁务必要确定走了索引,而不是全表扫描。
数据检索乐观锁,修改删除悲观锁。