欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

[Java面试]java笔试题总结,

来源: javaer 分享于  点击 15500 次 点评:278

[Java面试]java笔试题总结,


java笔试题总结

    • 1. JVM总结
    • 2. Statement、PreparedStatement和CallableStatement
    • 3. doGet和doPost
    • 4. Servlet的生命周期
    • 5. Servlet是否是进程安全的
    • 6. Struts1和Struts2的区别和对比:
    • 7.封装
    • 8. final关键字
    • 9. 类的初始化顺序
    • 10. Java多线程
    • 11. SSM核心知识
    • 12. 依赖倒置原则、IOC、DI、IOC容器的关系
    • 13. Spring IOC 容器
      • Spring源码 getBean方法的调用逻辑
      • Spring Bean的作用域
      • Spring Bean的生命周期
      • 理解Spring AOP
    • 14. Mysql数据库采用b+树较b树的优势
    • 15. switch语句带来的性能损耗问题
    • 16 . Try catch以及throws异常的机制
    • 17. 采用getter setter方法进行传值的分析
    • 18. equals方法
    • 19.StringBuilder和String类型在效率上的具体效率
    • 20. 反射的理解
    • 21.各种内存区域
    • 22. 反射的性能问题
    • 23. 类继承
    • 24. 抽象类和接口在设计上的区别
    • 25. 自动装箱和拆箱
    • 26. 理解字符串常量池和运行时常量池

这篇博客是自己平时看到的一些或者有新知识点,或者旧知识重新学习之后有启发的一些内容,总结在这里,也是为了方便日后回顾,共勉。

1. JVM总结

@转自 牛客网:菜鸟葫芦娃 的回答


参考链接

  • 线程共享:
    • 方法区(method area):存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等
    • 堆(heap):存储对象信息,包括对象的属性、方法
  • 非线程共享
    • 程序计数器(Program Counter Register)
    • 虚拟机栈(VM Stack)
    • 本地方法栈 (Native Method Stack)

    大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的),Native Method Stack ( 本地方法栈 ),其中Method Area 和 Heap 是线程共享的 ,VM Stack,Native Method Stack 和Program Counter Register 是非线程共享的。为什么分为 线程共享和非线程共享的呢?请继续往下看。
     首先我们熟悉一下一个一般性的 Java 程序的工作过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢?
     概括地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么我把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说知发生在Heap上)的原因。

2. Statement、PreparedStatement和CallableStatement

PreparedStatement是预编译的,使用PreparedStatement有几个好处

3. doGet和doPost

  • doget/dopost与Http协议有关,是在 javax.servlet.http.HttpServlet 中实现的。
  • GenericServlet 抽象类 给出了设计 servlet 的一些骨架,定义了 servlet 生命周期,还有一些得到名字、配置、初始化参数的方法,其设计的是和应用层协议无关的

4. Servlet的生命周期

5. Servlet是否是进程安全的

servlet在多线程下其本身并不是线程安全的。
如果在类中定义成员变量,而在service中根据不同的线程对该成员变量进行更改,那么在并发的时候就会引起错误。最好是在方法中,定义局部变量,而不是类变量或者对象的成员变量。由于方法中的局部变量是在栈中,彼此各自都拥有独立的运行空间而不会互相干扰,因此才做到线程安全。

6. Struts1和Struts2的区别和对比:

  • Action 类:
    • Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口,而struts2的Action是接口。
    • Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去 实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。

  • 线程模式:
    • Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
    • Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)

  • Servlet 依赖:
    • Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。
    • Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。

  • 可测性:
    • 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。
    • Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。

  • 捕获输入:
    • Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存 在的JavaBean(仍然会导致有冗余的javabean)。
    • Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。

  • 表达式语言:
    • Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。
    • Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--“Object Graph Notation Language” (OGNL).

7.封装

封装是把对象的属性和操作结合在一起,组成一个新的独立的对象,其内部信息对外界是隐藏的,外界只能通过有限的接口域对象发生关系

8. final关键字

  • final修饰的类:叫做最终类,不可被继承
  • final修饰的方法:不能被重写
  • final修饰的变量:final修饰的变量叫做常量,必须要初始化,且无法被修改

9. 类的初始化顺序

类的初始化顺序遵循两个规则:(方便记忆)
一、父类先于子类
二、静态先于非静态

我们根据这两个规则:有初始化顺序–>

10. Java多线程

11. SSM核心知识

  • IOC依赖注入,基于反射机制
  • AOP面向切面,基于动态代理(jdk,cglib)

12. 依赖倒置原则、IOC、DI、IOC容器的关系

**解释:**其中依赖倒置原则是一种设计思想,该思想的核心理念是高层的代码不应该依赖于底层的代码。并基于此思想设计出了IOC控制反转,IOC的实现需要通过依赖注入的方法实现,即DI是实现IOC的一种方法。

**优势:**避免在各处使用new来创建对象,从而实现对象的统一维护
创建实例的时候不必了解其中的实现细节,通过接口进行实现。

IOC与普通创建对象过程上的差异:

13. Spring IOC 容器

Spring IOC容器的核心接口:

  • BeanFactory: 提供IOC的配置机制,包含Bean的各种定义,便于实例化Bean;建立Bean之间的依赖关系;控制Bean的生命周期
  • ApplicationContext :继承多个接口
  • BeanDefinition: 用来描述Bean’的定义
  • BeanDefinitionRegistry: 提供向IOC容器注册BeanDefinition对象的方法

Spring源码 getBean方法的调用逻辑

Spring Bean的作用域

  • singleton: 默认作用域,容器里拥有唯一的bean实例(适合无状态的Bean)
    在Spring IoC容器中仅存在一个Bean的示例,Bean以单实例的方式存在,单实例模式是重要的设计模式之一,在Spring中对此实现了超越,可以对那些非线程安全的对象采用单实例模式。
  • prototype:针对每一个getBean请求,容器都会创建一个bean实例 (适合有状态的Bean)

当用户使用Spring的WebApplicationContext时,还可以使用另外3种Bean的作用域,即request,session和globalSession。

  • request:为每个http请求创建一个bean实例
  • session:为每个session创建一个bean实例
  • globalSession:为每个全局HttpSession创建一个Bean实例,该作用域仅对Portlet有效

Spring Bean的生命周期

理解Spring AOP

面向切面编程
关注点分离,不同的问题交给不同的部分去解决。
分离业务功能代码和切面代码,架构将变变得高内聚低耦合。为确保功能的完整性,切面最终要通过Weave被合并到业务中。


AOP的实现

  • JDKProxy:通过Java内部的反射机制进行实现
  • Cglib:借助ASM进行实现
    区别:
  • JDK反射机制在生成类的过程中比较高效
  • ASM在生成类之后的执行过程比较高效
    设计模式: 代理模式==》接口+ 真实实现类+代理类
    getBean方法返回的实际上是Proxy的实例

14. Mysql数据库采用b+树较b树的优势

https://www.cnblogs.com/nullzx/p/8978177.html

-----------------------------------------------------------------2019.6.2---------------------------------------------------------------

15. switch语句带来的性能损耗问题

switch语句不加break会产生击穿现象,顺序执行case后面的内容,带来性能的损耗。
在switch语句对case判断成功后,不加break,其后的内容将会顺序执行,带来性能问题。

16 . Try catch以及throws异常的机制

  • 降低代码量。
    使用trycatch接收异常信息,就不需要在下层书写和传递过多的判断变量,优化代码的逻辑和代码量。
  • 不影响线程的继续执行
    若系统产生的异常交给java虚拟机进行处理,当前线程的执行会终止,其后的内容便无法执行。

17. 采用getter setter方法进行传值的分析

对于同时使用了getter和setter方法的域属性,除在

18. equals方法


如上图是Object类的equals方法, 比较的是对象的引用地址。
String类重写的equals方法,比较字符串的值

19.StringBuilder和String类型在效率上的具体效率

20. 反射的理解

根据类的路径获取类的具体信息,并可通过获取的类型信息进行对象实例化

  • 对Class类的理解:
    网上对Class有各种各样的说法,其中有一大部分称之为 类类型 ,个人认为这种说法并不友好,也很难理解。根据反射的概念,我们通过反射获取到的是类的信息,如Class Student = Class.forName(“类的路径”);
    此时Class中包含的就是这个路径所代表的类的所有信息,我们还可通过Filed,Method分别获取类的域和方法信息。

21.各种内存区域

  • final修饰的数据的存储地址与是否final修饰无关,加final仅限定不可变,具体的存储地址与变量的类型有关。
  • 基本数据类型:栈
  • 对象:堆
  • 常量池:
    Java6和6之前,常量池是存放在方法区中的。
    Java7,将常量池是存放到了堆中,常量池就相当于是在永久代中,所以永久代存放在堆中。
    Java8之后,取消了整个永久代区域,取而代之的是元空间。没有再对常量池进行调整。

String a = “aaa”+“bbb”;
String b = “aaabbb”;
----->比较结果为true

String a= “aaa”;
String b = “bbb”;
String c = “aaabbb”;
System.out.println((a+b) == c);
----->比较结果为false
subString方法采用的是new的方式产生子串

22. 反射的性能问题

如对数组进行拷贝的时候使用for循环进行拷贝,和使用Arrays.copyof()方法进行数组拷贝哪个效率更高呢?
我们可以看到copyof方法使用了反射的机制进行数组拷贝,而使用反射会带来极大的性能问题,因为反射需要获取类的信息。所以对于引用数据类型,使用for循环进行拷贝是一种更好的选择。

23. 类继承

子类继承父类,使用多态进行实现,Person person = new Student()
若想调用子类的方法,需要将person强转为Student类型

24. 抽象类和接口在设计上的区别

抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。

举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

25. 自动装箱和拆箱

Java包装类及自动装箱、拆箱

java会自动调用装箱和拆箱操作,Integer.valueOf(3)和 i.intValue()

  • 128陷阱
    超过128会返回 new Integer();
public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }

26. 理解字符串常量池和运行时常量池

  • 运行时常量池存在于内存中,也就是class常量池被加载到内存之后的版本,不同之处是:它的字面量可以动态的添加,符号引用可以被解析为直接引用
  • JVM在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。在解析阶段,会把符号引用替换为直接引用,解析的过程会去查询字符串常量池,也就是我们上面所说的StringTable,以保证运行时常量池所引用的字符串与字符串常量池中是一致的。

相关文章

    暂无相关文章
相关栏目:

用户点评