20191227面试小结

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

有4个主要特征:封装、抽象、继承、多态

  1. 封装: 封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。把握一个原则:把对同一事物进行操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同一个类中。

  2. 抽象: 抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个Person类,
    如下: class Person{ String name; int age; } 人本来是很复杂的事物,有很多方面,但因为当前系统只需要了解人的姓名和年龄,所以上面定义的类中只包含姓名和年龄这两个属性,这就是一种抽像,使用抽象可以避免考虑一些与目标无关的细节。我对抽象的理解就是不要用显微镜去看一个事物的所有方面,这样涉及的内容就太多了,而是要善于划分问题的边界,当前系统需要什么,就只考虑什么。

  3. 继承: 在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。

  4. 多态: 多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态性增强了软件的灵活性和扩展性。例如,下面代码中的UserDao是一个接口,它定义引用变量userDao指向的实例对象由daofactory.getDao()在执行的时候返回,有时候指向的是UserJdbcDao这个实现,有时候指向的是UserHibernateDao这个实现,这样,不用修改源代码,就可以改变userDao指向的具体类实现,从而导致userDao.insertUser()方法调用的具体代码也随之改变,即有时候调用的是UserJdbcDao的insertUser方法,有时候调用的是UserHibernateDao的insertUser方法: UserDao userDao = daofactory.getDao(); userDao.insertUser(user);

2、String是最基本的数据类型

不是基本的数据类型,只是代表一个类,是一个引用类型
基本数据类型就只有八个
数值型:byte,short,int,long
浮点型:float,double
字符型:char
布尔型:boolean

3、int和Integer的区别

  • Integer是int的包装类,int则是java的一种基本数据类型
  • Integer变量必须实例化后才能使用,而int变量不需要
  • int存储在栈中,Integer对象的引用存储在栈空间中,对象的数据存储在堆空间
  • Integer的默认值时null,int的默认值是0
  • int是值传递,栈中的数据不可变,Integer对象是引用传递,引用不可变,但是引用指向的对空间地址的值是可以改变的
  • 泛型不支持int,但是支持integer

4、String、StringBuffer、StringBulider的区别

底层 可变 线程安全 执行速度 应用场景
String final char value[] 不可变 操作少量数据
StringBuffer char value[] 可变 单线程操作大量数据
StringBuilder char value[] 可变 多线程操作大量数据

5、运行时异常与一般异常有何不同

运行时异常:

  • 在定义方法时不需要声明会抛出runtime exception
  • 在调用这个方法时不需要捕获这个runtime exception
  • runtime exception是从java.lang.RuntimeException或java.lang.Error类衍生出来的

一般异常:
定义方法时必须声明所有可能抛出的checked exception;
在调用这个方法时,必须捕获它的checked exception,不然就得把它得exception传递

6、说一下ArrayList、Vector、LinkedList的存储性能和特性

类型 底层 查询 增删 线程安全 效率
ArrayList 数组 不安全
Vector 数组 安全
LinkedList 链表 不安全

7、Collection和Collection的区别

1、java.util.Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式
2、java.util.Collections是一个包装类,它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架

8、final、finally、finalize的区别

在Java中,final可以用来修饰类,方法和变量(成员变量或局部变量)

  • final类中所有的成员方法都会隐式的定义为final方法,类不能被继承。
  • final方法意味着“最后的、最终的”含义,即此方法不能被重写。
  • final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。

finally

  • 异常处理的一部分,一般用于释放资源,例如IO流 数据库连接
  • 一般来说,finally中的代码块一定会执行,特殊情况下 例如运行之前jvm提前退出了(system。exit())则不会执行了

finalize

  • object类的一个方法,用于垃圾回收,一般由垃圾回收器调用,不用我们自己调用

9、Overload和Override的区别

Override(重写)

  • 方法名、参数、返回值相同。
  • 子类方法不能缩小父类方法的访问权限。
  • 子类方法不能抛出比父类方法更多的异常。
  • 存在于父类和子类之间。
  • 方法被定义为final不能被重写。
  • 被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

应用:
最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法
除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法

Overload(重载)

  • 参数类型、个数、顺序至少有一个不相同。
  • 不能重载只有返回值不同的方法名
  • 针对于一个类而言
  • 不能通过访问权限、返回类型、抛出的异常进行重载
  • 方法的异常类型和数目不会对重载造成影响

总结

override是在不同类之间的行为,overload是在同一个类中的行为。
Overload的方法可以改变返回值的类型,因为它与返回值类型无关。

10、同步和异步有何异同,在什么情况下分别使用他们

Java中交互方式分为同步和异步两种:

同步交互:

指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程;

异步交互:

指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。

区别:

一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。

哪些情况建议使用同步交互呢

比如银行的转账系统,对数据库的保存操作等等,都会使用同步交互操作,其余情况都优先使用异步交互

11、abstract class和interface有什么区别

抽象类:

  • 不能被实例化,可以定义引用
  • 继承抽象类需要实现所有抽象方法,否则仍需要声明为抽象类
  • 可以定义构造器,可以有抽象方法和具体方法
  • 成员可以是public、默认、protected、private
  • 可以定义成员变量
  • 有抽象方法必须是抽象类,抽象类未必有抽象方法

接口

  • 不能被实例化,可以定义引用
  • 实现接口需要实现所有的抽象方法,否则仍需要声明为抽象类
  • 不可以定义构造器,方法全部都是抽象方法
  • 成员必须public
  • 可以定义成员变量实际上常量

12、forward和redirect

类型 请求次数 地址栏 共享数据 跳转限制 发生行为不同
forward(转发) 1 不发生变化 请求共享数据 只能跳转本站资源 服务器端行为
redirect(重定向) 2 发生变化 不请求共享数据 跳转任意URL 客户端行为

重定向是浏览器向服务器发送一个请求并接收到响应后再次向一个新地址发出请求,转发是服务器收到请求后为了完成响应跳转到一个新地址

13、EJB与JavaBean的区别

  • JavaBean是一个组件,而EJB就是一个框架
  • JavaBean面向的是业务逻辑和表示层的显示,通过编写一个JavaBean,可以将业务逻辑的事件和事物都放在其中,然后通过它的变量属性将所需要的内容在表示层传递显示。EJB是部署在服务器上的可执行组件或商业对象,EJB有一个部署描述符,通过这个部署描述符可以对EJB的属性进行描述,EJB不和表示层交互
  • EJB不是一般的JavaBean,EJB是企业级JavaBean,EJB一共分为3种,实体Bean,消息Bean,会话Bean,书写EJB是需要遵循一定的规范的,具体规范你可以参考相关的资料.另外,要运行EJB,你需要相应的EJB容器,比如Weblogic,Jboss等,而JavaBean不需要,只需要安装Tomcat就可以了。
  • EJB用于服务端应用开发, 而JavaBeans用于客户端应用开发也可以使用JavaBeans进行服务端应用开发,但JavaBeans模型没有提供服务框架,当应用需要使用系统级服务(如事务管理,安全性,生命周期管理等)时,不适合。
  • EJB构件是部署可定制的,使用部署描述符可以在部署EJB时对其运行时配置进行定制,而JavaBeans构件在部署时不能进行定制,JavaBeans构件的定制仅发生在开发阶段,只能利用开发工具创建并组装JavaBeans构件,部署时不能定制。
  • EJB构件是分布式对象,可以被客户应用或者其它EJB构件进行远程访问,而JavaBeans构件不是分布式象,JavaBeans构件只能在其构成的应用中使用,不能提供远程访问能力。
  • EJB构件对终端用户不可见,运行在服务端,没有人机交互界面,而部分JavaBeans构件对终端用户可见,如GUI应用中使用的按钮构件

14、什么时候使用assert

断言在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,断言用于保证程序最基本、最关键的正确性。断言检查通常在开发和测试时开启,为了保证程序的执行效率,在软件发布后断言检查通常是关闭的。断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true,如果表达式的值为false,那么系统会报告一个AssertionError

15、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j减少1,写出程序

16、启动一个线程是用run()还是start()

启动线程肯定要用start()方法。当用start()开始一个线程,线程就进入就绪状态,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。当CPU分配给它时间时,才开始执行run()方法(如果有的话)。start()是方法,它调用run()方法,而run()方法是你必须重写的,run()方法中包含的是线程主体。

17、应用服务器有哪些

  • Tomcat:免费开源,轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。实际上Tomcat 部分是Apache 服务器的扩展,但它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。只实现了JSP/Servlet的相关规范,不支持EJB
  • jetty 免费开源,架构比较简单,也是一个可扩展性和非常灵活的应用服务器。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立运行(stand-alone)的Java应用提供

18、接口是否可继承接口

接口和普通类之间:

  • 一个接口可以继承多个接口:interface C extends A,B{}
  • 一个类可以实现多个接口:class D implements A,B,C{}
  • 一个类只能继承一个类,不可以多继承:class B extends A{}
  • 一个类在继承类的同时可以实现一个(或多个)接口:class E extends D implements A,B,C{}

接口、普通类和抽象类之间

  • 抽象类可以实现接口
  • 抽象类可以继承普通类

19、说一下数据连接池的工作机制是什么

数据连接池是把数据库连接放到中间服务器上,比如tomcat上,那么相当于每次你操作数据库的时候就不需要再"连接"到数据库再进行相关操作,而是直接操作服务器上的"连接池",.这样的话就可以提高"效率".但是数据池一般是用在数据量比较大的项目,这样可以提高程序的效率,想一想这样的话是不是就把相关的负荷加在了服务器上,因为这个"池"是在服务器上的,对于小数据量处理的项目不推荐使用,应为过于频繁的请求会使得服务器负载加重
J2EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其标记为忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量由配置参数决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。

20、数组有没有length()这个方法?String有没有length()这个方法?

数组:length属性
String:length()方法
list:size()方法

21、构造器Constructor是否可被override?

构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。

Constructor不能被继承,所以Constructor也就不能被override。每一个类必须有自己的构造函数,负责构造自己这部分的构造。子类不会覆盖父类的构造函数,相反必须负责在一开始调用父类的构造函数。

22、MVC的个部分都有哪些技术来实现?如何实现?

  • model:应用的业务逻辑(如:数据库的操作),通过JavaBean实现
    (hibernate、mybatis、ibatis)
  • view:视图层,用于与用户的交互,主要由jsp页面产生。
    (jsp、FreeMarker、tails、taglib、EL、Velocity )
  • controller:处理过程控制,一般是一个servlet。

它可以分派用户的请求并选择恰当的视图以用于显示
同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。
(severlet、struts、spring、action)

23、Java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用

  • 有两种实现方法,分别是继承 Thread类与实现Runnable接口
  • 分别使用 new Thread()和 new Thread(runnable)形式, 用 synchronized 关键字修饰同步方法
  • 第一种直接调用thread 的 run 方法, 所以, 我们往往使用Thread 子类, 即 new SubThread()。
  • 第二种调用 runnable 的 run 方法。
    java5 以前, 有如下两种:

第一种:
new Thread(){}.start();这表示调用 Thread 子类对象的 run 方法, new Thread(){}表示一个Thread 的匿名子类的实例对象, 子类加上 run 方法后的代码如下:

new Thread(){
      public void run(){
     } 
 }.start();

第二种:
new Thread(new Runnable(){}).start();这表示调用 Thread 对象接受的 Runnable 对象的 run方法, new Runnable(){}表示一个 Runnable 的匿名子类的实例对象,runnable 的子类加上 run 方法后的代码如下:

 new Thread(new Runnable(){
         public void run(){
         } 
     }
  ).start(); 

从 java5 开始, 还有如下一些线程池创建多线程的方式:

ExecutorService pool = Executors.newFixedThreadPool(3)
  for(int i=0;i<10;i++){
     pool.execute(new Runable(){
         public void run(){
         }
     });
 }
 Executors.newCachedThreadPool().execute(new Runable(){
     public void run(){
     }
 });
 Executors.newSingleThreadExecutor().execute(new Runable(
     {public void run(){
     }
 });   

stop()方法作为一种粗暴的线程终止行为,在线程终止之前没有对其做任何的清除操作,因此具有固有的不安全性。 用Thread.stop()方法来终止线程将会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果 很难检查出真正的问题所在。 由于上述原因,因此不应该使用stop()方法,而应该在自己的Thread类中置入一个标志,用于控制目标线程是活动还是停止。如果该标志指示它要停止运行,可使其结束run()方法。如果目标线程等待很长时间,则应使用interrupt()方法来中断该等待。

suspend()方法 该方法已经遭到反对,因为它具有固有的死锁倾向。调用suspend()方法的时候,目标线程会停下来。如果目标线程挂起时在保护关键系统资源的监视器上保持有锁,则在目标线程重新开始以前,其他线程都不能访问该资源。除非被挂起的线程恢复运行。对任何其他线程来说,如果想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。由于上述原因,因此不应该使用suspend()方法,而应在自己的thread类中置入一个标志,用于控制线程是活动还是挂起。如果标志指出线程应该挂起,那么用wait()方法命令其进入等待状态。如果标志指出线程应当恢复,那么用notify()方法重新启动线程。

发布了18 篇原创文章 · 获赞 1 · 访问量 1417

猜你喜欢

转载自blog.csdn.net/qiteng_sijia/article/details/103737499