Java面试题(一)

Java面试题(一)

java基础

常见的Annotation

@Deprecated  -- @Deprecated 所标注内容,不再被建议使用。
@Override    -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
@Documented  -- @Documented 所标注内容,可以出现在javadoc中。
@Inherited   -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。@Retention   -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
@Target      -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
@SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。


创建自定义注解和创建一个接口相似,但是注解的interface关键字需要以@符号开头。

  • 注解方法不能带有参数;
  • 注解方法返回值类型限定为:基本类型、String、Enums、Annotation或者是这些类型的数组;
  • 注解方法可以有默认值;
  • 注解本身能够包含元注解,元注解被用来注解其它注解。
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
 String name () default "";
}

注解是通过反射获取的,可以通过Class 对象的isAnnotationPresent()方法判断它是否应用了某个注解,再通过getAnnotation()方法获取Annotation 对象

java 修饰限定符

  • public :公共权限
  • private:私有权限,同个类可以访问
  • protected:受保护权限,同包及不同包的子类可以访问
  • default:默认权限,同包下都能访问
    在这里插入图片描述

utf-8 编码中的中文占几个字节;int 型几个字节?

utf-8 是一种变长编码技术,utf-8 编码中的中文占用的字节不确定,可能2 个、3 个、4
个,int 型占4 个字节

Java 的异常体系

Java 中Throwable 是所有异常和错误的超类,两个直接子类是Error(错误)和Exception(异常):

  • Error 是程序无法处理的错误,由JVM 产生和抛出,如OOM、ThreadDeath 等。这些异常
    发生时,JVM 一般会选择终止程序。
  • Exception 是程序本身可以处理的异常,又分为运行时异常(RuntimeException)(也叫Checked Exception) 和非运行时异常( 不检查异常Unchecked Exception) 。运行时异常有NullPointerException\IndexOutOfBoundsException 等,这些异常一般是由程序逻辑错误引起的,应尽可能避免。非运行时异常有IOException\SQLException\FileNotFoundException以及由用户自定义的Exception 异常等。

说说你对Java反射的理解
在运行状态中,对任意一个类,都能知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意一个方法和属性。这种能动态获取信息及动态调用对象方法的功能称为java语言的反射机制。
反射的作用:开发过程中,经常会遇到某个类的某个成员变量、方法或属性是私有的,或只对系统应用开放,这里就可以利用java 的反射机制通过反射来获取所需的私有成员或是方法。

  • 获取类的Class 对象实例Class clz = Class.forName(“com.zhenai.api.Apple”);
  • 根据Class 对象实例获取Constructor 对象Constructor appConstructor = clz.getConstructor();
  • 使用Constructor 对象的newInstance方法获取反射类对象Object appleObj = appConstructor.newInstance();
  • 获取方法的Method 对象Method setPriceMethod = clz.getMethod(“setPrice”, int.class);
  • 利用invoke 方法调用方法setPriceMethod.invoke(appleObj, 14);
  • 通过getFields()可以获取Class 类的属性,但无法获取私有属性,而getDeclaredFields()可以获取到包括私有属性在内的所有属性。带有Declared 修饰的方法可以反射到私有的方法,没有Declared 修饰的只能用来反射公有的方法,其他如Annotation\Field\Constructor 也是如此。

Java获取反射的三种方法

  • 通过new对象实现反射机制
  • 通过路径实现反射机制
  • 通过类名实现反射机制
public class Student {

private int id;

String name;

protected boolean sex;

public float score;

}

public class Get {

//获取反射机制三种方式

public static void main(String[] args) throws ClassNotFoundException {

//方式一(通过建立对象)

Student stu = new Student();

Class classobj1 = stu.getClass();

System.out.println(classobj1.getName());

//方式二(所在通过路径-相对路径)

Class classobj2 = Class.forName("fanshe.Student");

System.out.println(classobj2.getName());

//方式三(通过类名)

Class classobj3 = Student.class;

System.out.println(classobj3.getName());

}

}

Java 中String 的了解

  • String 类是final 型,固String 类不能被继承,它的成员方法也都默认为final 方法。String对象一旦创建就固定不变了,对String 对象的任何改变都不影响到原对象,相关的任何改变操作都会生成新的String 对象。
  • String 类是通过char 数组来保存字符串的,String 对equals 方法进行了重定,比较的是值相等
  • String保存于字符串常量池

String 为什么要设计成不可变的?

  • 字符串常量池需要String 不可变。因为String 设计成不可变,当创建一个String 对象时,若此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。如果字符串变量允许必变,会导致各种逻辑错误,如改变一个对象会影响到另一个独立对象。
  • String 对象可以缓存hashCode。字符串的不可变性保证了hash 码的唯一性,因此可以缓存String 的hashCode,这样不用每次去重新计算哈希码。在进行字符串比较时,可以直接比较hashCode,提高了比较性能。
  • 安全性。String 被许多java 类用来当作参数,如url 地址,文件path 路径,反射机制所需的Strign 参数等,若String 可变,将会引起各种安全隐患

list和set区别
都是继承自collection接口
List 特点:元素有放入顺序,元素可重复;
Set 特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode 决定的,其位置其实是固定的,加入Set 的Object 必须定义equals
()方法,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)

Set和List对比
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变

final finally finalize

final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。

finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。

finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的最后判断

对象的四种引用强
强引用:只要引用存在,垃圾回收器永远不会回收

Object obj = new Object();

User user=new User();

软引用:非必须引用,内存溢出之前进行回收.软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。

Object obj = new Object();

SoftReference<Object> sf = new SoftReference<Object>(obj);

obj = null;

sf.get();//有时候会返回null

弱引用:第二次垃圾回收时回

Object obj = new Object();

WeakReference<Object> wf = new WeakReference<Object>(obj);

obj = null;

wf.get();//有时候会返回null

wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾

ThreadLocal 中有使用到弱引用,

public class ThreadLocal<T> {
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
//....
}
//.....
}

虚引用:垃圾回收时回收,无法通过引用取到对象值,可以通过如下代码实现.虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。虚引用主要用于检测对象是否已经从内存中删除。

Object obj = new Object();

PhantomReference<Object> pf = new PhantomReference<Object>(obj);

obj=null;

pf.get();//永远返回null

pf.isEnQueued();//返回是否从内存中已经删除

LinkedHashMap 的应用
key有序,按插入顺序和访问顺序(accessOrder=true,顺序,最多访问在最后)
基于LinkedHashMap 的访问顺序的特点,可构造一个LRU(Least Recently Used) 最近最少使用简单缓存。也有一些开源的缓存产品如ehcache 的淘汰策略( LRU )就是在LinkedHashMap 上扩展的。

Cloneable 接口实现原理

Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就会抛出CloneNotSupportedException。

浅克隆(shallow clone),浅克隆是指拷贝对象时仅仅copy对象本身和对象中的基本变量,而不拷贝对象包含的引用指向的对象。深克隆(deep clone),不仅copy对象本身,而且copy对象包含的引用指向的所有对象。

深克隆(deep clone),不仅copy对象本身,而且copy对象包含的引用指向的所有对象。

  • Apache Commons Lang 的SerializationUtils.clone(object)
  • spring BeanUtils.copyProperties(source, target);

sleep 和wait区别

  • sleep 来自Thread 类,和wait 来自Object 类。
  • 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
  • wait,notify和notifyAll 只能在同步控制方法或者同步控制块里面使用,而sleep 可以在任何地方使用(使用范围)
  • sleep 必须捕获异常,而wait , notify 和notifyAll 不需要捕获异常

数组在内存中如何分配

对于Java 数组的初始化,有以下两种方式

静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。

动态初始化:初始化时由程序员显示的指定数组的长度,由系统为数据每个元素分配初始值。

//只是指定初始值,并没有指定数组的长度,但是系统为自动决定该数组的长度为3
String[] names = new String[]{"多啦A梦", "大雄", "静香"}; 

//只是指定了数组的长度,并没有显示的为数组指定初始值,但是系统会默认给数组数组元素分配初始值为null(不同数据类型有不一样的值)
String[] cars = new String[4]; 

集合现成安全

Java线程安全的集合详解

琐机制,类锁,方法锁,和双重锁的区别

  • 类锁:synchronized用于类的静态方法上或静态代码块上
  • 对象锁:synchronized修饰方法或代码块(当一个对象中有synchronized method或synchronized block的时候调用此对象的同步方法或进入其同步区域时,就必须先获得对象锁。如果此对象的对象锁已被其他调用者占用,则需要等待此锁被释放)
  • 方法锁:用synchronized修饰方法,要是一种对象锁。
  • 双重锁:单例模式里有用,先检查是否初始化,在上锁,在检查是否初始化,没有就初始话(不懂是不是这个)
类锁

1.静态代码块
synchronized static {
//代码块执行内容
}
2.静态方法
public synchronized static void method(){
}

3.类
 synchronized (Singleton.class){
 }
 
对象锁

1.synchronized (this){
}
2.
Obejct object =new Object();
synchronized (object){
//内容
}

双重锁:
单例模式
public class Singleton { 
private static Singleton uniqueSingleton; 
private Singleton() { } 

public Singleton getInstance() { 
 if (null == uniqueSingleton) { 
  synchronized (Singleton.class) { 
   if (null == uniqueSingleton) { 
    uniqueSingleton = new Singleton(); } 
    } 
  } 
  return uniqueSingleton; } 
 }

Spring

1.BeanFactory 和 ApplicationContext 有什么区别
BeanFactory

  • 含有bean集合的工厂类。BeanFactory 包含了各种bean的定义,以及对bean实例化(通过BeanDefinition加载bean配置信息–类名,属性,是否延迟加载等,在通过
    BeanDefinitionRegistry将这些bean注册到beanFactory中)。
  • BeanFactory还能在实例化对象的时生成协作类之间的关系。此举将bean自身与bean客户端的配置中解放出来。
  • BeanFactory还包含了bean生命周期的控制,调用客户端的初始化方法(initialization methods)和销毁方法(destruction methods)。

Spring源码解析:BeanFactory深入理解

ApplicationContext
如同bean factory一样具有bean定义、bean关联关系的设置,根据请求分发bean的功能。但application context在此基础上还提供了其他的功能。

  • 提供了支持国际化的文本消息
  • 统一的资源文件读取方式
  • 已在监听器中注册的bean的事件

Spring AOP 实现原理

Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和CGLIB 动态代理。JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是InvocationHandler 接口和Proxy 类。
如果目标类没有实现接口,那么Spring AOP 会选择使用CGLIB 来动态代理目标类。CGLIB (Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为final, 那么它是无法使用CGLIB 做动态代理的。

Spring MVC 运行流程

  1. spring mvc将所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求进行真正的处理工作。
  2. DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.
  3. DispatcherServlet将请求提交到目标Controller
  4. Controller进行业务逻辑处理后,会返回一个ModelAndView
  5. Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象
  6. 视图对象负责渲染返回给客户端

Spring 的单例实现原理

Spring 对 Bean 实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是 ConcurrentHashMap 对象

Spring的单例实现原理

Spring 框架中用到了哪些设计模式

  • 代理模式—在AOP和remoting中被用的比较多。
  • 单例模式—在spring配置文件中定义的bean默认为单例模式。
  • 模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
  • 前端控制器—Spring提供了DispatcherServlet来对请求进行分发。
  • 视图帮助(View Helper )—Spring提供了一系列的JSP标签,高效宏来辅助将分散的代码整合在视图里。
  • 依赖注入—贯穿于BeanFactory / ApplicationContext接口的核心理念。
  • 工厂模式—BeanFactory用来创建对象的实例。

IOC(控制反转)和 DI(依赖注入)

  • IOC(Inversion of Control,控制反转):这是spring的核心,贯穿始终。所谓IOC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。
  • DI(依赖注入):IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的

SpringCloud

SpringCloud面试题及答案

zookeeper

jvm

1.哪些情况下的对象会被垃圾回收机制处理掉?
利用可达性分析算法,虚拟机会将一些对象定义为GC Roots,从GC Roots 出发沿着引用链
向下寻找,如果某个对象不能通过GC Roots 寻找到,虚拟机就认为该对象不可达;如果对象没有重载finalize()方法,jvm就会直接回收该对象,如果对象重载了finalize()方法,但是没有执行过finalize()方法,jvm会把对象放到F-Queue,由一个低优先级的线程去执行该对象的finalize方法。执行完finalize方法完毕后,GC会再次判断对象是否可达,若不可达,则进行回收,如果可达,该对象会复活,被移除这个队列。
2.哪些对象会被看为GC Root?

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中的类静态属性引用的对象,常量引用的对象;
  • 本地方法栈中JNI(Native 方法)引用的对象
    3.类加载过程?
    java 类加载采用双亲委派模式:
    如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需要加载的类)时,子加载器才会尝试自己去加载。
    使用双亲委托机制的好处是:能够有效确保一个类的全局唯一性,当程序中出现多个限定名相同的类时,类加载器在执行加载时,始终只会加载其中的某一个类。

在这里插入图片描述

  • BootstrapClassLoader(启动类加载器):负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,加载System.getProperty(“sun.boot.class.path”)所指定的路径或jar。
  • ExtensionClassLoader(标准扩展类加载器):负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/* .jar或-Djava.ext.dirs指定目录下的jar包。System.getProperty(“java.ext.dirs”)所指定的路径或jar。负责记载classpath中指定的jar包及目录中class
  • AppClassLoader(系统类加载器):负责记载classpath中指定的jar包及目录中class
  • CustomClassLoader(自定义加载器):属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现。

如何自定义类加载器用途和如何定义?
用途:自定义类加载器,可以实现对类的加解密操作。
自定义类加载器: 继承ClassLoader类,重载findClass()方法

谈谈你对解析与分派的认识

  • 解析指方法在运行前,即编译期间就可知的,有一个确定的版本,运行期间也不会改变。解
    析是静态的,在类加载的解析阶段就可将符号引用转变成直接引用。
  • 分派可分为静态分派和动态分派,重载属于静态分派,覆盖属于动态分派。静态分派是指在重载时通过参数的静态类型而非实际类型作为判断依据,在编译阶段,编译器可根据参数的静态类型决定使用哪一个重载版本。动态分派则需要根据实际类型来调用相应的方法。

kafka

kafka 的message 包括哪些信息
个Kafka 的Message 由一个固定长度的header 和一个变长的消息体body 组成。
header 部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body 消息体是否正常)构成。当magic 的值为1 的时候,会在magic 和crc32 之间多一个字节的数据:
attributes(保存一些相关属性,比如是否压缩、压缩格式等等);如果magic 的值为0,那么不存在attributes 属性body 是由N 个字节构成的一个消息体,包含了具体的key/value 消息
怎么查看kafka 的offset
1.可以用最新的Consumer client 客户端,consumer.seekToEnd() / consumer.position() 可以用于得到当前最新的offset
2.通过kafka manager等工具能看到

hadoop

hadoop mapReduce过程

hadoop 的shuffle 过程
1.Map 端的shuffle
Map 端会处理输入数据并产生中间结果,这个中间结果会写到本地磁盘,而不是HDFS。
每个Map 的输出会先写到内存缓冲区中,当写入的数据达到设定的阈值时,系统将会启动一个线程将缓冲区的数据写到磁盘,这个过程叫做spill。在spill 写入之前,会先进行二次排序,首先根据数据所属的partition 进行排序,然后每个partition 中的数据再按key 来排序。partition 的目是将记录划分到不同的Reducer上去,以期望能够达到负载均衡,以后的Reducer 就会根据partition 来读取自己对应的数据。接着运行combiner(如果设置了的话),combiner 的本质也是一个Reducer,其目的是对将要写入到磁盘上的文件先进行一次处理,这样,写入到磁盘的数据量就会减少。最后将数据写到本地磁盘产生spill 文件(spill 文件保存在{mapred.local.dir}指定的目录中,Map 任务结束后就会被删除)。

最后,每个Map 任务可能产生多个spill 文件,在每个Map 任务完成前,会通过多路归并算法将这些spill 文件归并成一个文件。至此,Map 的shuffle 过程就结束了。

2.Reduce 端的shuffle
Reduce 端的shuffle 主要包括三个阶段,copy、sort(merge)和reduce。
首先要将Map 端产生的输出文件拷贝到Reduce 端,但每个Reducer 如何知道自己应该处理哪些数据呢?因为Map 端进行partition 的时候,实际上就相当于指定了每个Reducer 要处理的数据(partition 就对应了Reducer),所以Reducer 在拷贝数据的时候只需拷贝与自己对应的partition 中的数据即可。每个Reducer 会处理一个或者多个partition,但需要先将自己对应的partition 中的数据从每个Map 的输出结果中拷贝过来。

接下来就是sort 阶段,也成为merge 阶段,因为这个阶段的主要工作是执行了归并排序。从Map 端拷贝到Reduce 端的数据都是有序的,所以很适合归并排序。最终在Reduce端生成一个较大的文件作为Reduce 的输入。

最后就是Reduce 过程了,在这个过程中产生了最终的输出结果,并将其写到HDFS上。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值