常见JAVA面试题

JAVA类集

  • 类集是JAVA实现的数据结构应用,如果只是一个使用,那么类集的操作非常简单,类集的核心接口:List、Set、Map、Iterator、Enumeration

  • List子接口:可以根据索引号取得内容

    而在List集合里面最容易问到的问题:ArrayList(包装了数组的集合,比较常用,数组是可变的)、LinkedList(链表的实现,搜索数据的时间复杂度为:n)的区别

  • Set子接口:排序子类、HashSet与HashCode()和equals的关系

    • HashSet:重复的判断依靠的是HashCode()和equals(),但是她是无序的
    • TreeSet:是有序的,依靠Comparable排序
    • LinkedHashSet:继承了HashSet的特点,但是属于有序(增加顺序为保存顺序)
  • Map接口:Map.Entry、Iterator输出、HashMap、WeakHashMap(弱引用)

字符串哈西相等,equals相等吗?反过来呢?

  • HashCode()相同,那么equals()一定相同,反过来也是一样

Spring的工作原理,控制反转是怎么实现的,自己写过滤编码怎么实现

  • Spring的核心组成:IOC&DI(工厂设计)、AOP(代理设计、动态代理);

    • Spring之中针对于XML带带解析处理采用的是DOM4J的实现
    • Anntation的时候必须要求有一个容器
  • 对于编码过滤需要考虑两种情况

    • Struts 1.x、Spring MVC、JSP+Serlet:都可以直接通过过滤器完成
    • Struts 2.x:必须通过拦截器完成
    • 实现:考虑到可扩展性的配置,所以在配置文件里面设置编码,在程序运行的时候动态取得设置的编码进行操作,但是需要设置两个操作:请求编码、回应编码

框架源代码有没有看过

  • 框架的核心思想:反射 + XML(Annotation)
    • Struts 2.x的设计:请求交由过滤器执行,而后过滤器交给控制器完成(Action),后面由于将跳转路径等信息都写在了配置文件或者是Annotation里面,所以还需要进行这部分内容的加载
    • Spring MVC:他是基于方法的请求处理,所有的参数都提交到方法上,本质上还是一个DisoatcherServlet
    • Hibernate:就是反射和DOM解析处理流程

动态代理

  • 直接使用InvocationHandler接口进行实现,同时利用Proxy类设置动态请求对象
  • 使用CGLIB来避免对于“代理设计模式需要使用接口实现”的限制

action是单实例还是多实例

  • Struts 2.x和Spring MVC中的Action都是多实例
  • Struts 1.x的Action是单实例
  • Struts 2.x和Spring MVC的是否单实例可以控制,只要交由Spring管理的Action类,都可以通过 ”@scop = " prototye " "来进行控制

怎么配置bean

  • 这样的配置主要是在Spring里面,重点由xml和annotation的扫描负责:
    • xml中直接使用“< bean >”,这样在Spring容器启动的时候就可以通过容器进行初始化
    • Annotation必须设置context命名空间,而后进行扫描包的配置

修改单实例多实例

  • ”@scop = " prototye " "来进行控制

JAVA的设计模式

  • 工厂设计模式、代理设计模式、单例设计模式(Runtime)、合成设计模式、门面设计模式(JDBC)、装饰设计模式(PrintStream、PrintWriter)、模板设计模式(Servlet)

事务的控制

  • MySQL数据库如果要使用事务,必须使用 ” type = innodb“ 这个数据引擎
  • 事务的核心控制:commit、rollback
  • 在Spring里面,利用AspectJ可以设置AOP的切面,而后进行声明式事务控制

脏读、幻读、不可读

  • 脏读:是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据

  • 幻读:指当事务不是独立执行时发生的一种现象

    例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改时向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就像产生了幻觉

  • 不可重复读:指在一个事务内,多次读同一个数据。在这个事务还没有结束时,另外一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,此时第一个事务两次读到的数据是不一样的,因此称为是不可重复读

事务的传播属性

  • PROPAGATION REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务
  • PROPAGATION NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动的事务,则按TransactionDefinition.PROPAGATION_REQUIRED属性执行

购物车是如何实现的

  • 购物车的实现可以基于:

    • Session:浏览器关闭后消失
    • Cookie:数据保存在本地,如果切换到手机上无效
    • 数据库:在不同的终端上持续操作
  • 你的实现:Ajax处理操作,处理购物车的应用,考虑到用户如果多的情况,并且访问量频繁,要单独设计一个购物车的子系统模块

统计一天的订单量

  • 如果一天的订单预估1W条,随便折腾
  • 如果订单量很大不可使用COUNT()和WHERE
    • 分时统计,如果系统设计到位,可以单独配置一个文件进行计数(需要考虑同步,一同步就慢),不应该出现在抢购环节内

IN HAVING exsit

  • IN:是判断具体的几项数据
  • HAVING:是针对于分组后的数据的筛选,依然要使用统计函数处理
  • EXISTS:只是需要判断子查询里面是否有数据

有没有使用过定时任务

  • JAVA本身提供有定时任务:TimeTask,Timer,但是此类操作对于定时很难完成,他只能够做频率,但是这个频率不准,所以在定时开发中会使用quartz组件,而且Spring里面也提供有自己的定时实现,这个实现的好处是可以在准确的时间上进行触发

JVM的内存管理

  • 内存分为:栈(JAVA虚拟机栈),堆,程序计数器(类似于寄存器),方法区,本地方法栈
  • 所谓的垃圾处理操作指的是堆内存:年轻代,老年代,永生代(JDK1.8移除),会涉及到JVM的内存调优问题

堆内存、栈内存溢出

  • 栈溢出:栈帧,所有的方法调用都是通过栈帧的形式控制的。栈如果保存的数据过多则会产生栈溢出,如果在堆内存中产生的数据量过大,那么就有可能出现 “OutOfMemoryError” 错误

说一下缓存

  • 缓存的主要目的是提高查询的效率,常见的两种缓存组件:EhCache(数据库)、OSCache(页面),除了这样的操作之外还有缓存的数据库redis、memcached,其中redis可以将数据保存到磁盘上,并且支持的数据类型要多于memcached,这种redis的数据库每秒并发的访问量可以达到15W次

统计所有的重名用户

  • 考虑数据量问题,如果数据量大,考虑使用位图索引,如果分组量小就直接分组即可

面向对象的特征有哪些方面

  • 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面,抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么

  • 继承:继承是从已有类得到继承信息创建新类的过程

  • 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口

  • 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应,简单的来说就是用同样的对象引用调用同样的方法但是做了不同的事情。实现多态需要做两件事情:1.方法重写(子类继承父类并重写父类中的方法);2.对象造型(用父类型引用子类对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)

String是否为基本数据类型

  • 不是,八大基本数据类型(byte,short,int,long,float,double,char,boolean);除了基本数据类型和枚举类型,剩下的都是引用类型
  • 枚举类型:
    • 枚举类型都隐式继承了java.lang.Enum类,因此不能继承其他类,但可以实现接口
    • 枚举类型只能有私有构造方法(java运行时创建,外部不能进行实例化)
    • 不能泛型化
    • 当有字段和方法时,枚举常量的列表必须以分号结尾

int和Intrger有什么区别

  • JAVA是一个近乎纯净的面向对象的编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,JAVA为每一个基本数据类型都引入了对应的包装类型,int的包装类就是Integer,从JAVA 5开始引入了自动装箱和拆箱机制,使二者可以互换

&和&&的区别

  • 虽然二者都要求运算符左右两侧的布尔值都是true整个表达式才是true,&&之所以称为短路运算是因为,如果&&左边的表达式是false,右边的表达式就会直接短路,不进行运算

进程和线程有什么区别

  • 根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
  • 再开销方面:每个进程都有独立的代码和数据空间,程序之间的切换会有较大的开销;线程可以看作是轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC)线程之间切换的开销小
  • 所处环境:在操作系统中能够同时运行多个进程;而在同一个进程中有多个线程同时执行
  • 内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源
  • 包含关系:只有一个线程的进程可以看作是单线程,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线程共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程

解释内存中的栈(stack)、堆(heap)、静态区(static area)的用法

  • 栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间
  • String str = new String(“hello”);
  • 上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而hello这个自变量放在静态区

switch是否能作用在byte上,是否能作用在long上,是否能作用在String上?

  • expr可以是byte、short、char、int、enum、String类型,但是long类型不能

数组有没有length()方法?String有没有length()方法?

  • 数组没有length()方法,有length的属性,String有length()方法。JavaScript中,获得字符串的长度是通过length属性得到的,这一点容易和JAVA混淆

构造器(constructor)是否可被重写(override)?

  • 构造器不能被继承,因此不能被重写,但可以被重载

两个对象值相同(x.equals(y) = true),但却可以有不同的hash code 这句话对不对?

  • 不对,如果两个对象x和y满足x.equals(y) = true,他们的哈希码应当相同。**JAVA对于equals方法和hash code方法是这样规定的:1.如果两个对象相同(equals方法返回true),那么他们的hashcode值一定要相同;2.如果两个对象的hashcode相同,他们并不一定相同

当一个对象被当作参数传递到一个方法后,此方法可以改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

  • 值传递,JAVA语言的方法调用只支持参数的值传递,当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对于对象引用的改变是不会影响到调用者的

String和StringBuilder、StringBuffer的区别

  • JAVA平台提供了两种类型的字符串:String和StringBuffer/StringBuilder,他们可以存储和操作字符串,其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBulider类表示的字符串对象可以直接进行修改
  • StringBuffer和StringBuilder的方法完全相同,区别在于StringBuilder是在单线程环境下使用,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer要高

重载(Overload)和重写(Override)区别,重载的方法能否根据返回类型进行区分

  • 方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回值类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回值类型没有特殊的要求

描述一下JVM加载class文件的原理机制

  • JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,JAV中的类加载器是一个重要的JAVA运行时系统组件,它负责在运行时查找和装入类文件中的类。类的加载是指把类的.calss文件中的数据读入到内存中,通常时创建一个字节数组读入.calss文件

抽象类(abstract calss)和接口(interface)有什么异同

  • 抽象类和接口都不能够实例化,但是可以定义抽象类和接口类型的引用,一个类如果继承了某一个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类,接口比抽象类更加抽象,

数据类型之间的转换

  • 如何将字符串转换为基本数据类型
    • 调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型
  • 如何将基本数据类型转换为字符串
    • 一种方法是将基本数据类型与空字符串(“ ”)连接(+)即可获得对应的字符串;另一种方法是调用String类中的valueOf()方法返回相应字符串

如何实现字符串的反转及替换

  • 可以使用String或StringBuffer/StringBuilder中的方法

抽象类和接口的区别

  • 抽象类可以由构造方法,接口中不能由构造方法
  • 抽象类中可以有普通成员变量,接口中没有普通成员变量
  • 抽象类中可以包含非抽象类的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法
  • 抽象类中的抽象方法的访问类型可以是public,protected,但接口中的抽象方法只能是pubilc类型的,并且默认即为pulic abstract类型
  • 抽象类中可以包含静态方法,接口中不能包含静态方法
  • 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static fainal类型,并且默认即为public static final类型
  • 一个类可以实现多个接口,但是只能继承一个抽象类

普通类和抽象类的区别

  • 普通类:不含抽象方法,可以直接实例化
  • 抽象类:包含抽象方法,不能直接实例化

List、Set、Msp是否继承自Collection接口

  • List、Set是、Map不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素,List是线性结构的容器,适用于按数值索引访问元素的情形

List、Set、Msp三个接口存取元素时,各有什么特点

  • List以特定索引来存取元素,可以有重复元素,Set不能存储重复元素(用对象的equals()方法来区分元素是否重复),Map保存键值对(key - value pair)映射,映射关系可以是一对一或者是多对一

List、Set、Map的各自特征及使用场景

java中的集合分为单例集合Collection和双列集合Map

List(有序,可重复)

  • ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高
  • Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低
  • LinkedList:底层数据结构是链表,查询慢,增删块,线程不安全,效率高

Set(无序,唯一)

  • HashSet:底层结构是哈希表
    • LinkedHashSet:底层数据由链表和哈希表组成,由链表保证元素有序,由哈希表保证元素唯一
  • TreeSet:底层数据结构是红黑树(是一种自平衡的二叉树)根据比较的返回值是否是0来决定保证元素唯一性。
    • 两种排列方式
      • 自然排序(元素具备比较性):让元素所属的类实现Comparable接口
      • 比较器排序(集合具备比较性):让集合接收一个Comparator的实现类对象

Map(双列集合)

Map集合的数据结构仅仅针对键有效,与值无关。存储的是键值对形式的元素,键唯一,值可重复

  • HashMap:底层数据结构是哈希表,线程不安全,效率高

    哈希表依赖两个方法:hashCode()和equals()

    执行顺序:

    首先判断hashCode()值是否相等

    ​ 是:继续执行equals(),看其返回值

    ​ ture:说明元素重复,不添加

    ​ false:直接添加到集合

    ​ 否:直接添加到集合

    最终:自动生成hashCode()和equals()

    • LinkHashMap:底层数据结构由链表和哈希表组成,由链表保证元素有序,由哈希表保证元素唯一
  • Hashtable:底层数据结构是哈希表,线程安全,效率低

    哈希表依赖两个方法:hashCode()和equals()

    执行顺序:

    首先判断hashCode()值是否相等

    ​ 是:继续执行equals(),看其返回值

    ​ ture:说明元素重复,不添加

    ​ false:直接添加到集合

    ​ 否:直接添加到集合

    最终:自动生成hashCode()和equals()

  • TreeMap:底层数据结构是红黑树(是一种自平衡的二叉树)根据比较的返回值是否是0来决定保证元素唯一性。

    • 两种排列方式
      • 自然排序(元素具备比较性):让元素所属的类实现Comparable接口
      • 比较器排序(集合具备比较性):让集合接收一个Comparator的实现类对象

Collection和Collections的区别

  • Collection是一个接口,他是Set、List等容器的父类接口;Collections是一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等

Tread类的sleep()方法和对象的wait()方法都可以让线程停止执行,他们有什么区别

  • sleep()方法(休眠)是线程类(Tread)的静态方法,调用此方法会让当前进程暂停执行指定的时间,将执行机会CPU让给其他进程,但是对象的锁依然保持,休眠时间结束后会自动恢复
  • wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法或者notifyAll()方法时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态

线程的sleep()方法和yield()方法有什么区别

  • sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会
  • 线程执行sleep()方法后转入拥塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态
  • sleep()方法声明抛出InterruotedException,而yield()方法没有声明任何异常
  • sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性

当一个线程进入一个对象的synchronized方法A之后,其他线程是否可以进入此对象的synchronized方法B

不能,其他线程只能访问该对象的非同步方法,同步方法不能进入,因为非静态方法让sunchroized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池)中等待对象

synchronized关键字的用法

  • synchronized关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用synchronized(对象){…}定义同步代码块,或者在声明方法时将synchronized作为方法的修饰符

简述synchronized和java.util.concurrent.locks.Lock的异同

  • Lock时JAVA 5以后引入的新的API,和关键字synchronized相比主要相同点:Lock能完成sychronized所实现的所有功能;主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally块中释放(这是释放外部资源的最好的地方)

请说出与线程同步以及线程调度相关的方法

  • wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁
  • sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常
  • notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关
  • notifyAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让他们竞争,只有获得锁的进程才能进入就绪状态

编写多线程程序有几种实现方式

  • 分别是继承Thread类和实现Runnable接口,两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为JAVA的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,所以使用Runnable接口更为灵活

事务的ACID是指什么

  • 原子性(Atomic):事务中的各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败
  • 一致性(Consistent):事务结束后系统状态是一致的
  • 隔离性(Ioslated):开发执行的事务彼此无法看到对方的中间状态
  • 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据

获得一个类的类对象有哪些方式

  • 方法1:类型.calss,例如:String.class
  • 方法2:对象.getClass(),例如:“hello”.getClass()
  • 方法3:Class.forName(),例如:Class.forName(“java.lang.String”)

JAVA中会存在内存泄漏吗?

  • 理论上JAVA有垃圾回收机制(GC)不会存在内存泄漏问题,然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此会导致内存泄漏的发生。例如:hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄漏

接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)

  • 接口可以继承接口,而且支持多重继承,抽象类可以实现(implements)接口,抽象类可继承具体类也可继承抽象类

JAVA中final关键字有哪些用法

  • 修饰类:表示该类不能被继承
  • 修饰方法:表示方法不能被重写
  • 修饰变量:表示变量只能一次赋值以后不能被修改(常量)

比较一下JAVA和JavaSciprt

  • JAVA是静态语言,JS是动态语言
  • 基于对象和面向对象:JAVA是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JAVASciprt是一种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件,他是一种基于对象和事件驱动的编程语言
  • 解释和编译:JAVA的源代码在执行前,必须经过编译。JAVASciprt是一种解释性编译语言,其源代码不需要经过编译,由浏览器执行
  • 强类型变量和弱类型变量:JAVA采用强类型变量检查,即所有变量在编译之前必须做声明;JAVASciprt中变量是弱类型的,甚至在使用变量前可以不做声明,JAVASciprt的解释器在运行时检查推断其数据类型

try{}里面有个return语,那么紧跟在这个try后面的finally{}里的代码会不会被执行,什么时候执行,在return前还是后

  • 会执行,在方法返回调用者前执行

常见的运行错误

  • ArithmeticException(算术异常)
  • ClassCastException(类转换异常)
  • IllegalArgumentException(非法参数异常)
  • IndexOutOfBoundsException(下标越界异常)
  • NullPointerException(空指针异常)
  • SecurityException(安全异常)

面向对象的“六原则一法则”

  • 单一职责原则:一个类只做它该做的事(单一职责原则就是“高内聚”,写代码最终的原则只有六个字“高内聚、低耦合”)
  • 开闭原则:软件实体应当对扩展开放,对修改关闭(做到开闭原则的两个要点:1.抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;2.封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂)
  • 依赖倒转原则:面向接口编程
  • 里氏代换原则:任何时候都可以用子类型替换掉父类型
  • 接口隔离原则:接口要小而专,绝不能大而全(一个接口应该描述一种能力,接口也应该是高度内聚的)
  • 合成聚合复用原则:优先使用聚合或合成关系复用代码
  • 迪米特法则:又叫最少知识原则,一个对象应对对其他对象有尽可能少的了解(简单的来说就是如何做到低耦合)

设计模式

设计模式就是一套被反复使用的代码设计经验的总结,使用模式是为了可重用代码,让代码更容易被他人理解、保证代码可靠性

  • 工厂模式:工厂可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但这些方法针对不同的数据进行不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例
  • 代理模式:给一个对象提供一个代理对象,并由对象代理控制原对象的引用
  • 适配器模式:把一个类的接口换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用发类能够一起工作
  • 单例模式:一个类只有一个实例,即一给类只有一个对象实例
    • 懒汉式单例模式,线程不安全,致命的是在多线程不能正常工作
    • 饿汉式单例模式,避免了多线程的同步问题

Servlet的运行过程

  • Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的servlet()方法,servlet()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法

转发(forward)和重定向(redirect)的区别

  • forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再转发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此从浏览器的地址栏中可以看到跳转后的链接地址,很明显redirect无法访问到服务器保护起来资源,但是可以从一个网站redirect到其他网站。forward更加高效,所以在满足需要时尽量使用forward(通过RequestDispatcher对象的forward方法,该对象可以通过ServletRequest对象的getRequestDispatcher()方法获得) ,并且这样也有助于隐藏实际的链接;在有些情况下,比如要访问一个其他服务器上的资源,则必须使用重定向(通过HttpServletResponse对对象调用其sendRedirect()方法实现)

JSP有哪些内置对象,作用分别是什么

  • JSP有9个内置对象
  • request:封装客户端的请求,其中包含来自GET或POST请求的参数
  • response:封装服务器对客户端的响应
  • pageContext:通过该对象可以获取其他对象
  • session:封装用户会话的对象
  • application:封装服务器运行环境的对象
  • out:输出服务器响应的输出对象
  • config:Web应用的配置对象
  • page:JSP页面本身(相当于JAVA程序中的this)
  • exception:封装页面抛出异常的对象

讲解JSP中的四种作用域

  • page:代表与一个页面相关的对象和属性
  • request:代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件;需要在页面显示的临时数据可以置于此作用域
  • session:代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户组件的session中
  • application:代表与整个Web应用程序相关的对象和属性,它实质上是跨越整个Web应用程序,包括多个页面、请求和会话的一个全作用域

Spring注解

  1. @Controller
    • 用于标记在一个类上,声明注解的类是一个Controller,将该类交给Spring容器进行管理,可以使Controller定义更加灵活,可以不用实现Controller接口,请求处理的方法也更加灵活
    • 分发处理器将会扫描使用了该注解类的方法,并检测该方法是否使用了@RequestMapping注解。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是真正处理请求的处理器
    • 单单使用@Controller标记在一个类上还不能定义真正意义上的说他是SpringMVC的一个控制器类,因为这个时候Spring还不认识它。这个时候就需要我们把控制器类交给Spring来管理。
    • 有两种方法将该类交给Spring管理:
      • 第一种是在SpringMVC的配置文件中定义MyController的bean对象(< bean class=“com.host.app.web.controller.MyController”/>
      • 第二种是在SpringMVC配的配置文件中告诉Spring改到那里去找标记为@Controller的Controller控制器(<context:component-scan base-package = “com.host.app.web.controller”/>

什么是跨域?如何解决?

  • 跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制

    同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域

  • 如何解决跨域:首先我们用nginx作为代理服务器和用户交互,这样用户就只需要在80端口上进行交互,这样就避免了跨域问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值