Java面试题之Java基础、关键字、面向对象

欢迎访问我的个人博客,欢迎留言,我会尽最大努力分享我的笔记和回复大家问题

文章目录

java基础

1. int和Integer有什么区别?

​ 答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。

2.请你说明String 和StringBuffer的区别

​ 答:JAVA 平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地,你可以使用StringBuffers来动态构造字符数据。

3.请你讲讲数组(Array)和列表(ArrayList)的区别?什么时候应该使用Array而不是ArrayList?

答:Array和ArrayList的不同点:

Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
Array大小是固定的,ArrayList的大小是动态变化的。
ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

4.请你解释为什么会出现4.0-3.6=0.40000001这种现象?

​ 答:原因简单来说是这样:2进制的小数无法精确的表达10进制小数,计算机在计算10进制小数的过程中要先转换为2进制进行计算,这个过程中出现了误差。

5. 请你说说Lamda表达式的优缺点。

​ 答:

​ 优点:1. 简洁。2. 非常容易并行计算。3. 可能代表未来的编程趋势。

​ 缺点:1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行 计算有时需要预热才显示出效率优势)2. 不容易调试。3. 若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。

6.请你说明符号“==”比较的是什么?

​ 答:”对比两个对象基于内存引用,如果两个对象的引用完全相同(指向同一个对象)时,“”操作将返回true,否则返回false。“==”如果两边是基本类型,就是比较数值是否相等。

7. 请你解释Object若不重写hashCode()的话,hashCode()如何计算出来的?

​ 答:hashCode()默认是返回对象的内存地址

8.请你解释为什么重写equals还要重写hashcode?

​ 答:HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等的。若equals()不相等则认为他们不相等。

hashCode比较两个对象的内存地址是否相同

equals则是比较两个对象是否属于同一个类,然后在比较对象的值

9.请你介绍一下map的分类和常见的情况

​ 答:

​ java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap.

​ Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖),但允许值重复。

​ Hashmap 是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。 HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。

​ Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。

​ LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关

​ TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

​ 一般情况下,我们用的最多的是HashMap,在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。如果需要输出的顺序和输入的相同,那么用LinkedHashMap 可以实现,它还可以按读取顺序来排列.

关键字

1.请你讲讲Java里面的final关键字是怎么用的?

如果修饰类的话,表示这个类不能被继承,这个时候该类的成员方法也会被隐式的指定为final方法

如果修饰的方法的话,表示这个方法被锁定,任何继承类都无法修改它的含义,无法重写它

如果修饰的是变量,基础类型变量的话一但被初始化,那么它的值永远都无法更改,如果是引用类型变量,那么初始化以后它无法指向其他任何对象

2.请你谈谈关于Synchronized和lock

synchronized是Java的关键字,当它修饰一个方法或者一个代码块的时候,能够在同一时刻最多只有一个线程执行该段代码。

Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

3.请你介绍一下volatile?

volatile 变量的内存可见性是基于内存屏障(Memory Barrier)实现

  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性)
  • 禁止进行指令重排序。(实现有序性)
4.请你介绍一下Syncronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?

synchronized修饰静态方法以及同步代码块的synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。

synchronized修饰成员方法,线程获取的是当前调用该方法的对象实例的对象锁。

面向对象

1.请解释Java中的概念,什么是构造函数?什么是构造函数重载?什么是复制构造函数?

​ 当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java编译器会为这个类创建一个默认的构造函数。

​ Java中构造函数重载和方法重载很相似。可以为一个类创建多个构造函数。每一个构造函数必须有它自己唯一的参数列表。
​ Java不支持像C++中那样的复制构造函数,这个不同点是因为如果你不自己写构造函数的情况下,Java不会创建默认的复制构造函数。

2.请判断,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,该说法是否正确,为什么?

​ 不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:

​ (1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;

​ (2)如果两个对象的hashCode相同,它们并不一定相同。

3.请你说说Static Nested Class 和 Inner Class的不同

​ Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。Static-Nested Class 的成员, 既可以定义为静态的(static), 也可以定义为动态的(instance).Nested Class的静态成员(Method)只能对Outer Class的静态成员(static memebr)进行操作(ACCESS), 而不能Access Outer Class的动态成员(instance member).而 Nested Class的动态成员(instance method) 却可以 Access Outer Class的所有成员, 这个概念很重要, 许多人对这个概念模糊. 有一个普通的原则, 因为静态方法(static method) 总是跟 CLASS 相关联(bind CLASS), 而动态方法( (instance method) 总是跟 instance object 相关联, 所以,静态方法(static method)永远不可以Access跟 object 相关的动态成员(instance member),反过来就可以, 一个CLASS的 instance object 可以 Access 这个 Class 的任何成员, 包括静态成员(static member).

4. 请你讲讲abstract class和interface有什么区别?

​ 抽象类和接口的区别:

  • 一个类只能继承一个抽象类,但是可以实现多个接口
  • 接口只能做方法的声明,抽象类可以作方法的声明,也可以直接实现方法
  • 接口里定义的变量是公开的静态变量,抽象类可以定义普通的变量
  • 抽象类主要用来抽象类别,接口主要用来抽象功能
  • 接口的抽象级别最高
  • 接口是设计的结果,抽象类是重构的结果
5.说明Overload和Override的区别

​ 重载是指在同一个类中,多个相同名称的方法,他们具有不同的参数列表(参数类型不一样或者参数数量不同即可),它们的返回值可以相同也可以不同。

​ 重写是子类对父类的方法进行覆写,方法名一样,参数列表也必须一样(如果不一样的话就成了重载),访问权限不能比父类更加限制,返回类型必须和父类一致。总体来说重写父类方法就是只能更改方法体。

6. 请你谈谈如何通过反射创建对象?

​ 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()

​ 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).
newInstance(“Hello”);

7.请你说明是否可以在static环境中访问非static变量?

​ static变量在Java中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。

8.请解释一下extends 和super 泛型限定符和?通配符

​ 上界<? extend Fruit> ,只支持get。表示所有继承Fruit的子类,但是具体是哪个子类,无法确定,所以调用add的时候,要add什么类型,谁也不知道。但是get的时候,不管是什么子类,不管追溯多少辈,肯定有个父类是Fruit,所以,我都可以用最大的父类Fruit接着,也就是把所有的子类向上转型为Fruit。

​ 下界<? super Apple>,只支持add。表示Apple的所有父类,包括Fruit,一直可以追溯到老祖宗Object 。那么当我add的时候,我不能add Apple的父类,因为不能确定List里面存放的到底是哪个父类。但是我可以add Apple及其子类。因为不管我的子类是什么类型,它都可以向上转型为Apple及其所有的父类甚至转型为Object 。但是当我get的时候,Apple的父类这么多,我用什么接着呢,除了Object,其他的都接不住。

​ ?泛型通配符,表示任意泛型,既然?代表任意泛型,那么换句话说,你就不知道这个容器里面是什么类型,所以只能以Object的形式取出来,容器里既然什么类型都存在自然不能add对象,放任何对象都有风险

​ 所以,归根结底可以用一句话表示,那就是编译器可以支持向上转型,但不支持向下转型。具体来讲,我可以把Apple对象赋值给Fruit的引用,但是如果把Fruit对象赋值给Apple的引用就必须得用cast。

9.介绍一下类的加载机制以及双亲委派模型

​ 类的加载过程:

  • 加载:查找并加载类的二进制数据(class文件)
    • 方法区:类的类信息
    • 堆:Class文件对应的类的实例
  • 验证:确保加载的类信息是正确的
  • 准备:为类的静态变量进行初始化,分配空间并赋值
  • 解析:将符号引用转换为直接引用
  • 初始化:JVM对类进行初始化,对静态变量赋予正确值

类加载器:

​ BootstrapLoader(C语言写的)

​ |_(JDK/JRE/LIB java.)

​ ExtClassLoader

​ |_(JDK/JRE/LIB/EXT javax.)

​ AppClassLoader

​ |_自己定义的类,类路径下面

​ 用户自定义类加载器

​ |_流、网络、数据库

​ 双亲委派模型:

​ 某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

10. 请你谈谈StringBuffer和StringBuilder有什么区别,底层实现上呢?

​ StringBuffer线程安全,StringBuilder线程不安全,底层实现上的话,StringBuffer其实就是比StringBuilder多了Synchronized修饰符。

猜你喜欢

转载自blog.csdn.net/xdxx152/article/details/108520750