java基础面试题

文章 , 技术分享
405 0

6.1 equals与==的区别

equals用于比较对象的内容是否相等,而==比较的是对象的引用是否相同。例如:

String s1 = new String("hello");
String s2 = new String("hello");

System.out.println(s1 == s2); // 输出 false,因为引用不同
System.out.println(s1.equals(s2)); // 输出 true,因为内容相同

6.2 final、finally、finalize的区别

final:修饰符,可用于类、方法和变量,表示不可改变。

finally:与try-catch语句一起使用,表示无论是否发生异常,都会执行的代码块。

finalizeObject类的一个方法,当垃圾回收器准备回收对象时调用。

6.3 重载和重写的区别

重载:同一个类中,方法名相同但参数列表不同的方法。

重写:子类实现父类的方法,并对其进行修改,以满足子类的需求。

6.4 两个对象的hashCode()相同,则equals()是否也一定为true

不一定。hashCode()相同只能说明两个对象可能相等,还需要进一步使用equals()方法进行判断。

6.5 抽象类和接口有什么区别

抽象类:具有抽象方法的类,不能被实例化,用于被其他类继承。

接口:定义了一组规范,类可以实现接口以满足这些规范。

6.6 BIO、NIO、AIO有什么区别?

BIO(Blocking I/O):阻塞式I/O,每个请求都需要一个线程进行处理。

NIO(Non-blocking I/O):非阻塞式I/O,可以处理多个请求,效率较高。

AIO(Asynchronous I/O):异步I/O,不需要等待请求完成,直接返回。

6.7 String,StringBuffer,StringBuilder的区别

String:不可变字符序列,适用于字符串常量;
StringBuffer:可变字符序列,线程安全,性能较低;
StringBuilder:可变字符序列,非线程安全,性能较高。

6.8 Java中的几种基本数据类型是什么,各自占用多少字节?

byte:1字节
short:2字节
int:4字节
long:8字节
float:4字节
double:8字节
char:2字节
boolean:1字节

6.9 ComparatorComparable有什么区别?

Comparable:用于自然排序,需要实现compareTo()方法;
Comparator:用于自定义排序,需要实现compare()方法。

6.10 String类能被继承吗,为什么?

String类不能被继承,因为它被声明为final,表示不可被继承。

6.11 说说Java中多态的实现原理

Java中多态的实现依赖于继承、接口和方法重写。在运行时,JVM根据实际对象的类型调用对应的方法。

6.12 Java泛型和类型擦除

泛型:用于在编译期提供类型安全的一种机制;
类型擦除:泛型信息在编译后被擦除,运行时泛型类型信息不可用。

6.13 intInteger的区别,以及Integer缓存的实现

int:基本数据类型,直接存储数值;
Integer:包装类型,用于表示int类型的对象。
Integer缓存:在-128至127之间的整数会被缓存,以减少对象创建开销。

6.14 说说反射的用途及实现原理,Java获取反射的三种方法

反射用途:在运行时动态地创建对象、调用方法、获取和修改属性等。
实现原理:JVM在运行行时加载类元数据,通过这些信息进行反射操作。
获取反射的方法:

Class.forName("类名");
对象.getClass();
类名.class

6.15 面向对象的特征

封装:隐藏对象的实现细节,提供访问方法;
继承:子类继承父类的属性和方法;
多态:同一操作作用于不同对象,产生不同结果。

6.16 &&&的区别

&: 按位与,用于整数类型;
&&: 逻辑与,用于布尔类型,具有短路特性。

6.17 Java中I/O流分为几种?

Java中的I/O流分为四种:

字节输入流:InputStream
字节输出流:OutputStream
字符输入流:Reader
字符输出流:Writer

6.18 讲讲类的实例化顺序,比如父类静态数据,构造函数,子类静态数据,构造函数等

类的实例化顺序:

父类静态代码块和静态变量(按照声明顺序);
子类静态代码块和静态变量(按照声明顺序);
父类非静态代码块和非静态变量(按照声明顺序);
父类构造函数;
子类非静态代码块和非静态变量(按照声明顺序);
子类构造函数。

6.19 Java创建对象有几种方式?

使用new关键字;
使用Class类的newInstance()方法;
使用Constructor类的newInstance()方法;
使用clone()方法;
使用反序列化(如ObjectInputStreamreadObject()方法)。

6.20 如何将GB2312编码的字符串转换为ISO-8859-1编码的字符串?

String gb2312Str = "你好";
String iso8859Str = new String(gb2312Str.getBytes("GB2312"), "ISO-8859-1");

6.21 守护线程是什么?用什么方法实现守护线程?

守护线程是一种在后台运行的线程,当所有非守护线程结束时,守护线程也会自动结束。通过调用Thread类的setDaemon(true)方法将线程设置为守护线程。

6.22 notify()notifyAll()有什么区别?

notify():唤醒一个等待该对象锁的线程;
notifyAll():唤醒所有等待该对象锁的线程。

6.23 Java语言是如何处理异常的?关键字throwsthrowtrycatchfinally怎么使用?

Java通过异常处理机制处理运行时错误。关键字用法:

throws:声明方法可能抛出的异常;
throw:抛出异常;
try:尝试执行可能抛出异常的代码;
catch:捕获并处理异常;
finally:无论是否发生异常,都会执行的代码块。

6.24 谈谈Java的异常层次结构

Java的异常层次结构以Throwable为顶层,分为ErrorException两个子类。其中,Error表示严重错误,通常不需要捕获;Exception表示可捕获异常,分为RuntimeException(非受检异常)和其他受检异常。

6.25 静态内部类与非静态内部类有什么区别?

  • 静态内部类:不依赖外部类的实例,可以直接创建对象。
  • 非静态内部类:依赖外部类的实例,需要先创建外部类实例,然后通过外部类实例创建内部类对象。

6.26 String与new String有什么区别?

  • String:直接赋值时,字符串会被存储在字符串常量池中,相同内容的字符串共享内存。
  • new String:在堆内存中创建新的字符串对象,即使内容相同,也不共享内存。

6.27 反射中,Class.forName和ClassLoader的区别

  • Class.forName:加载并初始化类,触发类的静态代码块。
  • ClassLoader:仅加载类,不触发类的静态代码块。

6.28 JDK动态代理与CGLIB实现的区别

  • JDK动态代理:基于接口的代理,要求目标对象实现接口。
  • CGLIB:基于继承的代理,要求目标对象不是final类。

6.29 error和exception的区别,CheckedException,RuntimeException的区别

  • error:表示严重错误,通常不需要捕获,如OutOfMemoryError。
  • exception:表示可捕获的异常,分为CheckedException和RuntimeException。
  • CheckedException:受检异常,需要显式处理,如IOException。
  • RuntimeException:非受检异常,不需要显式处理,如NullPointerException。

6.30 深拷贝和浅拷贝区别

  • 浅拷贝:创建新对象并复制原对象的基本类型属性和引用类型属性的引用,指向相同的内存。
  • 深拷贝:创建新对象并复制原对象的基本类型属性以及引用类型属性的实际内容,不共享内存。

6.31 JDK和JRE有什么区别?

  • JDK(Java Development Kit):Java开发工具包,包括JRE、编译器、调试器等开发工具。
  • JRE(Java Runtime Environment):Java运行时环境,包括JVM、核心类库等,用于运行Java程序。

6.32 String类的常用方法有哪些?

  • length():获取字符串长度。
  • charAt():获取指定索引位置的字符。
  • substring():截取子字符串。
  • indexOf():查找字符或子字符串首次出现的位置。
  • lastIndexOf():查找字符或子字符串最后一次出现的位置。
  • equals():判断字符串内容是否相等。
  • toLowerCase():转换为小写。
  • toUpperCase():转换为大写。
  • trim():去除字符串首尾的空白字符。
  • replace():替换字符或子字符串。
  • concat():连接字符串。
  • split():根据分隔符拆分字符串为数组。

6.33 谈谈自定义注解的场景及实现

自定义注解可以用于在编译期或运行时为代码添加元信息。实现自定义注解需使用@interface关键字。例如,定义一个用于检查方法执行时间的注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CheckExecutionTime {
    String value() default "";
}

这里,@Retention指定注解的保留策略,@Target指定注解可用的元素类型。

使用自定义注解的场景包括:

  • 配置信息(如Spring的@Configuration)
  • 标记方法(如JUnit的@Test)
  • 依赖注入(如Spring的@Autowired)

实现自定义注解一般需要定义注解的属性、保留策略和可用元素类型。注解的属性可以是基本类型、String、Class等,也可以是其他注解类型或数组类型。注解的保留策略可以是SOURCE、CLASS或RUNTIME,分别表示注解只在源代码中保留、在编译时保留或在运行时保留。注解的可用元素类型可以是类、方法、字段、参数等。在使用自定义注解时,需要使用注解处理器来解析注解并实现相应的功能。

6.34 x++和++x
x++和++x都是自增运算符,但它们的执行顺序和结果不同。x++是后置自增运算符,它的执行顺序是先使用x的值,然后再将x加1。例如:int x = 5;int y = x++; // y的值为5,x的值变为6++x是前置自增运算符,它的执行顺序是先将x加1,然后再使用x的值。例如:int x = 5;int y = ++x; // y的值为6,x的值也为6因此,如果只是单独使用自增运算符,两种运算符的结果是一样的。但是如果在表达式中使用自增运算符,就会有区别。例如:int x = 5;int y = x++ * 2; // y的值为10,x的值变为6int z = ++x * 2; // z的值为14,x的值为7在上面的例子中,y的值为10是因为先使用了x的值5,然后再将x加1,所以y的值是5乘以2的结果。而z的值为14是因为先将x加1变为6,然后再使用x的值6,所以z的值是6乘以2的结果。

最后更新 2023-07-15
评论 ( 0 )
OωO
隐私评论