JAVA基础面试题(第二期)

54 阅读8分钟

22.JAVA中的注解原理是什么?

注解其实就是一种标识,不会改变代码的逻辑,可以被框架或者工具处理比如编译时检查,运行时处理等操作

扩展:

可以使用@interface关键字来创建注解,通过三个元注解来决定这个注解的一些信息

@Retention:决定这个注解的保留情况是仅保存在源代码中还是可以留在.class文件中还是可以在运行时可用

@Target:决定这个注解作用于哪个地方(类,方法,字段)

@inherited:决定这个注解是否能够被继承

23.你使用过java的反射机制吗?如何使用反射?

java的反射机制是指程序在运行的过程中可以动态的获取类的结构信息,并创建操作对象的一种机制

java的动态代理底层就是利用反射实现的。

应用场景:框架上用的比较多,比如spring使用反射机制来读取和解析配置文件,从而实现依赖注入和面向切面编程

如何使用反射?

Class类:反射机制核心通过class类的实例可以获取类的各种信息

  1. 获取Class对象
Class<?> clazz = Class.forName("com.mianshiya.MyClass");
// 或者
Class<?> clazz = MyClass.class;
// 或者
Class<?> clazz = obj.getClass();
  1. 创建对象

创建构造类,通过getConstructor()方法创建对象

Object obj = clazz.newInstance(); // 已过时
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();

3.访问字段

Field类是字段类,通过getField方法获取字段类,然后通过传入对象来获取这个对象的这个字段的值

Field field = clazz.getField("myField");
field.setAccessible(true); // 允许访问 private 字段
Object value = field.get(obj);  //获取obj这个对象的这个字段值
field.set(obj, newValue);   //重新设置值

4.访问方法

通过创建Method类对象,获取实例对象中的方法

Method method = clazz.getMethod("myMethod", String.class);
Object result = method.invoke(obj, "param");

24.什么是JAVA的SPI机制?

SPI机制是一种插件机制,用于程序运行时动态的加载某些功能的实现

应用场景:

JDBC数据库连接,定义了一些接口然后不同的数据库区实现这些接口

25.JAVA泛型的作用是什么?

java泛型其实是一种伪泛型,为了在编译时检查类型安全,避免发生类型转换的错误

因为java5之前都是没有泛型的,一个List中可以放入各种各样类型的数据,这样就会出现当用到这些数据的时候就需要进行类型转换,这样很容易出错

为了防止出现这个情况java出现了伪泛型:只用于在编译的阶段检查泛型类型,在真正运行的时候将这些数据重新转换成Object类型(泛型擦除

那为什么要加入伪泛型而不是真正的泛型呢?

因为java5之前就已经有很多的代码在运行了如果突然更改会导致之前的代码可能报错,所以就增加了这种伪泛型伪了向下兼容

26.什么是泛型擦除?

就是java代码在运行的时候会将泛型全部转化为Object类型处理

27.什么是JAVA泛型的上下界限定符?

用于对泛型类型的参数进行范围限制,比如一个函数中的参数是泛型,但是并不是所有泛型都能够所以需要对泛型范围进行改变

? extends T:上界限定符,允许T泛型或者T的子类作为泛型参数

下界限定符:? super T,允许T或者T的父类作为泛型参数

28.浅拷贝和深拷贝有什么区别?

对于基本类型的对象,浅拷贝和深拷贝都是复制值

对于引用类型的对象,浅拷贝是只复制对象的引用不复制指向的实际对象,也就是新的对象和旧的对象指向的是同一个引用,这就导致修改新的对象的属性,原来的对象的属性也会改变

实现:

使用Object.clone()方法就是浅拷贝

深拷贝:不仅复制对象本身而且递归复制对象所包含的所有引用类型的对象,可以复制一个完全独立于原来对象的新对象,修改字段值不会对源对象产生任何影响

29.什么是JAVA的Integer缓存池?

就是java对于值在-128~127范围内的Integer对象进行缓存

用处:当进行自动装箱的时候如果值在范围内,不会创建新的Integer对象,而是会返回已经缓存的Integer对象。如果是主动new的话还是会创建一个新的对象

​
        Integer i1= 5;  //自动装箱
        Integer i2=5;   //自动装箱
        Integer i3=new Integer(5);  //主动创建

这个时候i1==i2为true,但是i1==i3为false

除了Integer,Long,Short,Byte缓存区都是-127~128,Boolean只缓存了两个值true和false

Character 缓存了0~127的(ASCII字符集)

30.JAVA的类加载机制是怎么样的?

类加载就是将类加载到JVM中,把二进制流保存到内存中,然后通过一番解析处理,转换成可用的class类

31.什么是JAVA的BigDecimal?

是java.math包下的一种高精度计算类

32.为什么BigDecimal可以保证精度不丢失?

因为BigDecimal采用了整数表示法,利用两个变量一个存储整数一个存储小数点的位置,类似于科学技术法的样子,这样保证了精度不丢失

33.使用new String("xxx")在java中会创建多少个对象?

  • 如果字符串常量池中不存在xxx,会先创建xxx字符串常量,然后再在堆中创建这个String对象引用这个字符串常量,所以是2个
  • 如果已经存在这个字符串常量,就只会在堆中创建新的String类型变量,然后引用这个字符串常量

tip:String s1="xxx"和String s2=new String("xxx"),String s3="xxx"是不同的

第一个是直接引用字符串常量,第二种是在堆中创建一个String 变量然后再引用字符串常量

所以s1和s3是同一个引用,s1==s3为true

34.JAVA中final,finally,finalize()分别有什么区别?

final是关键字可以修饰类,方法,字段

修饰类:表示这个类不可以被继承,(final类中不能有abstract方法,因为不能被继承所以没有子类实现这个方法)

修饰方法:这个方法不能被重写,但是可以被重载

修饰字段;这个字段的值不能被改变

fianlly,常与try-catch连用,finally中的字段不论如何都会执行

finalize()是Object中的方法用于被回收的时候进行一些处理(java9之后被弃用)

35.为什么编写代码的时候会遇到乱码问题?

因为字符编码和解码不一致,java默认使用操作系统的编码,如果程序在不同的系统上运行如果没有指定编码就会造成乱码

36.为什么java9之后将String中的char数组改成了byte数组?

为了节省空间,char类型占用2个字符,byte占用1个字节

如果存储的所有数据都是比如英文的话只需要一个字节,现在有2个字节就会造成浪费,所以改成了byte+coder变量来存储数据

coder变量存储了表示编码的方式默认时latin-1,如果检测到数据中有占用2个字节的数据就将编码改成utf-16,可以存放两个字节的数据

37.如何在java中调用外部命令:

  1. 使用Rutime类中的exec()方法

Rutime.getRutime().exec(args);args是String []类型的参数,里面分别放着在命令行的各条命令

38.如果一个线程中被调用两次start方法会发生什么?

会报错,start方法是将线程变成可运行态(Runnable),而不是立即执行

39.栈和队列在java中的区别是什么?

栈是先进后出,队列是先进先出

java中Stack类实现了栈的数据结构

java中Queue接口实现了队列的数据结构,LinkedList类底层就是双端队列,除此之外还有PriorityQueue(优先队列)

队列中的元素按照优先级排序而不是插入顺序

40.JAVA中Optional类是什么?有什么作用?

optional类是java8引入的一个容器类,可以优雅的解决null问题,不用显示的处理null的情况

创建Optional对象

可以使用静态方法empty(),of(),ofNullable()三种方法创建,空对象,非空对象,可能为空可能非空对象

判断,可以使用isPresent()和isEmpty()方法判断被包裹的对象是否存在

可以使用orElse(),orElseGet()方法执行,当对象为null的时候返回哪一个值或者执行哪一个方法