面试题总结-Java基础

*号开头,表示在面试中真实碰到过
*1.面向对象五大基本原则(S.O.L.I.D)
答:1.单一职责原则SRP(Single Responsibility Principle)
规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。
2.开放封闭原则OCP(Open-Close Principle)
软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的3.里氏替换原则 LSP(the Liskov Substitution Principle)
子类对象能够替换父类对象被使用。
4.接口分离原则 ISP (the Interface Segregation Principle)
模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来。
5.依赖反转原则DIP (the Dependency Inversion Principle)
是指一种特定的解耦(传统的依赖关系创建在高层次上,而具体的策略设置则应用在低层次的模块上)形式,使得高层次的模块不依赖于低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低层次模块依赖于高层次模块的需求抽象。

*2. Java中stack和heap的区别
答:1.Stack是栈,Heap是堆
2.存储数据不同,堆存储的是对象实例,栈中存储的是基本数据类型、指令代码、常量以及对象的引用地址
3.回收方式不同,堆中数据是由垃圾回收GC负责,栈中数据由系统自动释放
4.堆是在运行时动态分配内存,存取速度较慢,而栈不是,其数据可以共享,且存取速度较快

*3.volatile关键字能保证对变量操作的原子性吗?
答:不能,一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。其原因是使用volatile关键字会强制将某线程修改的值立即写入主存,其他线程读取时会去读取主存内最新的数据,而不是缓存中的数据。
但对该变量进行非原子性操作(如自增操作),则不能保证变量的原子性。

4.ArrayList与LinkList的区别
答:ArrayList 采用的是数组形式来保存对象的,这种方式将对象放在连续的位置中,所以最大的缺点就是插入删除时非常麻烦
LinkedList 采用的将对象存放在独立的空间中,而且在每个空间中还保存下一个链接的索引 但是缺点就是查找非常麻烦 要丛第一个索引开始

5.Linux下如何查看/监控JVM内存?
答:-全局可以用top
-细节有界面可用jvisualvm
-细节无界面可用jmap dump到文件中去查看

6.对Java异常的理解
答:在 Java 中,所有的异常都有一个共同的祖先 Throwable类。
这里写图片描述
图为Java异常类层次结构图
Throwable: 有两个重要的子类:Exception(异常)和 Error(错误)。
Error(错误):是程序无法处理的错误,如OOM(OutOfMemoryError)、StackOverFlowError。
Exception(异常):是程序本身可以处理的异常。分为运行时异常和受检异常。
运行时异常,非受检异常,编译时无法发现的异常,一般是由程序逻辑错误引起的。如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)、ClassNotFoundException、 ArithmeticException、IllegalArgumentException (非法参数异常)等。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
受检异常:编译时即可检查出来,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException、FileNotFoundException等以及用户自定义的Exception异常。
*7.简述ArrayList的实现原理
答:ArrayList是List接口的可变数组的实现。(数组+容量+扩容+拷贝)
对于ArrayList而言,它实现List接口、底层使用数组保存所有元素。 每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。
每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。
这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。

8.简述ConcurrentHashMap的实现原理
答:HashMap不是线程安全的,不能用于并发。
HashTable是线程安全的, HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。
ConcurrentHashMap所使用的分段加锁技术,首先将数据Hash成16段(default),然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,有效的提高了并发访问效率

9.抽象类(abstract class)和接口(interface)有什么异同?
答:1.抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。
2.一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。
3.接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。
4.抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。
5.有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

10.关键字final、关键字finally、finalize方法
答:1) final修饰变量、方法、类时不同:
基本类型变量:该变量值不能被修改
引用(reference)变量:不可更改指向对象,但该对象的值可以被更改
方法:该方法不能被重写(override)
类:该类不能被继承
2) finally,与try/catch语句块配合使用,无论是否发生异常,finally中的语句块都会被执行(即使try语句块里有return,finally里的语句也还是会执行,就是这么任性~~)
3) finalize(),垃圾回收时会调用此方法。因此,一个类可以重写Object类的finalize()方法,以定义在垃圾回收时的特定行为(如关闭已打开的文件、释放资源等)

11.从继承的角度看,将构造函数声明为private有何作用?
答:将构造函数声明为private,可以确保该类以外的类不能实例化本类。
由于构造函数是私有的,该类不可被继承。

*12.用过Object吗?什么情况下用?
答:Object在实例化时是可以指定为各种类型的,当写一个方法然而并不知道该返回什么类型或者传入的参数会是什么类型的时候就可以考虑使用。

13.Java一些常用的集合框架(collection framework)
答:ArrayList,可动态调整大小的数组
Vector,与ArrayList类似,但其可同步
LinkedList,与迭代器配合使用
HashMap,你懂的。

14.Java中常用的类、包、借口
类:String、Integer、HashMap、ArrayList、StringBuffer
包:
java.util.*
java.lang.*
java.sql.*
java.io.*
java.math.*
java.text.*
接口:Runnable、Iterable、Map、Set、List、Collection

15.用Java实现单例模式
答:public class Aclass{
private Aclass(){}
private static Aclass instance=new Aclass();
public Aclass getInstance(){
return instance;
}
}

注意:实现一个单例有两点注意事项:
①将构造器私有,不允许外界通过构造器创建对象;
②通过公开的静态方法向外界返回类的唯一实例。

16.Java中的对象反射是什么?它有什么用?
答:对象反射(Object Reflection)是Java的一项特性,提供了获取类和对象反射信息的方法。可以:
1、运行时取得类的方法和字段的信息–有助于观察或操纵应用程序的运行时行为。
2、可以创建某个类的新实例,可以直接访问方法和成员变量–有助于调试或测试信息
3、可以通过名字调用方法,如让用户传入类名、构造函数的参数和方法1名,我们就可以使用该信息创建对象,并调用方法。

17.如何通过反射创建对象?
- 方法1:通过类对象调用newInstance()方法,例如:

Class myString=Class.forName("String");
myString.newInstance() 

-方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:

Class myString=Class.forName("String");
String instance=myString.getConstructor(String.class).newInstance("Hello");

18.如何通过反射调用对象的方法?
答:使用getDeclaredMethod获取方法,使用invoke调用方法。

Class myString=Class.forName("String");
String instance=myString.getConstructor(String.class).newInstance("Hello");
Method m=myString.getDeclaredMethod("methodName");//获取方法
String s=m.invoke(instance);//调用方法

19.如何通过反射获取和设置对象私有字段的值?
答:可以通过类对象的getDeclaredField()方法字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。
详见http://blog.csdn.net/jackfrued/article/details/44921941
20.请问以下输出的是什么

Long a = 5L;
Long b = 5L;

System.out.println(a==b);//-128~127, 直接引用常量池中的Long对象
Long x = new Long(5L);
Long y = new Long(5L);

System.out.println(x==y);//不是同一个对象

Long _a = 129L;
Long _b = 129L;

System.out.println(_a==_b);//>=128,新建对象

Long _x = 5L;
long _y = 5L;

System.out.println(_x==_y);//Long拆箱成long后比较

true
false
false
true
知识点:装箱和拆箱

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值