JAVA相关知识总结

前言:

    根据自己的经验和以往的总结将java分为7个部分,囊括了java领域大部分的知识和技术,如果能掌握约7层左右,再看一些面试题目,大多的java高级工程师的技术面试都没什么问题。对于面试者来说,学历和履历对于面试会有很大的竞争力,但是对于目前已经工作的朋友来说,学历和履历可能不易提升,那就学好知识,用技能打动面试官:

        1、Java基础       

        2、Java虚拟机相关   

        3、流行框架与技术   

        4、分布式服务    

        5、数据库与Nosql

        6、算法与数据结构    

        7、通讯协议

一、java基础

    1、面向对象   

        1、面向对象和面向过程的区别

            (1)“面向过程”是一种是事件为中心的编程思想。就是分析出解决问题所需的步骤,然后用函数把这写步骤实现,并按顺序调用。

             (2) ”面向对象“是以“对象”为中心的编程思想。

        2、四个基本特性

            (1)抽象:忽略主题全部不打算把全部事件描述下来,只是抽取主要部分抽象化描述,可以理解抽象是一个接口类或一个抽象类!比如:描述一个抽象功能,用接口表示,只要添加、删除、修改等方法功能!(抽象类和接口类是Java抽象的一个机制)!

                抽象类(abstr class):  1.可以实现继承父类 2.可以拥有私有的方法或私有的变量, 3.只能单独继续一个类!

             接口类(interface):  1.不可以实现继承 2.不可以拥有私有的方法或私有的变量 3.一个接口类可以实现多重继承             

            (比如A类接口实现B\C\类,那么B\C\继承是另一个类)!接口是为了拟补Java单继承问题!

            (2)继承: 继承是一个层次结构,子类继承父类的方法可以重写或重载!
             重写(Overriding):方法重写又称为方法覆盖,子类和父类具有相同的方法名称、相同返回类型、相同参数!如果子类打算调用父类的方法 使用,可以在具有和父类相同的情况下,重写方法的逻辑!如果需要使用父类方法可以使用supper关键字引用父类!
             重载(Overloading): 子类重载父类_具有相同的方法和不同的参数或类型,也就是方法名相同但是参数不同或返回类型也可以不相同!
            (3)封装:主要是把过程和数据包围起来,不对外部公开内部的数据和逻辑,从而保护内部的数据结构不被外界改变,起到保护作用!
            (4)多态性:不同类的对象对同一个类的对象做出不同的响应信息!(Java提出多态性是对Java单继承的一个补充)

        3、重载和重写

            (1) 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载是一个类中多态性的一种表现。
            (2) Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。

            (3)重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。

             (1)父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
             (2)若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。子类函数的访问修饰权限不能少于父类的;

        4、构造器Constructor是否可被override

                构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。构造器不是方法,那么用来修饰方法特性的所有修饰符都不能用来修饰构造器(并不等与构造器具备这些特性,虽然不能用static修饰构造器,但它却有静态特性)构造器只能用 public private protected这三个权限修饰符,且不能有返回语句。

        5、访问控制符

                

        6、抽象类和接口的区别

   抽象类:
      (1) 抽象方法,只有行为的概念,没有具体的行为实现。
   使用:abstract 关键字修饰,并且没有方法体。
       (2)包含抽象方法的类,就一定是抽象类。
   使用: abstract 关键字修饰,包含抽象方法。
               (3)抽象类不能直接创建实例。可以定义引用变量。
               (4)抽象类只能被继承,一个具体类继承一个抽象类,必须实现所有抽象方法。  
               (5)抽象方法和抽象类非常适合作为系统的分析和设计的工具。

    接口:

                (1)全部的方法都是抽象方法,全部的属性都是常量。接口用来表示纯抽象概念,没有任何具体的方法和属性。

                (2)不能实例化,可以定义变量。
                (3)接口变量可以引用具体实现类的实例。
                (4)接口只能被实现(继承),一个具体类实现接口,必须使用全部的抽象方法。
                (5)接口之间可以继承。
                 (6)一个具体类可以实现多个接口,实现多继承现象,表示:
                (7) 接口中的属性,默认是常量 public static final 
                (8)接中的方法一定是:public abstract 
                (9)实现一个接口,使用关键字implements, 实现实际上是
                           一种继承关系。接口和实现类是父子类型的关系
    2、语言特性

        1、String和StringBuffer、StringBuilder的区别

            性能差别:StringBuilder > StringBuffer > String;

        String:适用于少量的字符串操作的情况,字符串常量对字符串的操作(修改、拼接)其实是在创建新的对象,效率低下;
                StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况,线程不安全
                StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况,线程安全

        2、hashCode和equals方法的关系

            hashcode()方法是JDK根据对象的地址或者字符串的值计算出来的int类型的数值(哈希码值)。

            同一对象多次调用hashcode()方法,必须返回相同的数值。

            如果两个对象根据equals()方法比较是相等的,那么两个对象调用hashcode()方法返回的结果必须相等。

            如果两个对象根据equals()方法比较是不相等的,那么两个对象调用hashcode()方法返回的结果不一定不相等。

        3、自动装箱与拆箱

                自动装箱:把基本类型用它们对应的包装类包装起来,使它们具有对象的特质,可以调用所对应的包装类所定义的方法Java通过自动装箱和拆箱的机制,节省了部分内存开销和创建对象的开销,提高了效率同时简化了代码。在使用该机制的时候,需要注意以下几点: 
                    (1)在进行==比较的时候,在自动装箱池范围内的数据的引用是相同的,范围外的是不同的。 
                    (2)在自动拆箱时,要保证包装类的引用不为空。

        4、什么是泛型、为什么要使用以及泛型擦除

                泛型:本质是参数化类型。 
                为什么要使用?创建集合的时候,往集合里面添加数据,再次取出时,集合会忘记这数据类型,该对象的编译类型就会变成Object类型,否则如果想要变回原来的数据类型的时候,就要强制进行转换。创建集合的时候,我们就指定集合类型,避免这个过程。 
                泛型擦除?Java的泛型处理过程都是在编译器中进行的,编译器首先会生成bytecode码,这个过程是不包括泛型类型,泛型类型在编译的时候是被擦除的,这个过程及泛型擦除。 
                泛型擦除的过程: 
                (1)将所有泛型参数用顶级父类类型替换 
                (2)擦除所有的参数类型

        5、Java中的集合类

                    至少得弄明白,每种集合之间的区别,有精力更好的就是研究一下集合的源码,ArrayList和HashMap就可以了,得知道它们底层的原理,比如ArrayList怎么动态扩容,底层Add()、remove()等方法的实现,HashMap中的怎么通过hash算法找到对应的Value值 等等,详解见:http://blog.csdn.net/u010775025/article/details/79315361

                Collection下所有子类集合都用于存储Value,Map下所有子类集合都用于存储Key-Value。

                ArrayList是线程不安全的,Vector是线程安全的(二者底层都是数组类型结构),LinkedList线程不安全(底层链表类型结构);

                ArrayList每次扩容50%,而Vector每次扩容翻倍;

                 Set集合存储无序的不可重复元素,允许一个null元素。HashSet对象必须定义hashcode()方法,LinkedHashSet具备HashSet的性能,但内部使用链表维护元素的顺序(插入顺序)。TreeSet底层使用树结构维护有序的元素。

                 HashMap是线程不安全的,可以存储null值null键和;HashTable是线程安全的,不允许存储null值null键;HashTable因为是线程安全的,所以性能低于HashMap。

        6、Java中的异常

                IndexOutOfBoundsEecption:元素越界异常;

                ArrayIndexOutOfBoundsEecption:多个元素越界异常;

                ClassCastException:类型转换异常;

                NullPointerException:空指针异常,null对象的应用;

                RuntimeException:运行时异常;

                IOException:IO操作异常;

                ConnectException:连接失败异常;

        7、Java中的NIO,BIO,AIO

                BIO(同步阻塞IO):一个连接对应一个线程

                当有客户端连接请求时,服务端需要启动一个线程进行处理,如果这个连接不做任何处理,会造成不必要的线程开销,可以通过线程池机制改善,从而实现伪异步IO;

                NIO(同步非阻塞IO):N个连接对应一个线程

                客户端所有的连接请求都会注册到多路复用器上,服务端通过一个多路复用器来处理所有请求。

                AIO(异步非阻塞IO):NIO的2.0版本,引入了异步通道的概念,可以实现异步调用。

                异步实现方式:通过java.util.concurrent.Future类来表示异步操作的结果;

                在执行异步操作的时候传入java.nio.channels。

        8、IO和NIO区别

                NIO是Java1.4的新特性,提供了与标准IO不同的工作方式:

                标准IO基于字节流和字符流进行操作,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据从通道读取到缓冲区中,或者从缓冲区写入到通道。

                NIO引入了选择器(Selectors)概念,选择器用于监听多个通道的事件(比如:连接打开、可读、可写),因此NIO可以通过一个线程监听多个数据通道。相比标准IO为每一个连接创建一个线程,NIO大大降低了线程创建的资源开销。

        9、序列化与反序列化

                序列化是指将对象的状态信息转换为可以存储或传输的形式的过程,通过序列化可以将对象的状态保存为字节数组,需要的时候再将字节数组反序列化为对象。

    3、多线程

        1、多线程的实现方式

                通常使用继承Thread类或实现Runnable接口

                还可以通过Callable接口实现

        2、线程的状态转换

                new 新建线程

                Runnable 可运行状态(执行start()方法,CPU决定是否运行)

                Blocking 阻塞状态(线程被阻塞于锁)

                Waiting 等待、计时等待(等待某些条件成熟)

                Stop 终止状态(线程运行结束)

        3、如何停止一个线程

                run方法代码执行完成

                线程运行时抛出一个未捕获的异常,跳出线程

                通过标志位跳出线程

                interrupt() 向需要中断的线程发送停止指令;isInterrupted() 线程检查自己的中断标志位;Thread.interrupted()将中断标志位复位为false;

                不安全方式

                Stop() 立刻停止线程,但不会释放线程运行所应用的资源

                Suspend() 立刻挂起线程,但不会释放线程运行锁应用的资源,容易造成死锁

        4、什么是线程安全

                当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。

        5、synchronized如何使用

                加锁

                可以修饰方法或代码块以同步的方式执行(同一时间只会有一个线程执行)

                类锁与实例锁本质上是两把锁,类锁锁的是每一个类的class对象。

        6、synchronized和Lock的区别

                synchronized是一个Java的关键字,Lock是一个接口;
                synchronized代码块执行完或线程抛出异常时结束线程,Lock必须显示调用释放锁的方法:unlock();
                synchronized修饰的锁其他线程在等待获取锁的阶段,会一直阻塞等待直到得到锁为止(不可中断锁);Lock有多种方式可以获取锁,不一定一直阻塞等待(可中断锁)。
                synchronized无法判断锁的状态,Lock可以判断;
                synchronized是非公平锁,而Lock可以设置为公平锁;
                Lock用法:
                lock()(阻塞线程等待获取锁)
                lockInterruptibly():可中断(阻塞线程等待获取锁,会响应中断)
                tryLock():尝试非阻塞的获取锁(非阻塞方式尝试获取锁,无法获取则返回false)
                unlock()
                公平锁与非公平锁:
                公平锁,先对锁发出获取请求的一定先获得锁。非公平锁则反之(性能更高)。
                ReentrantLock(boolean)可选择公平锁或非公平锁,默认使用非公平锁。
                锁的可重入:
                递归的时候发生锁的重入
                synchronized隐式支持锁的重入
                ReentrantLock的lock()支持锁的重入
                排它锁:同一时刻只有一个线程获取锁;
               读写锁:同一时刻运行多个读线程访问,但是只允许一个写线程,写锁会阻塞所有锁。(ReentrantReadWriteLock,相比synchronized速度更快)
                Condition接口有何作用?
                Condition接口与Lock配合,来实现等待通知机制。

        7、sleep和wait的区别

                sleep()是线程Thread的方法,而wait()是Object对象的方法。

                sleep()不会释放对象锁、wait()会释放对象锁

                sleep()可以在任何地方调用,wait()方法之可以在同步方法或同步块中使用。

                yield() 当前线程出让cpu占有权,当前线程变成可运行状态。

                wait()\notify()\notifyAll()

                调用以前,当前线程必须要持有锁,调用它们线程会释放锁,等待通知机制。

                notify() 唤醒一个线程(谨慎使用),具体唤醒哪个线程,由CPU决定。

                notifyAll() 所有在对象O上wait的线程全部唤醒(应用较多)

        8、死锁

                当一个锁未被释放,其他线程无法获取锁的时候,程序产生死锁情况。

         死锁的两种情况:

                 线程thread1先获取锁locka,然后在同步块里嵌套竞争锁lockb。而线程thread2先获取锁lockb,然后在同步块里嵌套竞争锁locka。

                Lock.unlock()方法的错误使用,导致死锁。

        9、Java线程池

                什么是线程池?用于管理线程的一个工具。

                线程池的作用?限制系统中执行线程的数量;降低资源的消耗、提高响应速度、提高线程的可管理性。

                为什么适应线程池?构建服务器应用程序的一个简单模型是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务。实际上对于原型开发这种方法工作得很好,但如果试图部署以这种方式运行的服务器应用程序,那么这种方法的严重不足就很明显。每个请求对应一个线程(thread-per-request)方法的不足之一是:为每个请求创建一个新线程的开销很大;为每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源要比花在处理实际的用户请求的时间和资源更多。
                除了创建和销毁线程的开销之外,活动的线程也消耗系统资源。在一个 JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目。
线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。

                Java常见的线程池

                Executors.newSingleThreadExecutor:单个线程的线程池;

                Executors.newFixedThreadExecutor:固定线程数量的线程池;

                Executors.newCacheThreadExecutor:可缓存线程;

                Executors.newScheduledThreadPool:创建一个定长线程池,支持定时和周期性的执行线程;

        10、并发工具类和并发容器类

                常用的并发工具类

                闭锁:CountDownLatch

                栅栏:CyclicBarrier

                信号量:Semaphore

                交换者:Exchanger

                CountDownLatch 闭锁允许一个线程或多个线程等待特定情况,同步完成线程中其他任务。

                CyclicBarrier和CountDownLatch都可以协同多个线程,让指定数量的线程等待期他所有的线程都满足某些条件之后才继续执行。CyclicBarrier可以重复使用(reset),而CountDownLatch只能够使用一次,如果还需要使用,必须重现new一个CountDownLatch对象。

                构造方法CyclicBarrier(int, Runnable) 所有线程达到屏障后,执行Runnable。

                Semaphore 型号量用来控制同时访问特定资源的线程数量。

                Exchanger 交换者用于在两个线程之间传输数据,被调用后等待另一个线程达到交换点,然后相互交互数据。

            常用的并发容器

                ConcurrentHashMap:JDK1.7实现:分段锁;JDK1.8实现:元素(key)锁+链表+红黑树

                SkipList:跳表自动随机维护一套索引,用于高效的索引List中的有序数据。

                ConcurrentSkipListMap:TreeMap的并发实现

                ConcurrentSkipListSet:TreeSet的并发实现

                ConcurrentLinkedQueue:LinkedList的并发实现

                CopyOnWriteArrayList:写时复制,在添加元素是,复制一个新的容器,在新容器中新增元素;读数据都在Old容器中操作,进行读写分离。数据一致性较弱,适合读多写少的场景。

                CopyOnWriteArraySet:同上

        11、volatile关键字

                在多个线程之间,访问同一个被volatile修饰的对象时,所有线程共享这个对象的值。

                但是volatile不是线程安全的(多个线程同时修改这个变量时,最终结果不一定是最后修改的那个值;可以保证线程的可见性,不可以保证操作的原子性)

二、Java虚拟机

    1、内存管理

        1、内存区域与内存溢出异常

名称特征作用配置参数异常
程序
计数器

占用内存小,线程私有,

生命周期与线程相同

大致为字节码行号指示器
虚拟机栈

线程私有,生命周期与线程

相同,使用连续的内存空间

Java 方法执行的内存模型,存储局部变量

表、操作栈、动态链接、方法出口等信息

-Xss

StackOverflowError

OutOfMemoryError

java

线程共享,生命周期与虚拟机相

同,可以不使用连续的内存地址

保存对象实例,所有对象实例(包括

数组)都要在堆上分配

-Xms 最小

-Xmx 最大

-Xmn 新生代

OutOfMemoryError
方法区线程共享,生命周期与虚拟机相
同,可以不使用连续的内存地址

存储已被虚拟机加载的类信息、常量、静

态变量、即时编译器编译后的代码等数据

-XX:PermSize:16M

-XX:MaxPermSize:64M

OutOfMemoryError

运行时
常量池

JDK1.6之前是方法区的一部分,

JDK1.7被移到堆中管理,具有动态性

存放字面

         直接内存并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常。

        2、垃圾收集器与内存分配策略

          垃圾收集算法:
                标记-清除算法、 复制算法、标记-整理算法、分代收集算法

                Serial Collecor、 ParNew收集器、Parallel Scavenge收集器、 Serial Old收集器、 Parallel Old收集器、CMS收集器、G1收集器


                对象的内存分配,往大方向讲,就是在堆上分配(但也可能经过JIT编译后被拆散为标量类型并间接地栈上分配),对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配。少数情况下也可能会直接分配在老年代中,分配的规则并不是百分之百固定的,其细节取决于当前使用的是哪一种垃圾收集器组合,还有虚拟机中与内存相关的参数的设置。

                接下来我们将会讲解几条最普遍的内存分配规则,并通过代码去验证这些规则。本节下面的代码在测试时使用Client模式虚拟机运行,没有手工指定收集器组合,换句话说,验证的是在使用Serial / Serial Old收集器下(ParNew / Serial Old收集器组合的规则也基本一致)的内存分配和回收的策略。读者不妨根据自己项目中使用的收集器写一些程序去验证一下使用其他几种收集器的内存分配策略。

    2、虚拟机执行子系统

        1、虚拟机类加载

                类加载的时机
            类从被夹在到虚拟机内存中开始,到卸载出内存位置,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载7个阶段。其中,验证、准备、解析3个部分统称为连接。


                类加载器

                对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。

                双亲委派模型的工作原理是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,自加载器才会尝试自己去加载。


        2、字节码执行

            略

       3、Java内存模型


三、流行框架与技术   

spring

Spring概述

1、Spring有哪些特点?

            Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。

2、使用Spring有什么好处?

            轻量:Spring 是轻量的,基本的版本大约2MB。
            控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
            面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
            容器:Spring 包含并管理应用中对象的生命周期和配置。
            MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
            事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
           异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。

3、Spring应用程序看起来像什么?

            一个定义了一些功能的接口。
            这实现包括属性,它的Setter , getter 方法和函数等。
            Spring AOP。
            Spring 的XML 配置文件。
            使用以上功能的客户端程序。

4、Spring核心容器模块是什么?

            应用上下文:这是基本的Spring模块,提供spring 框架的基础功能,BeanFactory 是 任何以spring为基础的应用的核心。Spring 框架建立在此模块之上,它使Spring成为一个容器。

5、为了降低Java开发的复杂性, Spring采取了哪几种策略

            基于POJO的轻量级和最小侵入性编程;
            通过依赖注入和面向接口实现松耦合;
            基于切面和惯例进行声明式编程;
            通过切面和模板减少样板式代码。

6、谈谈Spring框架几个主要部分组成

            Spring框架有七个模块组成组成,这7个模块(或组件)均可以单独存在,也可以与其它一个或多个模块联合使用,主要功能表现如下: 

            ☞ Spring 核心容器(Core):提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,她是工厂模式的实现。BeanFactory使用控制反转(Ioc)模式将应用程序的配置和依赖性规范与实际的应用代码程序分开。  

            ☞ Spring AOP:通过配置管理特性,Spring AOP模块直接面向方面的编程功能集成到了Spring框架中,所以可以很容易的使Spring框架管理的任何对象支持 AOP。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用Spring AOP,不用依赖于EJB组件,就可以将声明性事务管理集成到应用程序中。  

            ☞ Spring ORM:Spring框架集成了若干ORM框架,从而提供了ORM的对象关系工具,其中包括 JDO、Hibernate、iBatis和TopLink。所有这些都遵从Spring的通用事务和DAO异常层结构。  

            ☞ Spring DAO:JDBC DAO抽象层提供了有意义的异常层次的结构,可用该结构来管理异常处理和不同数据供应商抛出的异常错误信息。异常层次结构简化了错误处理,并且大大的降低 了需要编写的异常代码数量(例如,打开和关系连接)。Spring DAO的面向JDBC的异常遵从通用的DAO异常层结构。  

            ☞ Spring WEB:Web上下文模块建立在上下文模块(Context)的基础之上,为基于Web服务的应用程序提供了上下文的服务。所以Spring框架支持 Jakarta Struts的集成。Web模块还简化了处理多部分请求及将请求参数绑定到域对象的工作。              ☞ Spring上下文(Context):Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化校验和调度功能。  

            ☞ Spring MVC:Spring的MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的,MVC容纳的大量视图技术,包括JSP、Velocity、Tiles、iText和Pol 

SpringBean

1、说一下Spring中支持的bean作用域      

作用域描述
单例(singleton)(默认)每一个Spring IoC容器都拥有唯一的一个实例对象
原型(prototype)一个Bean定义,任意多个对象
请求(request)一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例。只在基于web的Spring ApplicationContext中可用
会话(session)限定一个Bean的作用域为HTTPsession的生命周期。同样,只有基于web的Spring ApplicationContext才能使用
全局会话(global session)限定一个Bean的作用域为全局HTTPSession的生命周期。通常用于门户网站场景,同样,只有基于web的Spring ApplicationContext可用
应用(application)限定一个Bean的作用域为ServletContext的生命周期。同样,只有基于web的Spring ApplicationContext可用

2、Spring框架中单例beans是线程安全的吗?为什么?

            Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。

              最浅显的解决办法就是将多态bean的作用域由“singleton变更为prototype

3、解释Spring框架中bean的生命周期

    Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;
    Spring上下文中的Bean也类似,如下
        1)实例化一个Bean--也就是我们常说的new;
        2)按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;
       3)如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
        4)如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
        5)如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
        6)如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
        7)如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
        8)如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法
    注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
        9)当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
        10)最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

4、哪些是最重要的bean生命周期方法?能重写它们吗?

        setBeanName() setBeanFactory() setApplicationContext()  postProcessBeforeInitialization()

5、Spring容器实例化Bean有多少种方法?分别是什么?

        1,调用默认的构造函数(默认)  2,使用静态工厂方法  3,使用实例工厂方法 

6、如何减少Spring XML的配置数量

        注解

7、什么是bean自动装配?并解释自动装配的各种模式?

        在spring中,对象无需自己查找或创建与其关联的其他对象,容器负责把需要相互协作的对象引用赋予各个对象。而创建对象之间协作关系的行为通常称为装配。

  1. 隐式Bean的发现机制和自动装配
  2. 显式装配:
      - 在Java中显式装配
      - 在XML中显式装配

8、自动装配有哪些好处和坏处?

        自动装配有助于减少甚至消除配置<property>元素和<constructor-arg>,减少XML的配置数量,当然不用写XML文件,我们自然要轻松地多。

9、是不是所有类型都能自动装配?如果不是请举例

10、什么是循环依赖?

        循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环。

11、Spring如何解决循环依赖?

      表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyIn CreationException异常表示循环依赖。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean.对于“prototype”作用域bean,Spring容器无法完成依赖注入,因为Spring容器不进行缓存“prototype”作用域的bean,因此无法提前暴露一个创建中的bean。

SpringMVC

1、SpringMVC的工作流程和原理是什么?

      1)首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
        2)DispatcherServlet——>HandlerMapping, HandlerMapping 将会把请求映射为HandlerExecutionChain 对象(包含一个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
        3)DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
        4)HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);
        5)ModelAndView的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
        6)View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
    7)返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。      

2、SpringMVC与Struts2的主要区别?

        1)springmvc基于方法开发的,struts2基于类开发的。
        2)单例和多例的区别:springmvc在映射的时候,通过形参来接收参数的,是将url和controller方法映射,映射成功后,springmvc生成一个handlers对象,对象中只包括一个method,方法执行结束的时候,形参的数据就销毁,
所以springmvc可以进行单例开发,并且建议使用。
但是structs接收的参数是通过类的成员变量来接收的,这些变量在多线程访问中,是共享的,而不是像springmvc那样,方法结束之后,形参自动销毁,且无法使用单例,只能使用多例。
这样的话,在structs中,随着方法的添加,很多的成员变量,维护到最后的时候根本就不知道这个成员变量被哪个方式所使用,所以springmvc开发类似于service开发。
        3)经过实际测试,structs速度慢,在与使用structs标签,如果使用structs建议使用jstl。

3、SpringMVC的控制器是不是单例模式,如果是有什么问题,怎么解决

        

Spring注解

1、Spring注解的基本概念和原理

2、举例说明什么是Spring基于Java的配置?

3、什么是基于注解的容器配置?

4、@Autowired@Resource @Inject 的区别

Spring AOP

1、什么是AOP,有什么作用,能应用在什么场景?

2、什么是织入,织入的时机是什么

3、什么是切入点,关注点,连接点

4、Spring提供了几种AOP支持?

Spring JDBC

1、举例说明什么是事物以及其特点

2、Java EE事务类型有哪些?应用场景是什么?Spring是如何实现的?

3、Spring有几个事物隔离级别,分别详述

4、描述下SpringJDBC的架构

5、描述下Spring事务处理类及其作用

6、Spring提供几种事物实现?分别是什么?各有什么优缺点?

7、JdbcTemplate有哪些主要方法

8、JdbcTemplate支持哪些回调类

mybatis

1、什么是MyBatis?简述MyBatis的体系结构

2、列举MyBatis的常用API及方法

3、对于Hibernate和MyBatis的区别与利弊,谈谈你的看法

4、#{}和${}的区别是什么?

5、Mybatis是如何进行分页的?分页插件的原理是什么?

6、简述Mybatis的插件运行原理,以及如何编写一个插件

7、Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理

8、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

9、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?

10、Mybatis都有哪些Executor执行器?它们之间的区别是什么?

11、Mybatis是否可以映射Enum枚举类?

12、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?

13、Mybatis能否执行一对一、一对多关联查询?都有哪些实现方式,它们之间有什么区别

14、什么是MyBatis的接口绑定,有什么好处

15、iBatis和MyBatis在细节上的不同有哪些

16、讲下MyBatis的缓存


四、分布式服务    

SpringCloud

1、微服务是如何保护自己的

        一种方法是构建一个单点登录(SSO)网关   另一种方法是用HMAC(基于哈希的消息代码)(密钥服务如OAuth或SAML)

        现在已经知道如何保护应用程序了,是时候关注容器的安全了。Docker是一个广泛使用的容器,保护Docker安全的一个有用的工具是Calico。每个Docker网络都有Calico配置文件,必须设置规则和策略以控制流量。

2、客户端与服务端负载均衡区别

         服务器端负载均衡:例如Nginx,通过Nginx进行负载均衡,先发送请求,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;

        客户端负载均衡:例如spring cloud中的ribbon,客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡;

         客户端负载均衡和服务端负载均衡最大的区别在于服务清单所存储的位置。在客户端负载均衡中,所有的客户端节点都有一份自己要访问的服务端清单,这些清单统统都是从Eureka服务注册中心获取的。

3、路由网关原理

        Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。

        当@EnableZuulProxy与SpringBoot Actuator配合使用时,Zuul会暴露一个路由管理端点/routes。借助这个端点,可以方便、直观地查看以及管理Zuul的路由。

        /routes端点的使用非常简单,使用GET方法访问该端点,即可返回Zuul当前映射的路由列表;使用POST方法访问该端点就会强制刷新Zuul当前映射的路由列表(尽管路由会自动刷新,Spring Cloud依然提供了强制立即刷新的方式)。

4、如何解决微服务多配置问题

       高可用的分布式配置中心(Spring Cloud Config)

5、各服务之间如何调用

6、注册中心工作原理

7、如何保证服务健康的情况

SpringBoot

1、与SpringMVC差异化在哪

2、为什么说Spring是一个容器

3、常用注解@Required @Autowired @Qualifier @Controller @RequestMapping

4、谈谈对AOP的理解

5、怎样开启注解装配

6、描述模板JdbcTemplate  RestTemplate

7、Spring支持的事务管理类型

8、Spring框架的事务管理有哪些优点

9、Spring BootStarter内容及工作原理

Dubbo

1、什么是RPC框架

2、序列化方式及作用

3、如果注册中心集群都挂掉,发布者和订阅者之间还能通信么?

4、dubbo连接注册中心和直连的区别

5、dubbo底层协议

6、dubbo注册中心如何设置

7、dubbo负载均衡的理解

8、dubbo服务的容错机制

9、服务调用超时的实现原理是什么?

10、描述服务注册与发现流程怎样实现

11、服务提供者能实现失效踢出是什么原理

五、数据库与Nosql

mysql

1、各个数据库引擎区别

2、提高sql语句的技巧(sql优化)

3、怎么样做执行计划分析

4、创建索引的注意事项

5、sql语句场景

6、怎么样做mysql的高可用(读写分离、分库分表、集群)

mongoDB

1、与mysql区别

2、nosql的应用场景

3、mongodb的索引注意事项

4、怎么样做mongodb查询优化

5、常用命令考察

6、mongodb是怎么实现高可用?(复制、分片)

redis

1、结合项目经验,说下redis应用场景

     是一个完全开源免费的key-value内存数据库,通常被认为是一个数据结构服务器,主要是因为其有着丰富的数据结构 strings、map、 list、sets、 sorted sets
        通常局限点来说,Redis也以消息队列的形式存在,作为内嵌的List存在,满足实时的高并发需求。而通常在一个电商类型的数据处理过程之中,有关商品,热销,推荐排序的队列,通常存放在Redis之中,期间也包扩Storm对于Redis列表的读取和更新。

2、redis支持数据类型?各有什么特点?

        Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

3、有什么持久化策略?各有什么特点

                2

               rdb:快照形式是直接把内存中的数据保存到一个dump文件中,定时保存,保存策略

     默认情况下,是快照rdb的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是dump.rdb

               aof:把所有的对redis的服务器进行修改的命令都存到一个文件里,命令的集合,每一个写命令都通过write函数追加到appendonly.aof.

4、redis如何事务支持?与一般意义上的事务有何区别

        事务必须满足ACID原则(原子性、一致性、隔离性和持久性)。

MULTI用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才会被原子的执行。
EXEC执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了WATCH命令,那么只有当WATCH所监控的Keys没有被修改的前提下,EXEC命令才能执行事务队列中的所有命令,否则EXEC将放弃当前事务中的所有命令。
DISCARD回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果WATCH命令被使用,该命令将UNWATCH所有的Keys。
WATCH key [key ...]在MULTI命令执行之前,可以指定待监控的Keys,然而在执行EXEC之前,如果被监控的Keys发生修改,EXEC将放弃执行该事务队列中的所有命令。
UNWATCH取消当前事务中指定监控的Keys,如果执行了EXEC或DISCARD命令,则无需再手工执行该命令了,因为在此之后,事务中所有被监控的Keys都将自动取消。
         三个阶段: 
        1. 开启:以MULTI开始一个事务 
        2. 入队:将多个命令入队到事务中,找到这些命令并不会立即执行,而是放到等待执行事务队列里面 
        3. 执行:由EXEC命令触发事务 
        三个特性:单独的隔离操作:事务的所有命令都会序列化、按顺序地实行 
        没有隔离级别的概念:事务提交前任何指令都不会被实际执行 
        不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,不回滚

5、介绍下哨兵机制

         有了主从复制的实现以后,如果想对主服务器进行监控,那么在redis2.6以后提供了一个"哨兵"的机制。顾名思义,哨兵的含义就是监控Redis系统的运行状态。可以启动多个哨兵,去监控Redis数据库的运行状态。其主要功能有两点:
         1)监控主数据库和从数据库是否正常运行。
         2)主数据库出现故障时,可以自动将从数据库转换为主数据库,实现自动切换。

6、介绍redis集群方案?以及其原理

        

            每一个节点都存有这个集群所有主节点以及从节点的信息。它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。如果某个节点和所有从节点全部挂掉,我们集群就进入faill状态。还有就是如果有一半以上的主节点宕机,那么我们集群同样进入发力了状态。这就是我们的redis的投票机制

7、redis能做读写分离吗?同步策略是怎么实现的?

        redis是内存数据库,不存在IO瓶颈,读写都很快

        主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

8、与memcached区别

        redis与memcached相比,不仅支持简单的key-value数据类型,同时还提供list,set,zset,hash等数据结构的存储;redis支持数据的备份,即master-slave模式的数据备份;redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用等等, memcached是多线程,非阻塞IO复用的网络模型,redis使用单线程的IO复用模型,自己封装了一个简单的AeEvent事件处理框架

        详见:http://blog.csdn.net/u010775025/article/details/79400922

六、算法与数据结构   

数据结构

1、队列

            队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作。
            LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。

2、堆栈

            在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构。堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。在单片机应用中,堆栈是个特殊的存储区,主要功能是暂时存放数据和地址,通常用来保护断点和现场。要点:堆,队列优先,先进先出(FIFO—first in first out)[1]  。栈,先进后出(FILO—First-In/Last-Out)。

            堆栈是一个在计算机科学中经常使用的抽象数据类型。堆栈中的物体具有一个特性: 最后一个放入堆栈中的物体总是被最先拿出来, 这个特性通常称为后进先出(LIFO)队列。 堆栈中定义了一些操作。 两个最重要的是PUSH和POP。 PUSH操作在堆栈的顶部加入一 个元素。POP操作相反, 在堆栈顶部移去一个元素, 并将堆栈的大小减一

3、链表

            链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

     链表,队列,堆栈的区别
        1、栈是个有底的口袋,像袜子。
                队列是没底的口袋,像通心粉。
                所以:栈的特点是先进后出,队列的特点是先进先出。
        2、主要区别是适用的地方不一样,   
              链表实际上可以认为是一种数据的物理组织形式,是用指针或对象的引用组织起的一种数据的存储方式.   
              队列和堆栈是一个更高层次的概念,其底层可以是用链表也可以是用数组来实现.   
              队列和堆栈的主要区别是进出的顺序不一样,   
              队列是先进先出,堆栈是后进先出.   
        3、cooled(经典中--经过非典中)   说的很详细了,我补充一下   
              队列和堆栈是一种特殊的数据组织形式。   
              可以把他们看成是一系列的集合。   
              队列可以看成是有2个口的集合一个口叫队头一个叫队尾,只能在对头进行删除操作,在队尾做插入。根据这样的操作。队列特点是先进先出   
              堆栈可以看成是有1个口的集合,这个口叫栈顶。插入和删除操作只能在栈顶操作。根据这样的操作。堆栈的特点是是后进先出.   
              链表是一种存储方式,它可以在非连续的内存空间里面存储一个集合的元素。和它对应的是数组,数组要在连续的空间里存储集合的元素

4、树(二叉树、B+树、哈夫曼树)


算法

1、广度优先、深度优先(图)

2、常见排序算法(时间复杂、空间复杂)(冒泡、选择、插入、希尔、归并、快排、堆排、桶排)

3、常见查找算法(时间复杂、空间复杂)

4、hash原理 hashmap内部实现


七、通讯协议

TCP/IP

1、解释TCP长连接和短连接

2、Java如何实现Socket长连接和短连接

3、TCP与UDP的区别

4、TCP的三次握手与四次挥手过程,各个状态名称与含义,TIMEWAIT的作用

5、电脑上访问一个网页,整个过程是怎么样的:如浏览器、网络(UDP,TCP,HTTP等),以及服务器等各种参数与对象上由此引发的一系列活动。请尽可能的涉及到所有的关键技术点。

Http

1、解释与说明HTTP协议的几个重要概念

2、Http的报文结构

3、Get/Post 以及幂等性

4、Http怎么处理长连接

5、Http Request的几种类型

6、Http几个版本,版本间有什么区别

7、如果客户端不断的发送请求连接会怎样


    注:如有什么遗漏的请在留言区给予指出、后续会继续完善相关得知识。




  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值