Java基础常见面试题总结(上)

1.什么是字节码?采用字节码的好处是什么? 

字节码是一种中间代码形式,它由Java源代码编译而来,可以在Java虚拟机(JVM)上执行。字节码是一种面向对象的、平台无关的代码形式,其具有以下优点:

可移植性:字节码可以在任何装有JVM的平台上运行,而不需要对源代码进行任何修改,从而实现了Java的“一次编写,到处运行”的特性。

安全性:字节码可以被JVM动态地加载、校验和执行,从而可以保证Java程序的安全性。

高效性:由于字节码是一种中间代码,可以通过JIT编译器将其转换为本地代码,从而实现了与本地代码类似的执行效率。

面向对象性:字节码是面向对象的,可以支持Java的所有面向对象特性,如继承、多态、封装等。

可读性:字节码是一种可读的、可反编译的代码形式,可以方便地进行代码审查和调试。

2.JAVA中的几种基本数据类型? 

Java语言中一共提供了8种原始的数据类型(byte,short,int,long,float,double,char,boolean),这些数据类型不是对象。

3.类型String,StringBuffer,StringBuilder的区别? 

 

在Java中,String,StringBuffer和StringBuilder都是用来表示文本字符串的类,它们之间的主要区别在于它们的可变性和线程安全性。

String类是不可变的,意味着一旦一个字符串被创建,它的值就不能被改变。任何对字符串的操作都会创建一个新的字符串对象。这使得String在多线程环境下是线程安全的,但会导致频繁的对象创建和销毁。

StringBuffer是可变的,可以进行添加、插入、删除和替换等操作,这些操作都是在原字符串对象上进行的,不会创建新的对象。StringBuffer是线程安全的,因为它的方法都是同步的,但是同步操作会影响性能。

StringBuilder与StringBuffer类似,也是可变的,但是不是线程安全的。StringBuilder比StringBuffer更快,因为它的方法不是同步的。

因此,如果需要进行大量的字符串操作,最好使用StringBuilder,

因为它的性能比StringBuffer更好。如果需要在多线程环境下操作字符串,最好使用StringBuffer,

因为它是线程安全的。如果只是简单的字符串操作,使用String就可以。

4.自动装箱与拆箱了解吗?原理是什么?

自动装箱和拆箱是Java中的语法糖,它们使得基本数据类型和对应的包装类型之间的转换更加方便。

自动装箱(Autoboxing)是指将基本数据类型自动转换为对应的包装类型,例如将int转换为Integer。

而自动拆箱(Unboxing)则是指将包装类型自动转换为基本数据类型,例如Integer转换为int。这些转换是在编译期间自动完成的,编译器会在必要时插入相应的代码,以完成类型的转换。例如,下面的代码:

Integer i = 10; // 自动装箱int j = i;      // 自动拆箱

会被编译器转换成以下代码:​​​​​​​

Integer i = Integer.valueOf(10); // 自动装箱int j = i.intValue();            // 自动拆箱

其中,valueOf()方法用于将基本数据类型转换为对应的包装类型,intValue()方法用于将Integer类型转换为int类型。

自动装箱和拆箱的优点在于使得代码更加简洁,不需要显式地进行类型转换。但是,在性能要求高的场合,建议手动进行类型转换,以避免额外的开销和潜在的错误。

5.对象的相等和引用相等的区别?

  • 对象的相等一般比较的是内存中存放的内容是否相等。

  • 引用相等一般比较的是他们指向的内存地址是否相等。

6.类的构造方法的作用是什么?

主要作用是完成对象的初始化工作

7.抽象类和接口的区别?

a)抽象类可以包含具体方法的实现,而接口只能包含方法的声明,不包含方法的实现。

b)子类只能继承一个抽象类,而一个类可以实现多个接口。

c)抽象类可以有构造函数,而接口不能有构造函数。

d)抽象类可以有成员变量,而接口只能有静态常量。

e)抽象类可以被继承和扩展,而接口只能被实现。

f)抽象类的方法可以是 public、protected 或者默认访问修饰符,而接口的方法必须是 public。

g)抽象类可以用于定义模板方法,而接口不可以。

8.String.intern 方法?

Java 中的一个 native 方法,它的作用是将字符串对象添加到字符串常量池中,并返回常量池中对应的字符串引用。如果常量池中已经存在该字符串,则直接返回常量池中的引用。这个方法可以被用来优化字符串的内存使用。

当一个字符串被创建时,它会被存储在堆内存中。而如果调用该字符串对象的 intern() 方法,则会将该字符串对象添加到字符串常量池中,并返回常量池中对应的字符串引用。如果字符串常量池中已经存在该字符串,则直接返回常量池中的引用。通过使用 String.intern() 方法,可以减少字符串对象的内存占用,因为多个字符串对象可以共享同一个字符串常量池中的引用。

需要注意的是,由于 String.intern() 方法会将字符串对象添加到字符串常量池中,因此如果使用该方法的次数过多,会增加常量池的负担,可能导致性能下降。因此,建议在需要优化字符串内存使用时才使用该方法,而不是在每个字符串对象上都使用。

9.String 为什么是不可变的?

String 类中使用 final 修饰字符数组来保存字符串,所以不可变

具体代码:

 

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

    。。。
}
 

10.final 的用途?

用final修饰的类不能被扩展,也就是说不可能有子类;

用final修饰的方法不能被替换或隐藏;

用final修饰的变量最多只能赋值一次;

11.深拷贝和浅拷贝区别?

浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。

深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。

引用拷贝则是创建了一个指向同个原对象的引用类型。

12.== 和 equals() 的区别?

== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

13.hashCode() 有什么用?

hashCode是jdk根据对象的地址算出来的一个int数字,即对象的哈希码值,代表了该对象在内存中的存储位置

hashCode()方法是顶级类Object类的提供的一个方法,所有的类都可以进行对hashCode方法重写。

14.重写 equals() 时必须重写 hashCode() 方法吗?

hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度,如果在重写 equals 时,不重写hashCode,就会导致在某些场景下,例如将两个相等的自定义对象存储在 HashMap、HashSet、HashTable等 集合时,就会出现程序执行的异常。

为了保证程序的正常执行,在重写 equals 时,必须重写 hashCode 方法才行。 

14.Static 关键字的作用?

静态变量:在函数内部使用 static 关键字声明的变量,它的作用域仅限于该函数,但是该变量的值在函数调用之间保持不变。静态变量通常用于需要记住上次调用值的情况,或者需要在整个程序中共享值的情况。

静态方法:在类中使用 static 关键字声明的方法,可以在不实例化类的情况下直接调用。通常用于辅助方法或工具方法。

静态类:在某些编程语言中,使用 static 关键字声明的类被称为静态类。静态类不能被实例化,而且通常只包含静态成员,如静态变量和静态方法。

静态块:在 Java 中,使用 static 关键字声明的代码块称为静态块。静态块在类加载时执行,并且只会执行一次。它通常用于初始化静态变量。

15.序列化与反序列化?

序列化是指将 Java 对象转换为字节序列的过程,而反序列化是指将字节序列转换回 Java 对象的过程。这个过程常常用于将对象持久化存储或网络传输。Java 序列化和反序列化可以通过 Java 的 Serializable 接口来实现。

具体来说,当一个类实现了 Serializable 接口时,就表示这个类的对象可以被序列化。Java 序列化可以通过 ObjectOutputStream 来实现,反序列化可以通过 ObjectInputStream 来实现。以下是一个简单的例子:


// 实现 Serializable 接口
class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

// 序列化
Person person = new Person("Alice", 30);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"));
oos.writeObject(person);
oos.close();

// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"));
Person person2 = (Person)ois.readObject();
ois.close();

System.out.println(person2.getName()); // Alice
System.out.println(person2.getAge());  // 30
 

需要注意的是,序列化和反序列化的过程中需要保证对象的成员变量也是可序列化的,否则会抛出 NotSerializableException 异常。

16.Java8 的新特性?

a)Lambda 表达式:Lambda 表达式是一种匿名函数,可以简化代码,使得代码更加易读和简洁。

b)方法引用:方法引用是一种更加简洁的 Lambda 表达式的写法,可以引用已经存在的方法来代替 Lambda 表达式。

c)默认方法:默认方法是在接口中定义的具有默认实现的方法,可以避免在修改接口时破坏已有的实现。

d)函数式接口:函数式接口是指只包含一个抽象方法的接口,可以用于 Lambda 表达式和方法引用。

e)Stream API:Stream API 是一种用于操作集合和数组的新的 API,可以方便地进行过滤、排序、映射等操作。

f)Date/Time API:Java 8 引入了新的 Date/Time API,提供了更好的日期和时间处理方式,同时解决了旧的 Date/Calendar API 的一些问题。

g)Nashorn JavaScript 引擎:Java 8 引入了 Nashorn JavaScript 引擎,可以将 JavaScript 代码嵌入到 Java 应用程序中,并在 Java 平台上运行。

h)Parallel Array Sorting:Java 8 引入了一种新的数组排序算法,可以利用多核 CPU 实现并行排序,提高排序效率。

i)Type Annotations:Java 8 引入了 Type Annotations,可以在编译时检查代码中的类型错误,提高代码的健壮性。

17.说说类的实例化顺序?

 父类静态变量->父类静态代码块->子类静态变量->子类静态代码块->

父类非静态变量->父类构造函数->子类非静态变量->子类构造函数。

好了,看到了这里了, 转发、在看、点赞 随便安排一个吧,要是你都安排上我也不介意。写文章很累的,需要一点正反馈。

给各位读者朋友们磕一个了:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值