Java基础常见面试题汇总

重载和重写区别

重载:发生在一个类中,方法名相同,参数列表中的参数顺序,类型,个数不同,方法的返回值和修饰符可以一样也可以不一样,存在于编译期间

重写:发生在子类中,子类允许对父类中允许访问的方法进行重新编写。

  1. 返回值类型、方法名、参数列表必须相同,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。
  2. 如果父类方法访问修饰符为 private/final/static 则子类就不能重写该方法,但是被 static 修饰的方法能够被再次声明。
  3. 构造方法无法被重写

构造器能否被重写

不能,重写是子类方法重写父类的方法,重写的方法名不变,而类的构造方法名必须与类名一致,假设父类的构造方法如果能够被子类重写则子类类名必须与父类类名一致才行,所以 Java 的构造方法是不能被重写

 

谈谈Java三大特征

封装

封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。

继承

继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码

多态

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

在 Java 中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

 

String str="abcd"与 String str1=new String("abcd")一样吗?str 和 str1 相等吗?

这两种不同的创建方法是有差别的。

  • 第一种方式先检查字符串常量池中有没有"abcd",如果字符串常量池中没有,则创建一个,然后 str 指向字符串常量池中的对象,如果有,则直接将 str 指向字符串常量池中的"abcd"";

  • 第二种方式是直接在堆内存空间创建一个新的对象。

 

String,StringBuffer,StringBuilder区别?

String中使用了final 声明 char[] values所以不可变,StringBuffer和StringBuilder继承自AbstractStrignBuiler类,没有使用final进行声明,所以可以改变

String由于final修饰,不能更改,不能被继承,所以线程安全

StringBuffer使用synchornized修饰,线程安全,StringBuffer线程不安全

StringBuffer由于synchornized修饰,所以效率低下

 

int和Integer区别

int是原始数据类型,Integer是他的包装类

Integer默认值是null,int默认值是0

两个通过new生成的Integer不会相等,因为new生成的是两个对象

Integer和new Interger不会相等

Integer变量和int变量进行比较,只要两个值相等,结果就为true(因为Integer会自动拆箱)

非new生成的Integer变量和new Integer()生成的变量比较时,结果为false

对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false

 

接口类和抽象类的区别

相同点:

1.两者都能包含抽象方法

2.都是抽象类,不能被实例化

不同点:
接口类需要通过implements关键字进行实现,抽象类需要通过extend进行继承

一个类可以实现多个接口,但是只能继承一个抽象类

接口类中的每一个方法都是抽象方法,都需要被实现类实现,抽象类中可以有选择的实现

接口类的默认修饰符是public,而抽象类中的方法有public、protected 和 default 这些修饰符(抽象方法就是为了被重写所以不能使用 private 关键字修饰!

所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法

 

==和equals区别

==判断的是两个对象的地址值是否相同,即判断两个对象是不是同一个对象,基本数据类型==比较的是值,引用数据类型==比较的是内存地址

equals方法也是判断两个对象,如果equals在当前类没有被重写,那么也是通过==判断地址,如果重写过了,就按照重写的方法进行对比

 

hashcode和equals区别

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的 Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。

hashCode()与 equals()的相关规定

  1. 如果两个对象相等,则 hashcode 一定也是相同的;
  2. 两个对象相等,对两个对象分别调用 equals 方法都返回 true;
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的(不同的对象也可能产生相同的 hashcode,概率性问题);
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

 

什么是反射机制,反射机制的应用场景

JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制

  • 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
  • 缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多

应用场景:

在很多的框架中都用了反射机制,比如Spring框架中对于配置文件中bean的获取,bean对象的动态代理对象等等

通过反射获取对象类的方式?

  • 通过对象.getClass()方式

  • 通过类名.Class 方式

  • 通过Class.forName 方式

 

Java中IO流分为几种

  • 按照流的流向分,可以分为输入流和输出流;
  • 按照操作单元划分,可以划分为字节流和字符流;
  • 按照流的角色划分为节点流和处理流。

IO/NIO/AIO区别

BIO:同步阻塞 I/O 模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机 1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题

NIO:NIO 是一种同步非阻塞的 I/O 模型,在 Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法

AIO:AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作

 

Java中创建对象的方式

  ①、通过 new 关键字

  这是最常用的一种方式,通过 new 关键字调用类的有参或无参构造方法来创建对象。比如 Object obj = new Object();

  ②、通过 Class 类的 newInstance() 方法

  这种默认是调用类的无参构造方法创建对象。比如 Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();

  ③、通过 Constructor 类的 newInstance 方法

  这和第二种方法类时,都是通过反射来实现。通过 java.lang.relect.Constructor 类的 newInstance() 方法指定某个构造器来创建对象。

  Person p3 = (Person) Person.class.getConstructors()[0].newInstance();

  实际上第二种方法利用 Class 的 newInstance() 方法创建对象,其内部调用还是 Constructor 的 newInstance() 方法。

  ④、利用 Clone 方法

  Clone 是 Object 类中的一个方法,通过 对象A.clone() 方法会创建一个内容和对象 A 一模一样的对象 B,clone 克隆,顾名思义就是创建一个一模一样的对象出来。

  Person p4 = (Person) p3.clone();

  ⑤、反序列化

  序列化是把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。而反序列化则是把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。

 

浅拷贝与深拷贝

浅拷贝(clone):创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。

深拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都复制独立的一份。当你修改其中一个对象的任何内容时,都不会影响另一个对象的内容。

 

Java中的单例设计模式

饿汉式:

public class Singleton {
    private static Singleton instance = new Singleton();
 
    // 私有化构造方法
    private Singleton() {
 
    }
 
    public static Singleton getInstance() {
        return instance;
    }
 
}

懒汉式:

public class Singleton {
    //2.本类内部创建对象实例
    private static Singleton instance = null;
 
    /**
         * 1.构造方法私有化,外部不能new
         */
    private Singleton() {
 
    }
 
//3.提供一个公有的静态方法,返回实例对象
 
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
 

双重检验线程安全的懒汉式:

public class Singleton {
    private volatile static Singleton instance = null;
 
    // 私有化构造方法
    private Singleton() {
 
    }
 
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
 
        }
        return instance;
    }
 
}

 

posted @ 2021-06-18 16:02  头发少少少。  阅读(122)  评论(0编辑  收藏  举报