学习啦 > 创业指南 > 职场 > 面试题 > 阿里JAVA开发面试常问问题

阿里JAVA开发面试常问问题

时间: 护托1061 分享

阿里JAVA开发面试常问问题

  Java中没有虚函数的概念。它的普通函数就相当于c++的虚函数,动态绑定是java的默认行为。下面就由学习啦小编为大家介绍一下阿里JAVA开发面试常问问题的文章,欢迎阅读。

  阿里JAVA开发面试常问问题篇1

  栈内存、堆内存

  在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。

  堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因。

  引用、值传递

  值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参数的值。

  引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。

  单例模式及好处

  构造函数私有化,用一个静态方法来获取对象实例。

  特点:

  1)单例类只能有一个实例。

  2)单例类必须自己创建自己的唯一实例。

  3)单例类必须给所有其他对象提供这一实例。

  主要优点:

  1)提供了对唯一实例的受控访问。

  2)由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。

  3)允许可变数目的实例。

  主要缺点:

  1)由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

  2)单例类的职责过重,在一定程度上违背了“单一职责原则”。

  3)滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

  阿里JAVA开发面试常问问题篇2

  重载和重写

  重载:Overloading

  (1) Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。

  (2) 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回类型作为重载函数的区分标准。

  重写:Overriding

  注意:当要重写父类方法时,要使用@Override标签提醒编译器检查代码是否是重写,而不是重载了原来的方法。

  (1) 父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。

  (2)若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。

  (3)子类函数的访问修饰权限不能少于父类的。

  子类、父类间的转换和构造顺序

  子类、父类间的转换:

  子类能够自动转换成父类类型。

  当创建子类对象的时候:

  ①先调用了子类的构造函数

  ②调用了父类的构造函数

  ③执行了父类的构造函数

  ④执行了子类的构造函数

  Final、finally、finalize

  final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。

  finally是异常处理语句结构的一部分,表示总是执行。

  finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等

  Synchronized和volatile的区别

  volatile只作用于在多个线程之间能够被共享的变量。如果一个字段被声明成volatile,java线程内存模型确保所有线程看到这个变量的值是一致的。Volatile变量修饰符如果使用恰当的话,它比synchronized的使用和执行成本会更低,因为它不会引起线程上下文的切换和调度。

  synchronized获得并释放监视器——如果两个线程使用了同一个对象锁,监视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是,synchronized也同步内存:事实上,synchronized在“ 主”内存区域同步整个线程的内存。

  因此volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。

  1)volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取,没有互斥锁;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

  2)volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的

  3)volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值;显然synchronized要比volatile消耗更多资源。

  4)volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

  5)volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化 。

  阿里JAVA开发面试常问问题篇3

  集合类没有实现Cloneable和Serializable接口的原因

  Collection接口指定一组对象,对象即为它的元素。如何维护这些元素由Collection的具体实现决定。例如,一些如List的Collection实现允许重复的元素,而其它的如Set就不允许。很多Collection实现有一个公有的clone方法。然而,把它放到集合的所有实现中也是没有意义的。这是因为Collection是一个抽象表现。重要的是实现。

  当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。

  在所有的实现中授权克隆和序列化,最终导致更少的灵活性和更多的限制。特定的实现应该决定它是否可以被克隆和序列化。

  hashCode()和equals()方法的重要性体现在什么地方?

  HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重要。

  equals()和hashCode()的实现应该遵循以下规则:

  (1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。

  (2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。

  Java中的HashMap使用hashCode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对HashMap的精确性和正确性是至关重要的。

  HashMap和HashTabel的区别

  HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点:

  1)HashMap允许键和值是null,而Hashtable不允许键或者值是null。

  2)Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。

  3)HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面,Hashtable提供了对键的列举(Enumeration)。

  一般认为Hashtable是一个遗留的类。

  Comparable和Comparator接口

  Comparable和Comparator都是用来实现集合中的排序的,只是Comparable是在集合内部定义的方法实现的排序,Comparator是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义Comparator接口的方法compare()或在集合内实现Comparable接口的方法compareTo()。

  comparable是支持自比较,而后者是支持外部比较;

  Comparable是一个对象本身就已经支持自比较所需要实现的接口(如String、Integer自己就可以完成比较大小操作)

  而Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。

  也就是说当你需要对一个自定义的类的一个数组或者集合进行比较的时候可以实现Comparable接口,当你需要对一个已有的类的数组或者集合进行比较的时候就一定要实现Comparator接口。另外,这两个接口是支持泛型的,所以我们应该在实现接口的同时定义比较类型。

  Java中HashMap的工作原理是?

  Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。

  1)HashMap有一个叫做Entry的内部类,它用来存储key-value对。

  2)上面的Entry对象是存储在一个叫做table的Entry数组中。

  3)table的索引在逻辑上叫做“桶”(bucket),它存储了链表的第一个元素。

  4)key的hashcode()方法用来找到Entry对象所在的桶。

  5)如果两个key有相同的hash值,他们会被放在table数组的同一个桶里面。

  6)key的equals()方法用来确保key的唯一性。

  7)value对象的equals()和hashcode()方法根本一点用也没有。

  重点内容

  Put:根据key的hashcode()方法计算出来的hash值来决定key在Entry数组的索引。

  Get:通过hashcode找到数组中的某一个元素Entry

  Hashcode的实现

  hashCode 的常规协定是:

  在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

  如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。

  当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

  String、StringBffer、StringBuilder的区别

  1)可变与不可变

  String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。

  private final char value[];

  StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。

  char[] value;

  2)是否多线程安全

  String中的对象是不可变的,也就可以理解为常量,显然线程安全。

  AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。

  StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的

3152971