1.抽象类和接口的区别(三张思维导图教您更高效学习SSM框架)
抽象类可以有构造方法,接口中不能有构造方法。
抽象类中可以有普通成员变量,接口中没有普通成员变量。
抽象类中可以包含非抽象普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的方法(1.8之前)。d. 抽象类中的抽象方法的访问权限可以是 public、protected 和(默认类型,虽然 eclipse 不报错,但也不能用,默认类型子类不能继承),接口中的抽象方法只能是 public 类型的,并且默认即为 public abstract 类型。e. 抽象类中可以包含静态方法,在 JDK1.8 之前接口中不能不包含静态方法,JDK1.8 以后可以包含。f. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问权限可以是任意的,但接口中定义的变量只能是 public static final 类型的,并且默认即为 public static final 类型。g. 一个类可以实现多个接口,用逗号隔开,但只能继承一个抽象类,接口不可以实现接口,但可以继承接口,并且可以继承多个接口,用逗号隔开。
2.重载和重写的区别
答:1.方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
2.重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。
3.stringBuffer和stringBuilder的区别
1、StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,
2、只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
3、在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全,而StringBuffer则每次都需要判断锁,效率相对更低
4. 集合的体系架构(单列集合和双列集合)
由于需求不同,Java就提供了不同的集合类。这多个集合类的数据结构不同,但是它们都是要提供存储和遍历功能的,我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。
Collection Map
|--List |--HashMap
|--ArrayList |--LinkedHashMap
|--Vector |--HashTable
|--LinkedList |--Properties
|--Set
|--HashSet
|--TreeSet
Collection:是集合的顶层接口,它的子体系有重复的,有唯一的(HashSet),有有序的(List),有无序的(Set)。
区别:Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的。可以把这个理解为:夫妻对,属于双列集合
Collection集合存储元素是单独出现的,Collection的儿子Set是唯一的,List是可重复的。可以把这个理解为:光棍(11.11) 属于单列集合
5. ArrayList和LinkedList的区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表结构。
2.对于随机访问的get和set方法,ArrayList要优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
6. hashMap和HashTable的区别
Hashtable是基于陈旧的Dictionary类,HashMap是Java 1.2引进的Map接口的一个实现
Hashtable:线程安全,效率低。不允许null键和null值,HashMap:线程不安全,效率高。允许null键和null值
7. java的GC机制的理解
GC :Garbage Collections 字面意思是垃圾回收器,释放垃圾占用的空间。让创建的对象不需要像c、c++那样delete、free掉 。对于c、c++的开发人员来说内存是开发人员分配的,也就是说还要对内存进行维护和释放。对于Java程序员来说,一个对象的内存分配是在虚拟机的自动内存分配机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,而且不容易出现内存泄露和内存溢出问题,但是,如果出现了内存泄露和内存溢出问题,而开发者又不了解虚拟机是怎么分配内存的话,那么定位错误和排除错误将是一件很困难的事情。
8. 说下final,finally,finalize有什么区别
final:最终的意思,可以修饰类,方法和变量。
它修饰的类,不能被继承
它修饰的方法,不能被重写
它修饰的变量,不能被改变
finally:是异常处理的一部分,用于释放资源的。它控制的代码永远会执行。
特殊情况:在执行到finally之前,JVM退出了。
finalize:是Object类的一个方法,用于垃圾回收。
9. Error和Exception的区别,try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?
Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。
Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。
编译时期异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常)
运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)
finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
什么时候的代码必须最终执行?
当我们在try语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等),我们都得在使用完之后,最终关闭打开的资源。
当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,否则finally永远会执行。如果try中有return语句,finally会在return之前执行。
10. 说说同步和异步的区别,多线程的几种实现方式,和run方法可以启动线程吗
1.如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正在写的数据以后可能被另外一个线程读到,或者正在读的数据可能已经被另外一个线程写过了,那么这些数据就必须进行同步存取(数据库中的排它锁就是最好的例子)
2.当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途经往往更有效率,事实上,所谓的同步就是指阻塞式操作,而异步就是非阻塞式操作
多线程的四种实现方式:
第一种方式:继承Thread类
万物皆对象,那么线程也是对象,对象就应该能够抽取其公共特性封装成为类,使用类可以实例化多个对象,那么实现线程的第一种方式就是继承Thread类。继承Thread类是最简单的一种实现线程的方式,通过JDK提供的Thread类,重写Thread类的run方法即可,那么当线程启动的时候,就会执行run方法体的内容。
第二种方式:实现Runnable接口
实现Runnable接口也是一种常见的创建线程的方式,使用接口的方式可以让我们的程序降低耦合度。Runnable接口中仅仅定义了一个方法,就是run。我们来看一下Runnable接口的代码。
其实Runnable就是一个线程任务,线程任务和线程的控制分离,这也就是上面所说的解耦。我们要实现一个线程,可以借助Thread类,Thread类要执行的任务就可以由实现了Runnable接口的类来处理。 这就是Runnable的精髓之所在!
第三种方式:使用内部类的方式
这并不是一种新的实现线程的方式,只是另外的一种写法。比如有些情况我们的线程就想执行一次,以后就用不到了。那么像上面两种方式(继承Thread类和实现Runnable接口)都还要再定义一个类,显得比较麻烦,我们就可以通过匿名内部类的方式来实现。使用内部类实现依然有两种,分别是继承Thread类和实现Runnable接口。
第四种方式:基于线程池的方式
我们知道,线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。当然了,线程池也不需要我们来实现,jdk的官方也给我们提供了API。
在启动线程的时候,并不是调用线程类的run方法,而是调用了线程类的start方法。那么我们能不能调用run方法呢?答案是肯定的,因为run方法是一个public声明的方法,因此我们是可以调用的,但是如果我们调用了run方法,那么这个方法将会作为一个普通的方法被调用,并不会开启线程。这里实际上是采用了设计模式中的模板方法模式,Thread类作为模板,而run方法是在变化的,因此放到子类来实现。
11.说说你对线程的几种状态的了解
1.新建状态(new):新创建一个线程对象的初始状态;也就是通过new关键字创建一个线程对象,但并没有调用start方法时候的状态;
2.就绪状态(Runnable):线程有资格运行,但调度程序还没有把它选为运行线程时的状态,此时,线程具备运行的条件,一旦被选中,马上就可以执行。线程创建后,调用了start方法,线程不处于运行状态;该状态下,等待操作系统的调度,获取cpu使用权之后就可以执行线程代码;
3.运行状态:从就绪状态池中被选择为当前执行的线程的状态;
4.阻塞状态(Blocked):线程在执行的过程中,遇到被synchronized关键字保护的代码,等待获得被保护对象的锁,此时线程会停止执行;这个地方要注意,只有synchronized锁才会让线程进入到Blocked状态,等待利用cas实现的锁(ReentrantLock),线程仍然处于Runnable状态。
5.等待状态(WATTING):线程处于等待状态只有一种情况,就是调用wait方法,如下所示
public static void timedWaiting() {
final Object lock = new Object();
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
}
}
}
6.死亡状态(Dead):线程执行完了或者异常退出run方法,线程结束生命周期;
12. 说说你对多线程锁机制的理解
在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。Java提供了多种多线程锁机制的实现方式,常见的有synchronized、ReentrantLock、Semaphore、AtomicInteger等。每种机制都有优缺点与各自的适用场景,必须熟练掌握他们的特点才能在Java多线程应用开发时得心应手。
几乎每一个Java开发人员都认识synchronized,使用它来实现多线程的同步操作是非常简单的,只要在需要同步的对方的方法、类或代码块中加入该关键字,它能够保证在同一个时刻最多只有一个线程执行同一个对象的同步代码,可保证修饰的代码在执行过程中不会被其他线程干扰。使用synchronized修饰的代码具有原子性和可见性,在需要进程同步的程序中使用的频率非常高,可以满足一般的进程同步要求(详见《Java多线程基础》)。
synchronized实现的机理依赖于软件层面上的JVM,因此其性能会随着Java版本的不断升级而提高。事实上,在Java1.5中,synchronized是一个重量级操作,需要调用操作系统相关接口,性能是低效的,有可能给线程加锁消耗的时间比有用操作消耗的时间更多。到了Java1.6,synchronized进行了很多的优化,有适应自旋、锁消除、锁粗化、轻量级锁及偏向锁等,效率有了本质上的提高。在之后推出的Java1.7与1.8中,均对该关键字的实现机理做了优化。
需要说明的是,当线程通过synchronized等待锁时是不能被Thread.interrupt()中断的,因此程序设计时必须检查确保合理,否则可能会造成线程死锁的尴尬境地。
最后,尽管Java实现的锁机制有很多种,并且有些锁机制性能也比synchronized高,但还是强烈推荐在多线程应用程序中使用该关键字,因为实现方便,后续工作由JVM来完成,可靠性高。只有在确定锁机制是当前多线程程序的性能瓶颈时,才考虑使用其他机制,如ReentrantLock等。
Java中锁的机制
synchronized–Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
1.当两个并发线程访问同一个对象Object中的这个synchronized同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块后才能执行该代码块。
2.然而,当一个线程访问Object的一个synchronized同步代码块时,另一个线程仍然可以访问该Object中的非synchronized同步代码块。
3.尤其关键的是,当一个线程访问Object的一个同步代码块时,其他线程对Object中所有其他同步代码块的访问将被阻塞。也就是说,当一个线程访问Object的一个同步代码块时,他就获得了这个Object的对象锁。结果,其他线程对该Object对象所有同步代码部分的访问都被暂时阻塞。
注:只能放在方法声明上(限定修饰符public、private之后,返回值void、Object之前)和方法内部使用。
13. 反射获取class对象的方式有哪些,反射创建对象的方式有哪些。
反射中,欲获取一个类或者调用某个类的方法,首先要获取到该类的 Class 对象。
1、获取Class对象
在 Java API 中,提供了获取 Class 类对象的三种方法:
第一种,使用 Class.forName 静态方法。前提:已明确类的全路径名。
第二种,使用 .class 方法。说明:仅适合在编译前就已经明确要操作的 Class
第三种,使用类对象的 getClass() 方法。适合有对象示例的情况下
2、获取对象实例
共两种方法:
1、直接用字节码文件获取对应实例
// 调用无参构造器 ,若是没有,则会报异常
Object o = clazz.newInstance();
2、有带参数的构造函数的类,先获取到其构造对象,再通过该构造方法类获取实例:
/ /获取构造函数类的对象
Constroctor constroctor = clazz.getConstructor(String.class,Integer.class); /
// 使用构造器对象的newInstance方法初始化对象
Object obj = constroctor.newInstance("龙哥", 29);
14.Java常用的设计模式有哪些(工厂模式,单例模式,装饰者模式等)
一、工厂模式:
工厂模式分为:简单工厂模式、抽象工厂模式
内涵:
工厂模式是由一个工厂对象决定创建出哪一个具体实例,简单工厂模式是工厂模式家族中最简单最常用的一种
二、单例模式
内涵:保证当前类有且仅有一个对象,不允许被创建多个实例
分类:饿汉式、懒汉式
实现思路:1.构造函数私有化
2.声明一个本类对象静态引用
3.提供获取当前实例的静态方法
三、装饰者模式
内涵:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
适用场景:
1. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销
2. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实
3 当不能采用生成子类的方法进行扩充时
15. UDP和TCP协议的区别
TCP(Transmission Control Protocol 传输控制协议):***是一种面向连接的、可靠的、基于字节流的传输层通信协议,使用三次握手协议建立连接、四次挥手断开连接。面向连接意味着两个使用TCP的应用(通常是一个客户端和一个服务器)在彼此交换数据包之前必须先建立一个TCP连接。在一个TCP连接中,仅有两方进行彼此通信,广播和多播不能用TCP。TCP 协议的作用是,保证数据通信的完整性和可靠性,防止丢包。TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种端点我们叫作套接字(socket),端口号拼接到IP地址即构成了套接字。
***UDP(User Datagram Protocol 用户数据报协议):***是OSI(Open System Interconnection 开放式系统互联)参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。
区别:
1.TCP提供的是面向连接的、可靠的数据流传输;UDP提供的是非面向连接的、不可靠的数据流传输。
2.TCP提供可靠的服务,通过TCP连接传送的数据,无差错、不丢失、不重复,按序到达;UDP尽最大努力交付,即不保证可靠交付。
3.TCP面向字节流;UDP面向报文。
4.TCP连接只能是点到点的;UDP支持一对一、一对多、多对一和多对多的交互通信。
5.UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
6.TCP对系统资源要求较多,UDP对系统资源要求较少。TCP首部有20字节;UDP的首部只有8个字节。
7.TCP的逻辑通信信道是全双工的可靠信道;UDP的逻辑通信信道是不可靠信道。
16.说说你对面向对象的理解
类是对象的模板,对象是类的实例化。
·17.如何避免死锁
当两个线程同时运行时,A线程拥有lock A,在等待lock B,而B线程拥有lock B,在等待lock A,那么这两个线程都在等待对方释放锁,并且谁也不会先释放锁,那么就陷入了死锁。
死锁的解决办法有三个,设置加锁顺序、设置加锁时限、开启死锁检测。
加锁顺序
当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。线程只有获得了从顺序上排在前面的锁之后,才能获取后面的锁。
按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁,并对这些锁做适当的排序,有些时候这是无法预知的。
加锁时限
在尝试获取锁的时候加一个超时时间,也就是在尝试获取锁的过程中如果超过了这个时限该线程则放弃对该锁请求。如果一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行。
不过由于存在线程执行的超时,所以不能认为超时了就一定是出现了死锁。也可能是因为获得了锁的线程(导致其它线程超时)需要很长的时间去完成它的任务。
超时和重试机制是为了避免在同一时间出现的竞争,但是当线程很多时,其中两个或多个线程的超时时间一样或者接近的可能性就会很大,因此就算出现竞争而导致超时后,由于超时时间一样,它们又会同时开始重试,导致新一轮的竞争,带来了新的问题。
死锁检测
每当一个线程获得了锁,会在线程和锁相关的数据结构中(例如map)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。
当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁。如果线程B确实有这样的请求,那么就是发生了死锁。
发生了死锁一种办法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁。
一个更好的办法是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。
18.说说冒泡排序的原理,选择排序的原理,二分查找的原理
冒泡排序:
相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处
选择排序:
从0索引开始,依次和后面元素比较,小的往前方,第一次完毕,最小值出现在了最小索引处
二分查找:
必须是有序列表中,从一端到另一端按照顺序进行查找,二分查找从中间开始
19.wait()和sleep()的区别
1.wait()方法可以使程序进入无限等待状态和计时等待状态,而sleep()方法只能让程序进入计时等待状态
2.wait()方法是可以被notify()方法唤醒的,而sleep()方法不行
20.为什么要使用泛型以及好处
1.避免了类型转换的麻烦,存储什么类型,取出来的就是什么类型
2.把运行期异常提升到了编译器,就是写代码时就会报错
21.什么是java的序列化,如何实现java的序列化
我们有时候将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象,例如,要将java对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个java对象变成某个格式的字节流再传输,但是,jre本身就提供了这种支持,我们可以调用OutputStream的writeObject方法来做,如果要让java 帮我们做,要被传输的对象必须实现serializable接口,这样,javac编译时就会进行特殊处理,编译的类才可以被writeObject方法操作,这就是所谓的序列化。需要被序列化的类必须实现Serializable接口,该接口是一个mini接口,其中没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的。
例如,在web开发中,如果对象被保存在了Session中,tomcat在重启时要把Session对象序列化到硬盘,这个对象就必须实现Serializable接口。如果对象要经过分布式系统进行网络传输或通过rmi等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现Serializable接口。
22.hashSet和TreeSet的区别
1、TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值。
2、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
3、HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的 String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例 。
23.java中io流有哪些,各有什么特点和功能
字节流,字符流。字节流继承于InputStream OutputStream,字符流继承于InputStreamReader OutputStreamWriter。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。 字节流与字符流的区别
字节流,字符流。字节流继承于InputStream OutputStream,字符流继承于InputStreamReader OutputStreamWriter。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。
要把一片二进制数据数据逐一输出到某个设备中,或者从某个设备中逐一读取一片二进制数据,不管输入输出设备是什么,我们要用统一的方式来完成这些操作,用一种抽象的方式进行描述,这个抽象描述方式起名为IO流,对应的抽象类为OutputStream和InputStream ,不同的实现类就代表不同的输入和输出设备,它们都是针对字节进行操作的。
在应用中,经常要完全是字符的一段文本输出去或读进来,用字节流可以吗?计算机中的一切最终都是二进制的字节形式存在。对于“中国”这些字符,首先要得到其对应的字节,然后将字节写入到输出流。读取时,首先读到的是字节,可是我们要把它显示为字符,我们需要将字节转换成字符。由于这样的需求很广泛,人家专门提供了字符流的包装类。
底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转成字节再进行写入。字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为我们向IO设别写入或读取字符串提供了一点点方便。
字符向字节转换时,要注意编码的问题,因为字符串转成字节数组,
其实是转成该字符的某种编码的字节形式,读取也是反之的道理。
24.hashmap底层实现原理
HashMap的底层是哈希表,即数组+链表结构,1.8之后,如果链表的长度超过了8位,就会转换成红黑树结构,提高查询速度,数组结构的特点是,查询快,増删慢,链表结构是查询慢,增删块,HashMap是一个无序集合。
25.ArrayList底层实现原理
ArrayList:内部是数组数据结构,是不同步的,代替了vector.,查询的速度快
内存原理:
在arrayList集合中,是一种线性表,每个对象存储都是有序的,用角标确定对象所存储的位置,查询时,直接通过角标进行查询,速度会很快,但是如果要进行增添、修改、删除操作的话,就要影响后面角标的对象,大部分对象都要移动,直接影响运行效率。
ListkedList:内部是链表数据结构,是不同步的,增删元素的速度很快。
26.说说你对java虚拟机的了解
Jvm虚拟机的作用,是翻译java语言至各平台使用,所以它最大的特点就是跨平台性,JVM本身是不具备跨平台性的,每个系统平台有各自的JVM虚拟机。
27.&和&&的区别
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str != null && !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x==33 & ++y>0) y会增长,If(x==33 && ++y>0)不会增长&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。
备注:这道题先说两者的共同点,再说出&&和&的特殊之处,并列举一些经典的例子来表明自己理解透彻深入、实际经验丰富。
28.==和equals的区别
==是比较运算符,equals是比较方法;
(单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚)
==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如Objet obj = new Object();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
equals方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。例如,对于下面的代码:
String a=new String("foo");
String b=new String("foo");
两条new语句创建了两个对象,然后用a,b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。
在实际开发中,我们经常要比较传递进行来的字符串内容是否等,例如,String input = …;input.equals(“quit”),许多人稍不注意就使用==进行比较了,这是错误的,随便从网上找几个项目实战的教学视频看看,里面就有大量这样的错误。记住,字符串的比较基本上都是使用equals方法。
如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下:
boolean equals(Object o){
return this==o;
}
这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object 类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。
29.String s = new String("xyz");创建了几个String Object? 二者之间有什么区别?
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如String s = new String("xyz")变量s是一个内存,new String("xyz")是另一个内存,此时,变量s所对应的内存中存储的数值就是对象占用的那块内存的首地址。
(两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那一个。New String每写一遍,就创建一个新的对象,它一句那个常量”xyz”对象的内容来创建出一个新String对象。如果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。)
30、线程池的核心类是哪一个?有几种线程池?分别有什么区别?
线程池是一种多线程处理形式,处理过程中将任务添加队列,然后在创建线程后自动启动这些任务,每个线程都使用默认的堆栈大小,以默认的优先级运行,并处在多线程单元中,如果某个线程在托管代码中空闲,则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后辅助线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才能启动。
java里面的线程池的顶级接口是Executor,Executor并不是一个线程池,而只是一个执行线程的工具,而真正的线程池是ExecutorService。
java中的有哪些线程池?
1.newCachedThreadPool创建一个可缓存线程池程
1.newCachedThreadPool,是一种线程数量不定的线程池,并且其最大线程数为Integer.MAX_VALUE,这个数是很大的,一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。但是线程池中的空闲线程都有超时限制,这个超时时长是60秒,超过60秒闲置线程就会被回收。调用execute将重用以前构造的线程(如果线程可用)。这类线程池比较适合执行大量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时被停止。
2.newFixedThreadPool 创建一个定长线程池
newFixedThreadPool 创建一个指定工作线程数量的线程池,每当提交一个任务就创建一个工作线程,当线程 处于空闲状态时,它们并不会被回收,除非线程池被关闭了,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列(没有大小限制)中。由于newFixedThreadPool只有核心线程并且这些核心线程不会被回收,这样它更加快速底相应外界的请求。
3.newScheduledThreadPool 创建一个定长线程池
newScheduledThreadPool 创建一个线程池,它的核心线程数量是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立即回收,它可安排给定延迟后运行命令或者定期地执行。这类线程池主要用于执行定时任务和具有固定周期的重复任务。
4.newSingleThreadExecutor 创建一个单线程化的线程池
newSingleThreadExecutor这类线程池内部只有一个核心线程,以无界队列方式来执行该线程,这使得这些任务之间不需要处理线程同步的问题,它确保所有的任务都在同一个线程中按顺序中执行,并且可以在任意给定的时间不会有多个线程是活动的。
使用线程池的优点
1.重用线程池的线程,避免因为线程的创建和销毁锁带来的性能开销
2.有效控制线程池的最大并发数,避免大量的线程之间因抢占系统资源而阻塞
3.能够对线程进行简单的管理,并提供一下特定的操作如:可以提供定时、定期、单线程、并发数控制等功能
31、说一说IO和NIO的区别以及应用场景?
现代的酒店服务方式跟传统的区别有两个:
1、增加了一个角色,要有一个专门负责收集客人需求的人。NIO里对应的就是Selector。
2、由阻塞服务方式改为非阻塞服务了,客人吃着的时候服务员不用一直侯在客人旁边了。传统的IO操作,比如read(),当没有数据可读的时候,线程一直阻塞被占用,直到数据到来。NIO中没有数据可读时,read()会立即返回0,线程不会阻塞。
NIO中,客户端创建一个连接后,先要将连接注册到Selector,相当于客人进入餐厅后,告诉前台你要用餐,前台会告诉你你的桌号是几号,然后你就可能到那张桌子坐下了,SelectionKey就是桌号。当某一桌需要服务时,前台就记录哪一桌需要什么服务,比如1号桌要点菜,2号桌要结帐,服务员从前台取一条记录,根据记录提供服务,完了再来取下一条。这样服务的时间就被最有效的利用起来了。
区别:
IO NIO
面向流 面向缓冲
阻塞IO 非阻塞IO
无 选择器
Java NIO提供了与标准IO不同的IO工作方式:
Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
Asynchronous IO(异步IO):Java NIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。
Selectors(选择器):Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
使用场景:
NIO的优势:
1.优势在于一个线程管理多个通道;但是数据的处理将会变得复杂;
2.如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,采用这种;
传统IO的优势:
1.适用于一个线程管理一个通道的情况;因为其中的流数据的读取是阻塞的;
2.如果需要管理同时打开不太多的连接,这些连接会发送大量的数据;
区别:
NIO vs IO之间的理念上面的区别(NIO将阻塞交给了后台线程执行):
IO是面向流的,NIO是面向缓冲区的
Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方;
NIO则能前后移动流中的数据,因为是面向缓冲区的
IO流是阻塞的,NIO流是不阻塞的
Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了
Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。NIO可让您只使用一个(或几个)单线程管理多个通道(网络连接或文件),但付出的代价是解析数据可能会比从一个阻塞流中读取数据更复杂。
非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
选择器
Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
32.java中会存在内存泄漏吗,请简单描述
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的
java中的内存泄露的情况:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是java中可能出现内存泄露的情况,例如,缓存系统,我们加载了一个对象放在缓存中(例如放在一个全局map对象中),然后一直不再使用它,这个对象一直被缓存引用,但却不再被使用。
检查java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。
如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
内存泄露的另外一种情况:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。
33.说一说你了解的数据结构。
1、数组
数组是可以再内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始。例如下面这段代码就是将数组的第一个元素赋值为 1。
int[] data = new int[100];data[0] = 1;
优点:
1、按照索引查询元素速度快
2、按照索引遍历数组方便
缺点:
1、数组的大小固定后就无法扩容了
2、数组只能存储一种类型的数据
3、添加,删除的操作慢,因为要移动其他的元素。
适用场景:
频繁查询,对存储空间要求不大,很少增加和删除的情况。
2、栈
栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。
栈的结构就像一个集装箱,越先放进去的东西越晚才能拿出来,所以,栈常应用于实现递归功能方面的场景,例如斐波那契数列。
3、队列
队列与栈一样,也是一种线性表,不同的是,队列可以在一端添加元素,在另一端取出元素,也就是:先进先出。从一端放入元素的操作称为入队,取出元素为出队,
使用场景:因为队列先进先出的特点,在多线程阻塞队列管理中非常适用。
4、链表
链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域。根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。
链表的优点:
链表是很常用的一种数据结构,不需要初始化容量,可以任意加减元素;
添加或者删除元素时只需要改变前后两个元素结点的指针域指向地址即可,所以添加,删除很快;
缺点:
因为含有大量的指针域,占用空间较大;
查找元素需要遍历链表来查找,非常耗时。
适用场景:
数据量较小,需要频繁增加,删除操作的场景
5、树
树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;
没有父节点的节点称为根节点;
每一个非根节点有且只有一个父节点;
除了根节点外,每个子节点可以分为多个不相交的子树;
在日常的应用中,我们讨论和用的更多的是树的其中一种结构,就是二叉树。
二叉树是树的特殊一种,具有如下特点:
1、每个结点最多有两颗子树,结点的度最大为2。
2、左子树和右子树是有顺序的,次序不能颠倒。
3、即使某结点只有一个子树,也要区分左右子树。
二叉树是一种比较有用的折中方案,它添加,删除元素都很快,并且在查找方面也有很多的算法优化,所以,二叉树既有链表的好处,也有数组的好处,是两者的优化方案,在处理大批量的动态数据方面非常有用。
扩展:
二叉树有很多扩展的数据结构,包括平衡二叉树、红黑树、B+树等,这些数据结构二叉树的基础上衍生了很多的功能,在实际应用中广泛用到,例如mysql的数据库索引结构用的就是B+树,还有HashMap的底层源码中用到了红黑树。这些二叉树的功能强大,但算法上比较复杂,想学习的话还是需要花时间去深入的。
34.Statement和PrepareStatement有什么区别?那个性能更好?
Statement和PrepareStatement的作用都是一样的,都是执行sql语句的对象。它们的区别是用Statement执行某些sql语句时,如果有特殊含义的语句参与字符串的拼接,会造成sql注入的安全问题,这时如果用PrepareStatement预编译sql语句,使用占位符?作为参数使用,就可以解决这个问题。所以我们一般使用PrepareStatement对象来执行sql语句比较安全,性能也更好。
35.JDBC操作数据库的核心步骤,数据库事务的特性
JDBC操作数据库的核心步骤:
导入驱动jar包
注册驱动
通过驱动管理对象DriverManager来获取数据库连接对象Connection,指定url数据连接的路径,用户名和密码
定义sql语句
通过数据库连接对象来创建执行sql的对象PrepareStatement
执行sql,接受返回结果
处理结果
释放资源
数据库事务的特性:
原子性:一个事务操作是不可分隔的,要么同时成功,要么同时失败
持久性:能持久化保存事务操作的数据
隔离性:期望事务之间不会相互影响
一致性:事务操作前后的数据总量是不变的,一致的。
36.Post请求和get请求的区别
Post和get都是定义表单form时数据的提交方式method,表单项中的数据要想被提交,必须指定其name属性,它们的区别是:
Get提交的数据是会在地址栏中显示的,会封装在请求行中,相对不安全,而且数据的大小有限制;
Post提交的数据是不会在地址栏中显示的,会封装在请求体中,相对安全,且数据大小没有限制。
37.面向对象的特征有哪些方面
1. 面向对象的编程语言有封装、继承 、抽象、多态等4个主要的特征。
2. 封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位?封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。
3. 抽象:?抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处
4. 继承:?在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
38.int和integer区别
1. Integer 表示的是对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值。
2. Integer是int的包装类,int则是java的一种基本数据类型
3. Integer的默认值是null,int的默认值是0
4. Integer变量必须先实例,int变量则可以直接使用
39.构造器是否可用被重写
1.构造器是不能被继承的,因为每个类的类名都不相同,而构造器名称与类名相同,所以根本谈不上继承。?
由于构造器不能继承,所以就不能被重写。但是,在同一个类中,构造器是可以被重载的
40.post和get的区别
Post和get都是定义表单form时数据的提交方式method,表单项中的数据要想被提交,必须指定其name属性,它们的区别是:
Get提交的数据是会在地址栏中显示的,会封装在请求行中,相对不安全,而且数据的大小有限制;
Post提交的数据是不会在地址栏中显示的,会封装在请求体中,相对安全,且数据大小没有限制。
41.Servlet的生命周期
Servlet的生命周期:
被创建:执行init方法,只执行一次,如果sevlet标签下配置的load-on-startup的值为0或者正整数,服务器启动时创建,如果值为负数(默认),则第一次访问时创建
提供服务:执行service方法,执行多次,每次访问servlet时,Service方法都会被调用一次
被销毁:执行destroy方法,只执行一次,只有服务器正常关闭时,才会执行destroy方法,在Servlet被销毁之前执行,一般用于释放资源
42.转发和重定向的区别
1.转发地址栏不会发生变化,重定向时地址栏会发生变化
2.转发只能访问当前服务器下的资源,重定向可以访问任意资源,包括外部服务器资源
3.转发是一次请求响应,可以使用request对象来共享数据,重定向是两次请求响应,不能使用request对象来共享数据。
一般情况下:servlet-->jsp使用转发,servlet-->servlet使用重定向,关键是看浏览器地址栏是否需要改变,是否需要转向另一个功能。
43.JSP的九个内置对象及三大指令
九个内置对象:
变量名 真实类型 作用
* pageContext PageContext 当前页面共享数据,还可以获取其他八个内置对象
* request HttpServletRequest 一次请求访问的多个资源(转发)
* session HttpSession 一次会话的多个请求间
* application ServletContext 所有用户间共享数据
* response HttpServletResponse 响应对象
* page Object 当前页面(Servlet)的对象 this
* out JspWriter 输出对象,数据输出到页面上
* config ServletConfig Servlet的配置对象
* exception Throwable 异常对象
三大指令:
1. page: 配置JSP页面的
2. include: 页面包含的。导入页面的资源文件
3.taglib : 导入资源
44.HTTP协议常见的状态码
1. 1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
2. 2xx:成功。代表:200
3. 3xx:重定向。代表:302(重定向),304(访问缓存)
4. 4xx:客户端错误。* 代表:* 404(请求路径没有对应的资源) * 405:请求方式没有对应的doXxx方法
5. 5xx:服务器端错误。代表:500(服务器内部出现异常)
45.简单描述一下数据库的事务以及他的操作及特性
简单地说,事务就是逻辑上的一组SQL语句操作,组成这组操作的各个SQL语句,执行时要么全部成功,要么全部失败。
数据库默认事务是自动提交的,也就是发一条sql它就执行一条。如果想多条sql放在一个事务中执行,则需要使用事务进行处理。当我们开启一个事务,并且没有提交,mysql会自动回滚事务。或者我们使用rollback命令手动执行回滚事务。
事务的四大特性
1、原子性(Atomicity)
事务是一个不可分割的单位,事务中的所有SQL操作要么都发生,要么都不发生。
2、一致性(Consistency)
事务发生前和发生后,数据的完整性必须保持一致。
3、隔离性(Isolation)
当并发访问数据库时,一个正在执行的事务在执行完毕前,对于其它的会话是不可见的,多个并发的事务之间的数据是不可见的。
4、持久性(Durability)
一个事务一旦被提交,它对数据库中的数据改变是永久性的。如果出了错误,事务也不允许撤销,只能通过”补偿性事务”。
46.事务的隔离级别和存在的问题
事务的隔离级别:
read uncommitted 读未提交 不能解决问题
Read committed 读已提交 可解决脏读 Oracle默认
Repeatable read 可重复读 可解决虚读 mysql默认
Serializable 串行化 可解决所有
存在的问题:
脏读:一个事务,读取到另一个事务中没有提交的数据
不可重复读(虚读):在同一个事务中,两次读取到的数据不一样
幻读:一个事务操作(DML)数据中的所以有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改
47.说一下=、==、===的区别
=是赋值,==是比较值,===是js中的比较运算符,先比较类型,再比较值。
48.过滤器的执行流程和过滤器生命周期方法
过滤器执行流程
1. 执行过滤器
2. 执行放行后的资源
3. 回来执行过滤器放行代码下边的代码
过滤器生命周期方法
1. init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
2. doFilter:每一次请求被拦截资源时,会执行。执行多次
3. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源
49.动态代理是干什么的?代理对象与真实对象的关系?
1.动态代理是干什么的?
在不改变源代码的情况下,增强一个类
2.代理对象与真实对象的关系
a.代理类继承目标类
b.代理类与目标类实现同样的接口
3.(目标类没有特有方法)代理对象调用方法会执行InvocationHandler中的invoke方法
4.我们可以在invoke方法中增强:参数列表,返回值,方法体逻辑
5.我们会在InvocationHandler中的invoke方法中去用真实对象调用真正的方法method.invoke(obj,args);
50.HTTP协议的特点和请求消息格式
HTTP协议的特点:
基于TCP/IP的高级协议
默认端口号:80
基于请求/响应模型,一次请求对应一次响应
无状态的,每次请求之间相互独立,不能交互数据
请求消息格式:
请求行:请求方式 请求url 协议/版本
请求头:浏览器信息
请求空行:分隔作用
请求体:post请求方式才有
51.XML的解析方式sax解析和dom解析区别
有两种方式:
DOM思想:将标记语言文档一次性加载进内存,形成DOM树
优点:操作方便,可以对文档进行增删改查操作
缺点:占内存
SAX思想:逐行读取,基于事件驱动
优点:不占内存
缺点:只能读取,不能增删改。
52.cookie的生命周期,cookie何时创建何时销毁,cookie的类别
cookie是客户端会话技术,将数据保存在客户端
cookie在服务器端创建,使用响应对象的addCookie方法(在响应头以键值对方式)发送cookie对象给客户端,客户端在第二次请求时以请求头的方式将cookie对象传送给服务器端,服务器端使用请求对象的getCookies方法获取cookie对象
Cookie对象在服务器端new出来的,默认情况下,客户端关闭后,cookie数据被销毁,可以使用setMaxAge‘(int seconds)方法持久化存储cookie数据,seconds默认为负数,就是在浏览器关闭时销毁,设置为正数,cookie会持久化存储相应的时间,设置为0就会删除cookie数据
Cookie的类别有两种:
临时Cookie(会话Cookie)
不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。
这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
2,永久Cookie
设置了过期时间,浏览器就会把cookie保存到硬盘上,
关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。
存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。
而对于保存在内存的cookie,不同的浏览器有不同的处理方式。
53.session的生命周期,何时创建,何时销毁,session销毁的方式有哪几种
Session是服务器端会话技术,基于cookie,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。
sessionid第一次产生是在直到某server端程序调用 HttpServletRequest.getSession()这样的语句时才被创建,销毁有三种情况:
1.服务器关闭(不考虑tomcat中的钝化和活化,就是说如果是用tomcat关闭服务器,则tomcat会自动完成session的钝化,将session对象序列化到硬盘上)
2.调用Session对象的invalidate方法
3.session的默认失效时间是30分钟,浏览器关闭30分钟后,session会被销毁,可以用方法设置存活时间。
54.HashSet和HashMap的区别
1.HashSet实现了Set接口,HashMap实现了Map接口
2.HashSet仅仅存储对象,HashMap存储键值对
3.添加元素的方式不一样,HashSet是用add方法,HashMap是用put方法
4.HashSet是用成员对象来计算hashcode值,如果hashcode值相同,则用equals比较两个对象是否一样,如果不同,则返回false
HashMap是使用键对象来计算hashcode值
HashSet查询比较慢,HashMap比较快,因为是用唯一的键来获取对象。
HashSet内部就是使用HashMap实现,只不过HashSet里面的HashMap所有的value都是同一个Object而已,因此HashSet也是非线程安全的
55.getAttribute()和getParameter()的区别
两者区别:
①getParameter()获取的是客户端设置的数据。
getAttribute()获取的是服务器设置的数据。
②getParameter()永远返回字符串
getAttribute()返回值是任意类型
56.谈谈你对MVC的理解
MVC是Model—View—Controler的简称。即模型—视图—控制器。MVC是一种设计模式,它强制性的把应用程序的输入、处理和输出分开。 MVC中的模型、视图、控制器它们分别担负着不同的任务。
视图: 视图是用户看到并与之交互的界面。视图向用户显示相关的数据,并接受用户的输入。视图不进行任何业务逻辑处理。
模型: 模型表示业务数据和业务处理。相当于JavaBean。一个模型能为多个视图提供数据。这提高了应用程序的重用性
控制器: 当用户单击Web页面中的提交按钮时,控制器接受请求并调用相应的模型去处理请求。
然后根据处理的结果调用相应的视图来显示处理的结果。
MVC的处理过程:首先控制器接受用户的请求,调用相应的模型来进行业务处理,并返回数据给控制器。控制器调用相应的视图来显示处理的结果。并通过视图呈现给用户。
如在项目中要对应MVC的话:View 对应项目中Jsp,Controler对应Action,Model 对应service+dao层的业务逻辑和持久层的操作。
MVC设计模式的好处:耦合性低,方便维护,利于分工,重用性高
缺点是:使项目开发变得复杂化,对开发人员要求高
57.session和application的区别
1.session是会话变量,只要同一个浏览器没有被关闭,session对象就会存在。因此在同一个浏览器窗口中,无论向服务器发送多少请求,session对象只有一个。但是如果在一个会话中,客户端长时间不向服务器发出请求,session对象就会自动消失。这个时间取决于服务器,但是我们可以通过编写程序进行修改这个session的生命周期的时间。session.setMaxInactiveInterval(10000);//用来设置session的有效期为10000秒,超出这个范围将失效。
并且通过session对象可以存储或者读取客户的相关信息,例如用户名或购物信息等,可以通过session对象的setAttribute(String name,Object obj)方法和getAttribute(String name)的方法实现。注意的是getAttribute()方法的返回值是Object类型,如果将获取到的信息赋给String类型的变量,则需要进行强制类型转换或者调用其的toString()方法。
session.setAttribute("user","小名");
String user=(String)session.getAttribute("user");
2.application它类似于系统的全局变量,用于保存所有程序中的公有数据。它在服务器启动时自动创建,在服务器停止时销毁。当application对象没有被销毁的时候,所有用户都可以享用该application对象。它的生命周期可以说是最长的。但是其应用程序初始化的参数是要在web.xml文件中进行设置的,通过<context-param>标记配置应用程序初始化参数。也就是说同时再打开另一个浏览器,他们使用的都是同一个application对象
58.this和super的区别
(1.)代表的事物不同
super代表的是父类空间的引用
this代表的是所属函数的调用者对象
(2.)使用前提不同
super必须要有继承关系才能使用
this不需要继承关系也能使用
(3.)调用的构造函数不同
super:调用父类的构造函数
this:调用所属类的构造函数
59.public、protected、private以及不写时的区别。
作用域 当前类 同一package 子孙类 其他package
public √ √ √ √
protected √ √ √ ×
friendly √ √ × ×
private √ × × ×
备注:只要记住了有4种访问权限,4个访问范围,然后将全选和范围在水平和垂直方向上分别按排从小到大或从大到小的顺序排列,就很容易画出上面的图了。
例子:应用场景
1、public:public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用,在程序的任何其它地方访问。
2、private:private表示私有,私有的意思就是除了class自己之外,和public相反,加上这个修饰的属性和方法,只允许在自己本身这个类里访问,程序的任何其它地方都不能访问
3、protected:protected对于子女、朋友来说,就是public的,可以自由使用,没有任何限制,而对于其他的外部class,protected就变成private。受保护的,位于public和private中间,加上这个修饰的属性和方法,只能在子类(extends)和同包下的程序访问,别的的地方不能访问。
4.default(默认):同一包中的类可以访问,声明时没有加修饰符,认为是friendly。
60. html和xml的区别
xml和html都是用于操作数据或数据结构,在结构上大致是相同的,但它们在本质上却存在着明显的区别。
一、名称
HTML:超文本标记语言
XML:可扩展标记语言
二、不同点
1、语法上
HTML:语法要求不是很严格,例如:不严格区分大小写,可自动过滤空格,可以不适用引号等。
XML:与之相反。
2、标记不同
html使用固有的标记;而xml没有固有的标记。
Html标签是预定义的;XML标签是免费的、自定义的、可扩展的。
3、作用不同
html是用来显示数据的;xml是用来描述数据、存放数据的,所以可以作为持久化的介质。Html将数据和显示结合在一起,在页面中把这数据显示出来;xml则将数据和显示分开。 XML被设计用来描述数据,其焦点是数据的内容。HTML被设计用来显示数据,其焦点是数据的外观。
61. javaScript和ECMAScript区别
1、ECMAScript是JavaScript的规格,JavaScript是ECMAScript的一种实现,在日常场合,这两个词是可以互换的。
JavaScript的创造者Netscape公司,将JavaScript提交给国际标准化组织ECMA,希望这种语言能够成为国际标准,后来ECMA发布标准文件的第一版(ECMA-262),规定了浏览器脚本语言的标准,并将这种语言称为ECMAScript。该标准从一开始就是针对JavaScript语言制定的,之所以不叫JavaScript,有两个原因:一是商标,Java是Sun公司的商标,根据授权协议,只有Netscape公司可以合法地使用JavaScript这个名字,且JavaScript本身也已经被Netscape公司注册为商标;二是想体现这门语言的制定者是ECMA,不是Netscape,有利于保证这门语言的开放性和中立性。
2、但事实上,JavaScript比ECMA-262的含义多得多,一个完整的JavaScript实现应该由以下三个部分组成:
1) ECMAScript:核心
2) DOM:文档对象模型
3) BOM:浏览器对象模型
62. xml的两种约束区别 DTD,SCHAME
Schema是对XML文档结构的定义和描述,其主要的作用是用来约束XML文件,并验证XML文件有效性。DTD的作用是定义XML的合法构建模块,它使用一系列的合法元素来定义文档结构。它们之间的区别有下面几点:
1、Schema本身也是XML文档,DTD定义跟XML没有什么关系,Schema在理解和实际应用有很多的好处。
2、DTD文档的结构是“平铺型”的,如果定义复杂的XML文档,很难把握各元素之间的嵌套关系;Schema文档结构性强,各元素之间的嵌套关系非常直观。
3、DTD只能指定元素含有文本,不能定义元素文本的具体类型,如字符型、整型、日期型、自定义类型等。Schema在这方面比DTD强大。
4、Schema支持元素节点顺序的描述,DTD没有提供无序情况的描述,要定义无序必需穷举排列的所有情况。Schema可以利用xs:all来表示无序的情况。
5、对命名空间的支持。DTD无法利用XML的命名空间,Schema很好满足命名空间。并且,Schema还提供了include和import两种引用命名空间的方法。
63. 什么是响应式布局?
一、什么是响应式布局?
响应式布局就是一个网站能够兼容多个终端——而不是为每个终端做一个特定的版本。这个概念是为解决移动互联网浏览而诞生的。基于栅格系统。
响应式布局可以为不同终端的用户提供更加舒适的界面和更好的用户体验。
二、响应式布局的优点和缺点有哪些呢?
(1) 优点 :1. 面对不同分辨率设备灵活性强
2. 能够快捷解决多设备显示适应问题
(2) 缺点 :1.不能完全兼容所有浏览器,代码累赘,会出现隐藏无用的元素,加载时间加长
2. 一定程度上改变了网站原有的布局结构,会出现用户混淆的情况。
64. cookie和session区别以及生命周期
cookie 和session 的区别:
1 、安全性上, session信息存储在服务器端的所以安全性高,cookie的存在浏览器端所以不安全
2、存储的类型, session 存储的类型是 Object, cookie 只能存字符串(并且需要进行编码处理)
3、存储大小, session 理论上没有限制(但不建议存储太多内容), cookie 的限制:每个cookie不能超过4k,每个网站cookie个数也有限制的
4 、失效时间, session 两次请求间隔30分钟, cookie 默认关闭浏览器失效,还可以通过 maxAge 调整的更长
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中
65. Servlet域对象以及作用范围
Servlet三大域对象的应用 request、session、application(ServletContext)
ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。
66. jsp的域对象
四个域对象:
pageContext page域
request request域
session session域
application context域
1)域对象作用:保存数据 和 获取数据 ,用于数据共享。
2)域对象方法:
setAttribute("name",Object) 保存数据
getAttribute("name") 获取数据
removeAttribute("name") 清除数据
3)域对象作用范围:
page域: 只能在当前jsp页面中使用(当前页面)
request域: 只能在同一个请求中使用(转发)
session域: 只能在同一个会话(session对象)中使用(私有的)
context域: 只能在同一个web应用中使用。(全局的)
67. js的数据类型
JavaScript 数据类型
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
注:Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
68. redis数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
69. 过滤器生命周期
启动服务器时加载过滤器的实例
调用init()方法初始化实例,在项目启动时候调用一次;
每一请求只调用方法的doFilter()进行真正的过滤处理,每次发出请求都会调用;
停止服务器调用destroy()方法,销毁实例,释放资源,项目停止时销毁一次。
注意:
过滤器是写在web.xml文件中的。其基本实现方式是:
新建一个类,实现javax.servlet.Filter接口,然后在该类中重写接口的三个方法。
70. 监听器生命周期
listener是web三大组件之一,是servlet监听器,用来监听请求,监听服务端的操作。
listener分为:(都是接口类,必须实现相应方法)
1.生命周期监听器(3个)
ServletContextListener
requestInitialized 在容器启动时被调用(在servlet被实例化前执行)
requestDestroyed 在容器销毁时调用(在servlet被销毁后执行)
HttpSessionListener
sessionCreated 在HttpSession创建后调用
sessionDestroyed 在HttpSession销毁前调用(执行session.invalidate();方法)
ServletRequestListener
requestDestroyed 在request对象创建后调用(发起请求)
requestInitialized 在request对象销毁前调用(请求结束)
2.属性变化监听器(3个)
attributeAdded(ServletContextAttributeEvent event) 向appliction中添加属性时调用
attributeRemoved(ServletContextAttributeEvent event) 从appliction中删除属性时调用
attributeReplaced(ServletContextAttributeEvent event) 替换application中的属性时
HttpSessionAttributeListener
ServletRequestAttributeListener
attributeAdded(ServletRequestAttributeEvent event)
attributeRemoved(ServletRequestAttributeEvent event)
attributeReplaced(ServletRequestAttributeEvent event)
attributeAdded(HttpSessionBindingEvent event)
attributeRemoved(HttpSessionBindingEvent event)
attributeReplaced(HttpSessionBindingEvent event)
以上监听器接口除了传参不同,方法名都是一样的。分别监听application,session,request对象的属性变化。
3.session中指定类属性变化监听器(2)
HttpSessionBindingListener
HttpSessionActivationListener
sessionWillPassivate(HttpSessionEvent se) 当对象session被序列化(钝化)后调用
sessionDidActivate(HttpSessionEvent se) 当对象session被反序列化(活化)后调用
valueBound(HttpSessionBindingEvent event) 当该类实例设置进session域中时调用
valueUnbound(HttpSessionBindingEvent event) 当该类的实例从session域中移除时调用
71.什么是spring框架?它的主要模块有哪些?
Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。
Spring有七大功能模块,分别是Spring Core,AOP,ORM,DAO,MVC,WEB,Context。
1,Spring Core
Core模块是Spring的核心类库,Spring的所有功能都依赖于该类库,Core主要实现IOC功能,Sprign的所有功能都是借助IOC实现的。
2,AOP
AOP模块是Spring的AOP库,提供了AOP(拦截器)机制,并提供常用的拦截器,供用户自定义和配置。
3,ORM
Spring 的ORM模块提供对常用的ORM框架的管理和辅助支持,Spring支持常用的Hibernate,ibtas,jdao等框架的支持,Spring本身并不对ORM进行实现,仅对常见的ORM框架进行封装,并对其进行管理
4,DAO模块
Spring 提供对JDBC的支持,对JDBC进行封装,允许JDBC使用Spring资源,并能统一管理JDBC事物,并不对JDBC进行实现。(执行sql语句)
5,WEB模块
WEB模块提供对常见框架如Struts1,WEBWORK(Struts 2),JSF的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器。
6,Context模块
Context模块提供框架式的Bean访问方式,其他程序可以通过Context访问Spring的Bean资源,相当于资源注入。
7,MVC模块
WEB MVC模块为Spring提供了一套轻量级的MVC实现,在Spring的开发中,我们既可以用Struts也可以用Spring自己的MVC框架,相对于Struts,Spring自己的MVC框架更加简洁和方便。
72.spring框架的好处有哪些?
1.方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
2.AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
3.声明事物的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4.方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
6.降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
7.Java 源码是经典学习范例
Spring的源码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。
73.什么是DI?什么是IOC?
IOC(控制反转):全称为:Inverse of Control。从字面上理解就是控制反转了,将对在自身对象中的一个内置对象的控制反转,反转后不再由自己本身的对象进行控制这个内置对象的创建,而是由第三方系统去控制这个内置对象的创建。
DI(依赖注入):全称为Dependency Injection,意思自身对象中的内置对象是通过注入的方式进行创建。
那么IOC和DI这两者又是什么关系呢?
IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。而Spring中的核心机制就是DI
74.BeanFactory和ApplicationContext的区别
BeanFactory:
是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
ApplicationContext:
应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;
1) 国际化(MessageSource)
2) 访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
4) 消息发送、响应机制(ApplicationEventPublisher)
5) AOP(拦截器)
两者装载bean的区别
BeanFactory:
BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;
ApplicationContext:
ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;
75. Spring Bean有三种配置方式:
1.传统的XML配置方式
创建applicationContext.xml文件,如果是setXXX的方式:配置bean标签,包括唯一标识id,全限定类名class,以及内标签property设置相关属性以及对象的依赖注入
如果是有参构造的方式:配置constructor-arg标签,一般用第一种方式
2.基于注解的配置
在类上加@Component注解实例化Bean,成员对象上加@Autowaird注解注入成员对象,@Value注解注入普通属性,在applicationContext.xml中配置组件扫描
3.基于类的Java Config
新注解方式,完全脱离xml配置,使用配置类,不常用。
————————————————
版权声明:本文为CSDN博主「${简简单单}」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/aohongzhu/article/details/91379909