Java 初级面试宝典【基础篇】

红色加粗一定要仔细看!!!

JVM:

 

       启动流程:先去装载配置,根据当前路径和系统版本寻找jvm.cfg ,然后去找需要的jvm.dll(主要实现), dll初始化jvm虚拟机,获得一些jnienv接口等,然后找到main方法并运行。

       内部结构:首先会有类加载器子系统(classloader),把java文件的class文件加载的jvm中,加载到内存空间(方法区,java堆,java栈,本地方法区(native方法调用)),虚拟机运行的时候和普通的cpu一样,需要一个指针指向下一条指令地址,就是pc寄存器。有一个执行引擎来执行虚拟机代码,就是class类的字解码。运行的时候还有一个垃圾回收器。

       pc寄存器:每一个线程拥有一个pc寄存器,pc寄存器总是指向下一条指令地址。执行本地的方法时,是未定义的。

       方法区:保存类的元信息的。就是class信息,用来描述类的信息,类型的常量池,字段,方法信息,方法字节码。(jdk6:是把常量信息置于方法区。jdk7:常量已经移到了堆)通常和永久区关联在一起。

       本地方法栈:本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。

        :和程序开发最为密切的,因为new出来的对象,都是在java堆里面分配的。所以的线程共享java堆。对分代GC来说,堆也是分代的。

         :线程私有的。栈又叫帧栈,先进后出的数据结构,帧保存一个方法的局部变量、操作数栈、常量池指针,每一次方法调用创建一个帧,并压栈。

         栈上分配:堆上分配,每次需要清理空间。栈上分配,函数调用完成自动清理。

可见性:一个线程修改了变量,其他线程可以立即知道

保证可见性的方法:1.volatile 2.synchronized(unlock之前,写变量值回主存) 3.final(一单初始化完成,其他线程就可见 )

有序性:在本线程内,操作都是有序的,在线程外观察,操作都是无序的。(指令重排 或 主内存同步延时)

启动GC:-verbose:GC

堆分配参数:

-Xmx:最大堆

-Xms:最小堆

-Xmn:新生代大小

-XX:NewRatio:新生代 比例值

 

栈分配参数:栈空间应该分配比较小,线程运行是不可缺少的,一般是几百k容量,栈是每一个线程起来的时候都会被分配的一个空间,如果想尽量跑一些线程,就应该设置小点。栈大小决定了函数调用的深度,比如递归调用,如果栈太小就会导致栈溢出。

-Xss:几百k,决定了函数调用的

GC:GC的对象就是堆空间和永久区。

回收垃圾的算法

1. 引用计数法:通过引用计算来垃圾回收(老牌垃圾回收算法),为每个对象标记一个使用数量,当对象引用数量为0的时候,就可以被回收。

引用方法问题:1. 随着引用的加法和减法,影响性能。 2.很难处理循环引用。

2.标记清除法:垃圾回收分为标记阶段和清除对象。在标记阶段通过根节点,标记所以从根节点开始的可达对象。清除阶段清理未标记的对象。

3.标记压缩法:在标记清除法做了一些优化。但是清除并不是清除未标记的对象,而是将存活对象压缩到内存的另外一端。之后清理边界外所有的空间。

4.复制算法:将内存分为两块,只使用其中的一块,将存活的对象复制到未使用的内存块中,清除正在使用的内存块中的所有对象,交换两个对象角色,完成回收。(浪费空间)

 

new对象:父类静态块>子类静态块> 父类属性(先系统默认值,后直接你赋予的值) >父类构造器>子类属性>子类构造器

this和super

     从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

     super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。

类(class)加载过程:加载 -> 校验 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载

1. 加载:

    加载一个Class需要完成以下3件事情:

  • 通过class的全限定名获取class的二进制字节流
  • 将class的二进制内容加载到虚拟机的方法区
  • 在内存中生成一个java.long.ckass对象表示这个class

    获取class的二进制字节流方法:

    由其他文件生成,典型的是从jsp文件生成相应的class

2. 校验:

     校验一个class的二进制内容是否合法:文件格式验证 -> 元数据验证 -> 字节码验证 -> 符号应用验证

3.  准备:虚拟机会在方法区中为class分配内存,并设置static成员变量的初始值为默认值。

4.  解析:

     主要针对的是类、接口、方法、成员变量等符号应用。

 

 

 

线程:

Q:如何创建一个线程?

A:实现Runnable接口,继承Thread类

 

Q:实现Runnable接口,继承Thread类 那个好呢?

A:Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口好 了。

 

Q:Thread 类中的start() 和 run() 方法有什么区别

A:start()方法被用来启动新创建的线程,而且start()内部 调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启 动,start()方法才会启动新线程。

 

Q:volatile 变量是什么?

A:volatile是一个特殊的修饰符,只有成员变量才能使用它。

 

Q:如何避免死锁?

A:死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。

 

Q:怎么检测一个线程是否拥有锁?

A:在Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。

 

Q:wait()与sleep()的区别

A:sleep()睡眠后不出让系统资源,wait让其他线程可以占用CPU

 

Q:什么是多线程的上下文切换?

A:多线程的上下文切换是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。

 

Q:Synchronized 和 lock 区别?

A:Lock是一个接口,而synchronized是关键字。synchronized会自动释放锁,而Lock必须手动释放锁。Lock能提高多个线程读操作的效率。synchronized能锁住类、方法和代码块,而Lock是块范围内的

 

拦截器和过滤器:

监听器:是servlet规范中定义的一种特殊类。用于监听域对象的创建和销毁事件。使用场景:1.统计在线人数和在线用户 2.系统启动时加载初始化信息 3.统计网站访问量 4.记录用户访问路径。

区别:

1.拦截器是基于java的反射机制,而过滤器是基于函数回调。

2.拦截器不依赖与servlet容器,过滤器依赖与servlet容器。

3.拦截器只能对action请求起作用,而过滤器则可能对几乎所有的请求起作用。

4.在action的生命周期中, 拦截器可以多次被调用,而过滤器在初始化时被调用一次。

5.拦截器可以获取ioc容器中的各个bean,而过滤器就不行,在拦截器里注入一个service,可以调用业务逻辑。

执行顺序:

 

拦截器创建:

1.实现Handler Interceptor接口,重写里面的方法,实现业务逻辑代码

2.用java代码进行配置拦截器

addPathPatterns("/**")添加了所有的都拦截。

 

过滤器创建:

1.在启动类增加@ServletComponentScan注解

2.配置过滤器,需要实现filter接口,然后配置注解@WebFilter,设定filter的名称和过滤地址

 

监听器创建:

自定义一个类实现ApplicationListener即可,具体监听什么事件,讲事件填入到泛型中

 

Spring IOC和AOP:

 上下文:负责加载在xml或者是java代码中配置bean的相关信息。

ioc:是一种编程思想,它的设计思想是想把创建对象,管理对象的生命周期,程序集直接的解耦工作交给第三方容器来处理。传统的方式都是自己new一个对象,然后再写一个公共类去维护这个对象的生命周期。用了IOC组件之后这些操作就交由第三方ioc容器组件来处理,只需要把对象塞进容器里,并告诉容器这个对象的生命周期就可以了。

创建对象的几种方式:
1.调用无参构造器
2.带参构造器
3.工厂创建对象:静态方法创建对象,非静态方法创建对象
什么情况下会用构造器注入:对强依赖使用构造器注入,对可选择性的依赖使用属性注入

spring提供了三种主要的方式来配置:
1.在xml中进行显式配置
2.在java中进行显式配置,javaConfig
3.隐式的bean发现机制和自动装配
@Autowired:实现自动装配
@Qualifier:解决多个相同类型的bean,指定bean
aop:
使用场景:缓存,持久化,同步,事务

AOP的源码中用到了两种动态代理来实现拦截切入功能:
jdk动态代理和cglib动态代理。
两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)

设计模式:

工厂模式:

使用目的:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

优点:1.一个调用者想创建一个对象,只要知道其名称就可以了。

2.扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

3.屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:1.每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

使用场景:1.日志记录器:记录肯记录到本地硬盘、系统事件、远程服务器等,太湖可以选择记录日志到什么地方。

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值