Java面试题-Java特性
1, 一个类实现了一个接口,需要重载这个接口的所有方法,还是重写这个接口的所有方法?
答案:Override,重写。
引申:
重载(Overload),是指一个类中有多个同名方法,但这些方法有着不同参数,因此可以在编译时决定到底用哪个方法,是一种编译时多态。
重写(Override),子类重写父类方法,导致同样的方法在子类和父类中有着不同的表现形式,而程序调用方法是在运行期动态绑定,是一种运行时多态。
2, 对于一些敏感数据是存储为字符数组还是字符串更安全?
答案:字符数组
引申:
在Java语言中,String是不可变类,它被存储在字符串常量池中,从而实现了字符串的共享,减少了内存的开支。但当这个数据不再使用,它仍会在常量池中存在一段时间,只有垃圾回收器能够回收。因此有权限访问memory dump(存储器转储,将内存中的数据写入到文件)的程序都能访问到这个数据。而字符数组当不用的时候,程序员可以把其内容置空,从而有效的控制了数据的生命周期。
3, volatile关键字有什么作用?
答案:该字段用于修饰被多线程访问的属性,以保证对属性的修改对所有线程可见,每次取到的都是最新的值。
引申:
相比于synchronized,它仅用于修饰字段,且它只保持线程安全三要素中可见性和有序性,并不能保证操作的原子性,所以不能保证严格保证线程安全。
Volatile的实现基于内存栅栏(Memory Barrier),一个volatile字段修改时,JVM会执行一个Write-Barrier
操作,该操作将当前处理器缓存的数据写会系统内存,并使其他CPU核心里引用了该地址的数据变为脏数据。当读取时,JVM会多执行一个Read-Barrier指令,如果该数据已经变脏,如果该数据已经变脏,那么从主存中重新获取数据。
4,Java反射是什么?获取Class对象有哪些方法,他们的区别是什么?
答案:Java中反射是指动态获取类或对象的属性与方法从而完成调用功能的手段。
获取Class对象有三种方式及其特点(区别)为:
l className.class(不执行静态块和动态构造块)
l Class.forName()(执行静态块,不执行动态构造块)
l Object.getClass()(因为需要创建对象,会执行静态块和动态构造块)
引申:
实例化一个类时,对于类中代码的执行顺序(假定A为父类,B继承A,B中main方法实例化B):
1 public class A {
2 public A() {
3 System.out.println("A 类构造方法执行");
4 }
5 {System.out.println("A 类动态代码块执行");}
6 static {System.out.println("A 类静态代码块执行");}
7 }
1 public class B extends A{
2 public B() {
3 System.out.println("B 类构造方法执行");
4 }
5 {System.out.println("B 类动态代码块执行");}
6 static {System.out.println("B 类静态代码块执行");}
7 public static void main(String[] args) {
8 System.out.println("start");
9 new B();
10 System.out.println("end");
11 }
12 /*
13 * A 类静态代码块执行
14 * B 类静态代码块执行
15 * start
16 * A 类动态代码块执行
17 * A 类构造方法执行
18 * B 类动态代码块执行
19 * B 类构造方法执行
20 * end
21 */
22 }
5, 嵌套类(内部类)都有哪些?
答案:内部类主要有四种:静态内部类、成员内部类、局部(方法)内部类、匿名内部类
引申:
静态内部类(static inner class)可以不依赖外部实例而被实例化,不能访问外部类普通成员变量,只能访问外部类中静态成员和静态方法(包括私有类型)。
成员内部类(member inner class)只有当外部类被实例化后才能被实例化,可以自由引用外部类的属性和方法。
局部(方法)内部类(local inner class)指定义在一个代码块内的类,作用范围只在代码块内,访问权限和成员内部类相似。
匿名内部类(anonymous inner class)没有类名,不使用关键字class,内部不能有构造函数,不能定义静态变量、方法和类。必须继承其它类或实现某个接口,访问权限和成员内部类相似。
6,泛型的本质是什么?java中的泛型是真泛型还是伪泛型?为什么这样设计?
答案:泛型的本质是一个参数化类型,为了实现在运行时确定参数的类型而提出。是伪泛型,为了对老程序的向下兼容。
引申:
泛型擦除:Java的泛型不存在于运行时,而是在编译器处理带泛型的类、接口或方法时会在字节码指令中抹去全部泛型类型信息。因此有好多注意的点,比如泛型不能用于方法重载、泛型不能用于自定义异常类,instanceOf后边的类泛型只能用?
1 list instanceOf ArrayList<?> 正确
2 list instanceOf ArrayList<String> 错误
编译器将java源代码编译为字节码(面向JVM的源代码)后,擦除了泛型,但是会在字节码注释中保留一些泛型信息,这些信息称为方法签名,java之所以这样设计,是为了兼容性的考虑,低版本的字节码和高版本基本上只有签名上不一样,不影响功能体,因此低版本的字节码可以不做任何改动就在高版本的虚拟机里运行。因为对List,具体的类型参数信息在编译时都会被擦除,那么<>中的东西显然是不能确定的。
7,java接口可以有方法体吗?这样做的好处是什么?
答案:从jdk1.8开始可以使用default和static关键字最接口中方法添加默认实现和静态实现。好处是降低对接口升级的代价,升级功能只改一下接口的实现即可全部升级。
引申:
从JDK1.9开始,接口不仅能够写带有方法体的方法,还能定义私有方法,目的是为了加强代码重用性,减少冗余,同时实现代码隐藏。
8,java函数式接口都有哪些?
答案:Function、Consumer、Supplier、Predicate
9,简单介绍一下Java访问权限?
答案:java权限大致分为四类:
|
private |
默认访问权限 |
protected |
public |
类本身 |
是 |
是 |
是 |
是 |
相同包中子类 |
否 |
是 |
是 |
是 |
相同包中的非子类 |
否 |
是 |
是 |
是 |
不同包中的子类 |
否 |
否 |
是 |
是 |
不同包中的非子类子类 |
否 |
否 |
否 |
是 |
但是从JDK1.9开始引入模块化概念,模块系统的出现意味着public不是对所有类可见了,如果一个类被修饰为public,那么它只能是在模块内是public的,不能被其它模块访问,除非这个模块被其它模块使用require来引用。这显然增加了程序的封装性。
10,try-with-resources语法JDK7与JDK9有什么区别?
答案:在JDK7中try语句块中不能使用外部声明的任何资源,使用时需要增加一个额外的引用
1 try(InputStream fis1=fis)
JDK9针对这个缺陷进行了改进,try块中可以直接引用外部声明的资源,代码变得更加简洁。
1 try(fis)
11,lambda表达式中takeWhile、dropWhile和Filter的区别与联系?
答案:这三个方法都使用了一个断言(四大核心函数式接口之一的Predicate)作为参数,不同的是takeWhile会返回从头元素开始直到断言语句为false为止的stream子集。DropWhile恰恰相反,直到断言第一次返回true才开始返回直到尾部stream子集。Filter则是返回断言为true的所有元素。