Java面试题-day09高级问题

高级问题

1) JVM优化

  1. 升级JVM版本。如果能使用64-bit,使用64-bitJVM。

  2. 选择一个正确的GC(GargageCollection)。
    由于当JAVA程序GC的时候,会停下当前程序。尤其FullGC的时候,会停留很长时间。一般对于GUI程序来说,是很难接受的。JAVA5以后,开始自带了好几种GC,你可以选择一个适合你的种类。有以下四种SerialCollector,Parallelcollector(推荐使用并行收集),ConcurrentCollector。

  3. 正确设置内存大小。进行JVM调优时对JVM堆内的各个区域(young,old,perm)正确设置大小。
    通常使用一下几个参数调整-Xms-Xmx-XX:MaxPermSize。

    3.1 调高-XX:NewRatio(NewSize/MaxNewSize)的值,会减少younggc的次数,但会增加oldgc的时间。

    3.2 增加普通GC的方法(减小FullGC)。扩大young区域的大小(最大40%),并过大Survivor的区域。使得更多的object留在younggen。

  4. 以下是几个写程序时,应该注意的地方。也可减小GC,提高JVM性能。

         1.不要使用System.gc()方法。因为它会产生FullGC。
         2.尽可能少分配大的临时对象(生命周期短的),可能会直接分配到old区域里,old区域只有FullGC的时候会收集。
         3.避免使用finalize()方法。finalize()会增加GC的负担,使用java.lang.ref代替。
    

2) JVM内存溢出问题

最近在熟悉一个开发了有几年的项目,需要把数据库从mysql移植到oracle,首先把jdbc的连接指向mysql,打包放到tomcat里面,可以跑起来,没有问题,可是当把jdbc连接指向oracle的时候,tomcat就连续抛java.lang.OutOfMemoryError的错误。

1.JVM内存溢出现象提示一:java.lang.OutOfMemoryError:Javaheapspace

解释:
Heapsize设置
JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heapsize的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn-Xms-Xmx等选项可进行设置。Heapsize的大小是YoungGeneration和TenuredGeneraion之和。

提示:在JVM中如果98%的时间是用于GC且可用的Heapsize不足2%的时候将抛出此异常信息。
提示:HeapSize最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
解决方法:
手动设置Heapsize
修改
TOMCAT_HOME/bin/catalina.bat
“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:
在这里插入图片描述

2、JVM内存溢出现象提示二:java.lang.OutOfMemoryError:PermGenspace

原因:
PermGenspace的全称是PermanentGenerationspace,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGenspace中,它和存放类实例(Instance)的Heap区域不同,GC(GarbageCollection)不会在主程序运行期对PermGenspace进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGenspace错误,这种错误常见在web服务器对JSP进行precompile的时候。如果你的WEBAPP下都用了大量的第三方jar,其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。

解决方法:手动设置MaxPermSize大小

修改TOMCAT_HOME/bin/catalina.bat(Linux下为catalina.sh),在Java代码
“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:
在这里插入图片描述
catalina.sh下为:
在这里插入图片描述

3) 泛型

从Java SE5.0开始引入,其实质是将原本确定不变的数据类型参数化。

为什么会出现泛型?

因为集合存放的数据类型不固定,故往集合里面存放元素时,存在安全隐 患,如果在定义集合时,可以想定义数组一样指定数据类型,那么就可以 解决该类安全问题。JDK1.5后出现了泛型,用于解决集合框架的安全问题。
泛型是一个类型安全机制。
泛型优点:作为对原有Java类型体系的扩充,使用泛型可以提高Java应用程序的类型安全、可维护性和可靠性。范型类,范型方法

枚举

一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值, Java5以后可以直接使用
枚举予以解决。

 可以这样来定义一个枚举类型。

public enum Color {
    
        
		Red,    
		White,    
		Blue 
	} 

 也可以这样使用

Color myColor = Color.Red

5) 设计模式

单态模式、工厂模式、MVC、代理模式(spring中的AOP功能)、DAO、
观察者模式(发布-订阅模式):定义了一种一对多的依赖关系,让多个观察者对象同事监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
工厂模式:该模式将创建对象的过程放在了一个静态方法中来实现.在实际编程中,如果需要大量的创建对象,该模式是比较理想的。

6) 反射技术

类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。
字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。
通过Class类、Method类、Field类等类可以得到这个类型的一些信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术。

举例:在spring中,生成对象时就是使用反射技术

如何通过反射创建对象?

  • 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()
  • 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);

7) Junit单元测试框架的基本使用

软件测试有很多分类

从测试的方法上可分为:黑盒测试、白盒测试、静态测试、动态测试等;

从软件开发的过程分为:单元测试、集成测试、确认测试、验收、回归等。

在众多的分类中,与开发人员关系最紧密的莫过于单元测试了。像其他种类的测试基本上都是由专门的测试人员来完成,只有单元测试是完全由开发人员来完成的。那么今天我们就来说说什么是单元测试,为什么要进行单元测试,以及如更好的何进行单元测试。
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。比如我们可以测试一个类,或者一个类中的一个方法。

8) 如何实现对象克隆?

有两种方式:

  • 1)实现Cloneable接口并重写Object类中的clone()方法;
  • 2)实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

9) Java对XML文件的处理方式

DOM解析和SAX解析

DOM解析原理:xml解析器一次性把整个xml文档加载进内存,然后在内存中构 建一棵Document的对象树,通过Document对象,得到树上的节点对象,通过节 点对象访问(操作)到xml文档的内容。(DOM4J)

DOM解析原理:一次性把xml文档加载进内存,然后在内存中构建Document树。
	对内存要求比较要。	
	缺点:不适合读取大容量的xml文件,容易导致内存溢出。	
	SAX解析原理:加载一点,读取一点,处理一点。对内存要求比较低。
    XML是一种重量级的数据交换格式。JSON是轻量级数据交换格式。

在这里插入图片描述

10) 你在项目中哪些地方用到了XML?

答:XML的主要作用有两个方面:数据交换信息配置。在做数据交换时,XML将数据用标签组装成起来,然后压缩打包加密后通过网络传送给接收者,接收解密与解压缩后再从XML文件中还原相关信息进行处理,XML曾经是异构系统间交换数据的事实标准,但此项功能几乎已经被JSON(JavaScript Object Notation)取而代之。当然,目前很多软件仍然使用XML来存储配置信息,我们在很多项目中通常也会将作为配置信息的硬代码写在XML文件中,Java的很多框架也是这么做的,而且这些框架都选择了dom4j作为处理XML的工具。

11) 你了解大O符号(big-O notation) 么?你能给出不同数据结构的例子么?

此问题是问算法的时间复杂度

大 O 符号描述了当数据结构里面的元素增加的时候,算法的规模或者是性能在最坏的场景下有多么好。
大 O 符号也可用来描述其他的行为,比如:内存消耗。因为集合类实际上是数据结构,我们一般使用大 O 符号基于时间,内存和性能来选择最好的实现。大 O 符号可以对大量数据的性能给出一个很好的说明。

容易计算的方法是:看看有几重for循环,只有一重则时间复杂度为O(n),二重则为O(n^2),依此类推,如果有二分则为O(logn),二分例如快速幂、二分查找,如果一个for循环套一个二分,那么时间复杂度则为O(nlogn)。

12) Java注解及实现原理

  • 一.什么是注解:
    注解是标记,也可以理解成是一种应用在类、方法、参数、属性、构造器上的特殊修饰符。注解作用有以下三种:
    第一种:生成文档,常用的有@param@return等。
    第二种:替代配置文件的作用,尤其是在spring等一些框架中,使用注解可以大量的减少配置文件的数量。
    第三种:检查代码的格式,如@Override,标识某一个方法是否覆盖了它的父类的方法。

  • 二.注解的底层实现原理:
    注解的底层也是使用反射实现的,我们可以自定义一个注解来体会下。注解和接口有点类似,不过申明注解类需要加上@interface,注解类里面,只支持基本类型、String及枚举类型,里面所有属性被定义成方法,并允许提供默认值。

     java 5.0开始,在java.lang.annotations中提供了四种元注解,专门注解其他的注解:
    
   @Target?  ——注解用于什么地方
    TYPE,  //给类(型)注解
    FIELD, //给字段注解,不要忘了,字段可以是对象
    METHOD, //给方法注解
    PARAMETER, //给参数注解
    CONSTRUCTOR, //给构造方法注解
    LOCAL_VARIABLE, //给局部变量注解
    ANNOTATION_TYPE,//给注解注解(这貌似把自己不当类来看)
    PACKAGE, //给包注解
   @Retention ——注解运行状态
	SOURCE, //源码状态运行,
	 CLASS, //编译类文件时运行
	 RUNTIME //运行时运行
   @Documented ——生成说明文档,添加类的解释
   @Inherited ——允许子类继承父类中的注解。

我们自定义一个注解来感受下:
定义注解类:

@Target({
    
    ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface User {
    
      
   String name() default "张三";  
}  

由于我们的注解是类注解,所以我们创建一个类

@User  
 public class test {
    
      
}  

到了这里,注解可能还没起什么作用。我们需要通过反向代理去读取类中定义的注解,读出来使用就简单了。
创建测试类,来读取:

public class testamin {
    
      
public static void main(String[] args) throws ClassNotFoundException{
    
      
        Class<?> classTest=Class.forName("com.test.test");  
        Annotation[] ann=classTest.getAnnotations();  
        for(Annotation aa:ann){
    
      
            User u=(User)aa;  
            System.out.println(u.name());  
        }  
     }  
}  

13) Java8新特性

  • 1)Lambda表达式和函数式接口
    Lambda表达式(也称为闭包)是Java 8中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理:函数式开发者非常熟悉这些概念。很多JVM平台上的语言(Groovy、Scala等)从诞生之日就支持Lambda表达式,但是Java开发者没有选择,只能使用匿名内部类代替Lambda表达式。

  • 2)接口的默认方法和静态方法
    Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得接口有点类似traits,不过要实现的目标不一样。默认方法使得开发者可以在不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。
    默认方法和抽象方法之间的区别在于抽象方法需要实现,而默认方法不需要。接口提供的默认方法会被接口的实现类继承或者覆写

  • 3)方法引用
    方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。

  • 4)重复注解
    自从Java 5中引入注解以来,这个特性开始变得非常流行,并在各个框架和项目中被广泛使用。不过,注解有一个很大的限制是:在同一个地方不能多次使用同一个注解。Java 8打破了这个限制,引入了重复注解的概念,允许在同一个地方多次使用同一个注解。

在Java 8中使用@Repeatable注解定义重复注解

14) 你知道哪些数据结构?

	线性表
	队列
	栈和堆
	二叉树
	二叉树可以为空。二叉树结点的子树要区分左子树和右子树,即使只有一棵子树也要进行区分,说明它是左子树,
还是右子树。这是二叉树与树的最主要的差别。

猜你喜欢

转载自blog.csdn.net/m0_56368068/article/details/120856657