编程语言
首页 > 编程语言> > Java初级基础常见知识&面试总结(下)

Java初级基础常见知识&面试总结(下)

作者:互联网

前言

Java的基础知识而已


一、泛型

1、Java 泛型了解么?什么是类型擦除?介绍一下常用的通配符?

Java 泛型(generics) 是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

Java 的泛型是伪泛型,这是因为 Java 在运行期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。

List<Integer> list = new ArrayList<>();

list.add(12);
//这里直接添加会报错
list.add("a");
Class<? extends List> clazz = list.getClass();
Method add = clazz.getDeclaredMethod("add", Object.class);
//但是通过反射添加是可以的
//这就说明在运行期间所有的泛型信息都会被擦掉
add.invoke(list, "kl");
System.out.println(list);

泛型一般有三种使用方式: 泛型类、泛型接口、泛型方法。

1.泛型类:

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T> {
          
   
    private T key;
    public Generic(T key) {
          
   
        this.key = key;
    }
    public T getKey() {
          
   
        return key;
    }
}

如何实例化泛型类:

Generic<Integer> genericInteger = new Generic<Integer>(123456);

2.泛型接口 :

public interface Generator<T> {
          
   
    public T method();
}

实现泛型接口,不指定类型:

class GeneratorImpl<T> implements Generator<T>{
          
   
    @Override
    public T method() {
          
   
        return null;
    }
}

实现泛型接口,指定类型:

class GeneratorImpl implements Generator<String>{
          
   
    @Override
    public String method() {
          
   
        return "hello";
    }
}

3.泛型方法 :

public static <E> void printArray(E[] inputArray) {
          
   
    for (E element : inputArray) {
          
   
        System.out.printf("%s ", element);
    }
    System.out.println();
}

使用:

// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = {
          
    1, 2, 3 };
String[] stringArray = {
          
    "Hello", "World" };
printArray(intArray);
printArray(stringArray);

常用的通配符有哪些?

常用的通配符为: T,E,K,V,?

二、反射

何为反射?

如果说大家研究过框架的底层原理或者咱们自己写过框架的话,一定对反射这个概念不陌生。

反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。

通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。

反射机制优缺点

反射的应用场景

像咱们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景。

但是,这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。

这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。

比如下面是通过 JDK 实现动态代理的示例代码,其中就使用了反射类 Method 来调用指定的方法。

public class DebugInvocationHandler implements InvocationHandler {
          
   
    /**
     * 代理类中的真实对象
     */
    private final Object target;

    public DebugInvocationHandler(Object target) {
          
   
        this.target = target;
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
          
   
        System.out.println("before method " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("after method " + method.getName());
        return result;
    }
}

另外,像 Java 中的一大利器 注解 的实现也用到了反射。

为什么你使用 Spring 的时候 ,一个@Component注解就声明了一个类为 Spring Bean 呢?为什么你通过一个 @Value注解就读取到配置文件中的值呢?究竟是怎么起作用的呢?

这些都是因为你可以基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。你获取到注解之后,就可以做进一步的处理。

三、注解

Annontation (注解) 是Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或者变量。

注解本质是一个继承了Annotation 的特殊接口:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
          
   

}

public interface Override extends Annotation{
          
   
    
}

注解只有被解析之后才会生效,常见的解析方法有两种:

JDK 提供了很多内置的注解(比如 @Override 、@Deprecated),同时,我们还可以自定义注解。

四、异常

Java 异常类层次结构图概览 :

Exception 和 Error 有什么区别?

在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类:

Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异常,可以不处理)。 Error :Error 属于程序无法处理的错误 ,我们没办法通过 catch 来进行捕获 。例如Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

Checked Exception 和 Unchecked Exception 有什么区别?

Checked Exception 即受检查异常,Java 代码在编译过程中,如果受检查异常没有被 catch/throw 处理的话,就没办法通过编译 。

比如下面这段 IO 操作的代码: 除了RuntimeException及其子类以外,其他的Exception类及其子类都属于受检查异常 。常见的受检查异常有: IO 相关的异常、ClassNotFoundException 、SQLException…。

Unchecked Exception 即 不受检查异常 ,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。

RuntimeException 及其子类都统称为非受检查异常,例如:NullPointerException、NumberFormatException(字符串转换为数字)、ArrayIndexOutOfBoundsException(数组越界)、ClassCastException(类型转换错误)、ArithmeticException(算术错误)等。

Throwable 类常用方法有哪些?

try-catch-finally 如何使用?

示例:

try {
          
   
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
          
   
    System.out.println("Catch Exception -> " + e.getMessage());
} finally {
          
   
    System.out.println("Finally");
}

输出:

Try to do something
Catch Exception -> RuntimeException
Finally

注意:不要在 finally 语句块中使用return ! 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。这是因为 try 语句中的 return 返回值会先被暂存在一个本地变量中,当执行到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。

中有明确提到:

If the try clause executes a return, the compiled code does the following: 1、Saves the return value (if any) in a local variable. 2、Executes a jsr to the code for the finally clause. 3、Upon return from the finally clause, returns the value saved in the local variable.

先执行一部分的,先把返回的结果存到一段内存中;

示例:

public static void main(String[] args) {
          
   
    System.out.println(f(2));
}

public static int f(int value) {
          
   
    try {
          
   
        return value * value;
    } finally {
          
   
        if (value == 2) {
          
   
            return 0;
        }
    }
}

输出:

0

finally 中的代码一定会执行吗?

不一定的!在某些情况下,finally 中的代码不会被执行。

就比如说 finally 之前虚拟机被终止运行的话,finally 中的代码就不会被执行。

try {
          
   
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
          
   
    System.out.println("Catch Exception -> " + e.getMessage());
    // 终止当前正在运行的Java虚拟机
    System.exit(1);
} finally {
          
   
    System.out.println("Finally");
}

输出:

Try to do something
Catch Exception -> RuntimeException

另外,在以下 2 种特殊情况下,finally 块的代码也不会被执行:

1、程序所在的线程死亡。

2、关闭 CPU。

标签:java,0基础Java自学之路,基础教程,教程,参考官方教程,多态的详细介绍
来源: