2020年面试题

数据库

为什么使用存储过程?与在应用中使用SQL语句有什么不同?

  1. 存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度
  2. 当对数据库进行复杂操作时(如对多个表进Update,Insert,Query,Delete
    时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。这些操作,如果用程序来完成,就变成了一条条的 SQL
    语句,可能要多次连接数据库。而换成存储,只需要连接一次数据库就可以了
  3. 存储过程可以重复使用,可减少数据库开发人员的工作量
  4. 使用存储过程也能很好的防止SQL注入,数据库结构也不容易暴露
  5. 在首次运行一个存储过程时,查询优化器对其进行分析、优化,并给出最终被存在系统表中的存储计划,这样,在执行过程时便可节省此开销,提高效率
  6. 数据库专业人员可以随时对存储过程进行修改,但对应用程序源代码却毫无影响,从而极大的提高了程序的可移植性

使用存储过程有什么不好?

  1. 存储过程需要专门的数据库开发人员进行维护,但实际情况是,往往由程序开发员人员兼职,需求的增加会导致数据结构的变得复杂,维护成本高
  2. 设计逻辑变更,修改存储过程不如SQL语句灵活

什么场景下使用存储过程?

  1. 在一些高效率或者规范性要求比较高的项目,建议采用存储过程
  2. 对于一些算法要求比较高,涉及多条数据逻辑,建议采用存储过程

如何优化SQL语句?

  1. 在大批量查询数据的表中,针对查询频繁的列加索引
  2. 查询的列尽量精确,避免使用select *
  3. 在查询条件中尽量避免使用in 和not in,or,like, is null, 1=1, 它们会导致数据库引擎放弃索引进行全表扫描

索引为什么能提高效率?

没有建立表索引的数据在数据库中的存放是杂乱无序的,每次查询都要进行全表扫描,当表中的数据量大时,效率非常低下。如果建立索引,索引就是通过事先排好序,从而在查找时可以应用二分查找等高效率的算法。一般的顺序查找,复杂度为O(n),而二分查找复杂度为O(log2n)。当n很大时,二者的效率相差及其悬殊。

举个例子:
  表中有一百万条数据,需要在其中寻找一条特定id的数据。如果顺序查找,平均需要查找50万条数据。而用二分法,至多不超过20次就能找到。二者的效率差了2.5万倍!

在一个或者一些字段需要频繁用作查询条件,并且表数据较多的时候,创建索引会明显提高查询速度,因为可由全表扫描改成索引扫描。(无索引时全表扫描也就是要逐条扫描全部记录,直到找完符合条件的,索引扫描可以直接定位)

不管数据表有无索引,首先在SGA的数据缓冲区中查找所需要的数据,如果数据缓冲区中没有需要的数据时,服务器进程才去读磁盘。
  1、无索引,直接去读表数据存放的磁盘块,读到数据缓冲区中再查找需要的数据。
  2、有索引,先读入索引表,通过索引表直接找到所需数据的物理地址,并把数据读入数据缓冲区中。

索引的劣势?

  1. 索引是有大量数据的时候才建立的,没有大量数据反而会浪费时间,因为索引是使用二叉树建立
  2. 当一个系统查询比较频繁,而新建,修改等操作比较少时,可以创建索引,这样查询的速度会比以前快很多,同时也带来弊端,就是新建或修改等操作时,比没有索引或没有建立覆盖索引时的要慢
  3. 索引并不是越多越好,太多索引会占用很多的索引表空间,甚至比存储一条记录更多。对于需要频繁新增记录的表,最好不要创建索引,没有索引的表,执行insert、append都很快,有了索引以后,会多一个维护索引的操作,一些大表可能导致insert速度非常慢。
  4. 通常,在大型表中使用索引特别有效.当然,你也会发现,在扫描小表时,使用索引同样能提高效率.虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价.索引需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身也会被修改.这意味着每条记录的INSERT,DELETE,UPDATE将为此多付出4,5次的磁盘I/O.因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。定期的重构索引是有必要的。

面向对象

从代码实现方面说明面向对象的三大特性?

  1. 封装:封装就是隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员。封装增强安全性和简化编程。比如将类变量成员私有化,提供get/set方法供外部类使用。public, protected, , private,这四个属性的访问权限依次降低
  2. 继承:继承机制允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类具有父类相同的方法或属性。比如人,可以定义一个父类,这个父类拥有眼睛,鼻子,耳朵等属性,拥有说话,走路,吃饭,睡觉这些功能,但是人有不同的职业,比如画家,音乐家,舞蹈家,这时我们需要根据不同的职业创建出子类,但是这个子类都能继承父类的属性和功能。
  3. 多态:多态同一个行为具有多个不同表现形式或形态的能力。从代码实现层面说就是方法的重写或重载。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
    比如音乐家,画家,舞蹈家都会表演,那么观众只需要提出表演这个需求,那她们就会根据自身的情况去展现,音乐家会表演唱歌,画家会表演作画,那舞蹈家表演跳舞。
    多态存在的三个必要条件:
    继承
    重写(子类继承父类后对父类方法进行重新定义)
    父类引用指向子类对象

举例说明类和实例?

面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,而实例是根据类创建出来的一个个具的“对象”。比如人,类就是指人这个概念,实例就是指具体的某个人。每个人都有共有的属性和功能,但是每个人又有不同的特点。

设计模式

单例模式?

所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。不管外界调用多少次,返回的永远是同一个对象。
特点:类构造器私有,持有自己类型的属性,对外提供获取实例的静态方法。
类加载后就立马创建对象,即外界调用之前:

class SingletonCaseOne{
    private static final SingletonCaseOne singletonCaseOne = new SingletonCaseOne();
    private SingletonCaseOne(){};
    public static SingletonCaseOne getSingleton(){
        return singletonCaseOne;
    }
}

外界调用时创建对象:

class SingletonCaseTwo{
    private static volatile SingletonCaseTwo singletonCaseTwo;
    private SingletonCaseTwo(){};
    public static SingletonCaseTwo getSingleton(){
        if(singletonCaseTwo == null){
            synchronized (SingletonCaseTwo.class){
                if (singletonCaseTwo == null){
                    singletonCaseTwo = new SingletonCaseTwo();
                }
            }
        }
        return singletonCaseTwo;
    }
}

工厂模式?

工厂模式分为简单工厂模式,抽象工厂模式,它们都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,目的是降低系统中代码耦合度,并且增强了系统的扩展性。
简单工厂模式:优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码逻辑将会非常复杂

public interface Person {
    public void say();
}

class Boy implements  Person {
    public void say(){
        System.out.println("I am a boy");
    }
}

class Girl implements  Person {
    public void say(){
        System.out.println("I am a girl");
    }
}

class simpleFactory{
    public Person createPerson(String sex){
        Person person = null;
        if(sex == "female"){
            person = new Girl();
        }else if(sex == "male"){
            person = new Boy();
        }
        return  person;
    }
}

抽象工厂模式:在工厂方法模式中,一个具体的工厂负责生产一类具体的产品,即一对一的关系,但是,如果需要一个具体的工厂生产多种产品对象,那么就需要用到抽象工厂模式了。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

interface Shape {
    public void draw();
}

class Rectangle implements  Shape {
    public void draw(){
        System.out.println("It's rectangle");
    }
}

class Square implements  Shape {
    public void draw(){
        System.out.println("It's square");
    }
}

interface Color{
    public void fill();
}

class Red implements  Color {
    public void fill(){
        System.out.println("It's red");
    }
}

class Green implements  Color {
    public void fill(){
        System.out.println("It's green");
    }
}

abstract class AbstractFactory {
    public abstract Color getColor(String color);
    public abstract Shape getShape(String shape) ;
}

class ShapeFactory extends AbstractFactory{

    public Color getColor(String color) {
        return null;
    }

    public Shape getShape(String shape) {
        Shape createdShape= null;
        if("Rectangle" == shape){
            createdShape = new Rectangle();
        }else if("Square" == shape){
            createdShape = new Square();
        }
        return createdShape;
    }
}

class ColorFactory extends AbstractFactory{

    public Color getColor(String color) {
        Color createdColor= null;
        if("Red" == color){
            createdColor = new Red();
        }else if("Green" == color){
            createdColor = new Green();
        }
        return  createdColor;
    }

    public Shape getShape(String shape) {
        return null;
    }
}

class FactoryProducer{
    public AbstractFactory getFactory(String type){
        AbstractFactory factory= null;
        if("Shape" == type){
            factory = new ShapeFactory();
        }else if("Color" == type){
            factory = new ColorFactory();
        }
        return factory ;
    }
}

Spring

如何理解Spring?

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

  1. 轻量:从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的
  2. 控制反转:spring的核心思想,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。通常通过依赖注入实现,当容器初始化某个对象时,会将依赖的对象进行创建并且注入到当前对象中,注入方式可分为属性注入,构造函数注入,set方法注入
  3. 面向切面:将影响多个类的公共行为封装成可重用的模块,通过切入的方式插入到要用到的地方。封装与业务无关的逻辑,与业务模块一起调用,减少代码的重复和耦合。具有良好的代码隔离性和源代码无关性。通常用在日志记录、声明性事务、安全性,和缓存等

如何自己实现一个IoC?

可参考下面链接:
[https://www.cnblogs.com/laipimei/p/11205510.html]

算法:

如何高效的反转一个数组?

public void reverseArray(int[] array){
        int len=array.length;
        for(int i=0; i<= len/2 ;i++){
            int temp = array[i];
            array[i]=array[len-1-i];
            array[len-1-i]=temp;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值