面试题汇总+常见题型(一)

•(1)面向对象的特征:继承、封装和多态

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
https://blog.csdn.net/sifanvv/article/details/81387668

(2)final, finally, finalize 的区别

虽然这个单词在Java中都存在,但是并没太多关联:
final:java中的关键字,修饰符。
A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。
B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
  1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
  2)被声明final的方法只能使用,不能重载。
finally:java的一种异常处理机制。
finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。
finalize:Java中的一个方法名。
Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

这里关于finally有几个小知识点:

1.try能直接和finally使用,不需要catch。
2. 如果try语句里有return,返回的是try语句块中变量值。 详细执行过程如下: 如果有返回值,就把返回值保存到局部变量中; 执行jsr指令跳到finally语句里执行; 执行完finally语句后,返回之前保存在局部变量表里的值。 如果try,finally语句里均有return,覆盖try的return,而使用finally的return.
      public class Test {
    public static void main(String[] args) {
        System.out.println("return value of getValue(): " +
        getValue());
    }
     public static int getValue() {
         try {
             return 0;
         } finally {
             return 1;
         }
     }
 }

OUT:return value of getValue(): 1

关于finalize() 详情可见《深入理解java虚拟机》p66
当确定对象在可达性算法中被确认是不可到达的时候,只是处于一个正在等待被处理的过程中。若要真正确认死亡还需要被标记俩次。
第一次 在对象被确认不可到达后,被标记即将送入刑场,但还要筛选一次,条件是对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者该方法已经被虚拟机调用过,则此时就没有必要执行,也就意味着对象是不可使用的。
当对象有必要执行finalize()方法时,对象会被放入F-Queen队列中。稍后GC会对对象进行第二次标记。
第二次标记的时候,如果对象成功在finalize()方法中将自己重新赋值给某个类变量或者对象的成员变量,就可以逃出被回收的命运。
但是,一个对象的finalize()方法只能被调用一次!!

• (3)Exception、Error、运行时异常与一般异常有何异同

1、Exception 和 Error 都是继承了 Throwable 类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。
2、Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
3、Error 是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如 OutOfMemoryError 之类,都是 Error 的子类。
4、Exception 又分为可检查(checked)异常和不检查(unchecked/运行时异常)异常,可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。不检查异常就是所谓的运行时异常,类似 NullPointerException、ArrayIndexOutOfBoundsException 之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。
https://blog.csdn.net/m0_37531231/article/details/79502778

在这里,我也遇到过一道类似于文字游戏的题目;
关于异常的描述,以下哪些是正确的
正确答案: A C D

A.异常的基类为Exception,所有异常都必须直接或者间接继承它

B.异常可以随便处理,而不是抛给外层的程序进行处理

C.如果某异常继承RuntimeException,则该异常可以不被声明

D.异常可以用try{ }catch(Exception e){ }来捕获并进行处理

要注意A选项,不要认为所有异常的基类是Throwable。
错误的基类是ERROR,所有异常的父类是throwable,所有异常的基类是Exception

• (4)请写出5种常见到的runtime exception

RuntimeException、NullPointerException、ClassCastException、SecurityException、ClassNotFoundException、ArrayIndexOfBoundsExpetion

• (5)int 和 Integer 有什么区别,Integer的值缓存范围

1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0

Integer的值缓存范围是-128~127
https://www.cnblogs.com/guodongdidi/p/6953217.html

包装类一般问题出在缓冲区和自动拆装箱上,如果没遇到过肯定是要吃亏的。

public class CharTest {
public static void main(String[] args) {
System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));
}
}
/output/
true
false
true

Integer.valueOf()返回的是Integer类型,在-128到127这个数值之间,Integer是从缓存区中拿去数值,==比较的是地址,所以是true;一旦超过127或者小于-128,就相当于new了一个新对象,所以地址不相同。Integer.parseInt()返回的是int,遇到和int基本数据类型发生比较,就会出现自动拆箱, Integer.parseInt(“128”)==Integer.valueOf(“128”)就会变成128= =128.
但是!!要注意一点:Integer t1=50和Integer.valueOf(50)是从缓存中取出数值引用,new Integer(50)就不是了,它是另开辟了内存空间来存储50.
上述问题

https://blog.csdn.net/dawn_after_dark/article/details/74154338

• (6)包装类,装箱和拆箱

基本类型是直接用来存储值的,放在栈中方便快速使用,包装类型是类,其实例是对象,放在堆中
基本类型不是对象,因此没有方法,包装类型是类,因此有方法
基本类型直接赋值即可,包装类型需要使用new关键字创建
包装类型初始值为null,基本类型初始值不为null,是根据类型而定的

http://www.cnblogs.com/dolphin0520/p/3780005.html

• (7)String、StringBuilder、StringBuffer

1、可变与不可变
String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。
2、是否多线程安全
String中的对象是不可变的,也就可以理解为常量,显然线程安全。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的
StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
3、StringBuilder与StringBuffer共同点
StringBuilder与StringBuffer有公共父类AbstractStringBuilder(抽象类)。
StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(…)。只是StringBuffer会在方法上加synchronized关键字,进行同步。
https://www.cnblogs.com/xudong-bupt/p/3961159.html

先来考虑下一个经常见到的问题:String str1 = “abc”; String str2 = new String(“abc”); 区别

JVM的方法区里有个块区域叫做常量池。常量池是干嘛的?它用于存储编译器生成的各种字面量和符号引用,举个例子,String就是放在常量池的。

  1. jvm 首先在字符串常量池内里面看看找不找到字符串"abc;找到,进入第二步;否则,创建新的 String 对象,并“放到”字符串常量池里面。
  2. 然后由于遇到了 new,还会在堆创建 String 对象,其实是拷贝的常量池的那个.最后将其返回给 s1。

public class StringTest {
public static void main(String[] args){
String str1=“a”;
String str2=“a”;
System.out.println(str1==str2); } }
OUT: true

为什么会是true?原因已经很明了了,因为常量池里面已经有了!!就是这么简单。
除了常量池的问题,String由于final修饰的关系有大量的坑去填。

1 String str=“abc”;
2 System.out.println(str);
3 str=str+“de”;
4 System.out.println(str);

如果运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。

String s1 =“abc”;
final String s2 = “ab”;
String s3 = s2 + “c”;
System.out.println(s1==s3); //true

当基本类型与String被final修饰时会被当成常量,在编译时等同于两常量相加,所以为true。

String s1 = “abc”;
String s2 = “ab”;
String s3 = s2 + “c”;
System.out.println(s1==s3); //false

注意一点:String str=“abc”+“de”;和 String str=“abcde”;是完全一样的

想起来还有一类题型,

System.out.println(“is ”+ 100 + 5);
System.out.println(100 + 5 +“ is”);
System.out.println(“is ”+ (100 + 5));

OUT:is 1005, 105 is, is 105

这种题目的解法就是什么时候遇到String,就开始把后面所有的+都当成字符串+处理。当然也要考虑运算顺序的问题。比如()

• (8)重载和重写的区别

方法重载是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同
方法重写是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型
注:
(1)子类中不能重写父类中的final方法
(2)子类中必须重写父类中的abstract方法

https://www.cnblogs.com/upcwanghaibo/p/6527354.html

重载和重写,你可以用专业一点的话,重载是静态分派,编译阶段就知道具体类型,都是在一个类中。要求方法名相同,参数列表不同,和返回值无关。重写是动态分派,运行阶段才知道具体的类型,要符合“二小二同一大”规则。
二小:抛出的异常错误要小于等于父类的方法,返回的类型要小于等于父类的方法。
二同:方法名相同,参数列表相同。
一大:访问的权限要大于等于父类的方法,

• (9)抽象类和接口有什么区别

• 1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
• 2、抽象类要被子类继承,接口要被类实现。
• 3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
• 4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
• 5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
• 6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果
• 7、抽象类里可以没有抽象方法
• 8、如果一个类里有抽象方法,那么这个类只能是抽象类
• 9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
• 10、接口可继承接口,并可多继承接口,但类只能单根继承•

当你简单的阐述上面那些要点之后,你要注意重点讲述下JDK1.8接口的变化!!最重要的就是接口中多了俩种可以有方法体的函数。
一种是static修饰的,另一种是default修饰的方法。

• (10)说说反射的用途及实现

一、Java反射框架主要提供以下功能:
1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
4.在运行时调用任意一个对象的方法
二、主要用途 :
1、反射最重要的用途就是开发各种通用框架。
三、基本反射功能的实现(反射相关的类一般都在java.lang.relfect包里):
1、获得Class对象
使用Class类的forName静态方法,直接获取某一个对象的class, 调用某个对象的getClass()方法
2、判断是否为某个类的实例
用instanceof关键字来判断是否为某个类的实例
3、创建实例
使用Class对象的newInstance()方法来创建Class对象对应类的实例。
先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。
4、获取方法
getDeclaredMethods()
5、获取构造器信息
getDeclaredMethods()
getMethods()
getMethod()
6、获取类的成员变量(字段)信息
getFiled: 访问公有的成员变量
getDeclaredField:所有已声明的成员变量。但不能得到其父类的成员变量
getFileds和getDeclaredFields用法
7、调用方法
invoke()
8、利用反射创建数组
Array.newInstance()

你可能感兴趣的:(面试题)