Java-常见面试题收集(二)

五 异常体系

1 Exception 和 Error 有什么区别?

  在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。
Throwable 类有两个重要的子类:
  Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可 以 分 为 Checked Exception ( 受 检 查 异 常, 必 须 处 理 ) 和 UncheckedException (不受检查异常,可以不处理)。
  Error :Error 属于程序无法处理的错误 ,我们没办法通过 catch 来进行捕获不建议通过 catch 捕获 。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等。
这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

2 Checked Exception 和 Unchecked Exception 有什么区别?

  Checked Exception 即 受检查异常 ,Java 代码在编译过程中,如果受检查异常没有被 catch 或者 throws 关键字处理的话,就没办法通过编译。
  除了 RuntimeException 及其子类以外,其他的 Exception 类及其子类都属于受检查异常 。常见的受检查异常有: IO 相关的异常、ClassNotFoundException 、SQLException…。
  Unchecked Exception 即 不受检查异常 ,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。

RuntimeException 及其子类都统称为非受检查异常,常见的有(建议记下来,日
常开发中会经常用到):
NullPointerException(空指针错误)
IllegalArgumentException(参数错误比如方法入参类型错误)
NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException 的
子类)
ArrayIndexOutOfBoundsException(数组越界错误)
ClassCastException(类型转换错误)
ArithmeticException(算术错误)
SecurityException (安全错误比如权限不够)
UnsupportedOperationException(不支持的操作错误比如重复创建同一用户)
// 等等

3 try with resource 语句适用于什么场合

  JDK7 之后,Java 多了个新的语法:try-with-resources 语句可以理解为是一个声明一个或多个资源的 try 语句(用分号隔开),一个资源作为一个对象,并且这个资源必须要在执行完关闭的,try-with-resources 语句确保在语句执行完毕后,每个资源都被自动关闭 。
  任何实现了 java.lang.AutoCloseable 的对象, 包括所有实现了 java.io.Closeable 的对象, 都可以用作一个资源。
开发场景以 打开了外部资源 居多:

  • 文件
  • 数据库连接
  • 网络连接

4 final, finally, finalize 的区别

  final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。内部类要访问局部变量,局部变量必须定义成 final 类型。
  finally 是异常处理语句结构的一部分,表示总是执行。
  finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。但是 JVM 不保证此方法总被调用

六 编程思维

1 编程题:求 x-y 之间所有基数的和

// 使用 while 编写函数 int sum(int x int y),返回从 x 到 y 其中所有的奇数值之和
public class SumDemo {
    public static int sum(int x, int y) {
        int i = x;
        int sum = 0;
        while (i <= y) {
            if (i % 2 != 0) {
                sum += i;
            }
            i++;
        }
        return sum;
    }
    public static void main(String[] args) {
        int sum = SumDemo.sum(1, 10);
        System.out.println("sum = " + sum);
    }
}

2 编程题:对数组元素进行反转

// 实现对一个数组元素反转的方法
public static void reverseArr(int[] arr) {
        int temp = 0;
        for (int i = 0; i < arr.length / 2; i++) {
            temp = arr[i];
            arr[i] = arr[arr.length - 1 - i];
            arr[arr.length - 1 - i] = temp;
        }
    }

3 编程题:从小到大输出

// 输入三个整数 x y z,请把这三个数由小到大输出
public void printNum(int x, int y, int z) {
        int[] arr = {x, y, x};
        Arrays.sort(arr);
        for (int item : arr) {
            System.out.println(item);
        }
    }

4 编程题:生成一个随机字符串数组

// 生成一个随机字符串数组。这些字符串必须是不一样的,每个字符串由字母和数字组成。方法输入参数有两个:
// Count:字符串数目
// Str_length: 字符串长
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class RandomDemo {
    // 每个字符串由字母和数字组成,将字母和数字存入一个数组
    public static List<Character> charAll() {
        List<Character> a = new ArrayList<>();
        for (char i = 'a'; i <= 'z'; i++) {
            a.add(i);
        }
        for (char i = 'A'; i <= 'Z'; i++) {
            a.add(i);
        }
        for (char i = '0'; i <= '9'; i++) {
            a.add(i);
        }
        return a;
    }

    public static List<String> randomStr(int Count, int Str_length) {
        List<String> list = new ArrayList<String>();
        //字母和数字组成
        List<Character> a = RandomDemo.charAll();
        // set
        HashSet s1 = new HashSet(); // 用于存一个字符串
        HashSet s2 = new HashSet(); // 用于存多个字符串
        //随机获得元素
        while (true) {
        //在 a.size()中获取随机数
            int a1 = (int) (Math.random() * a.size());
        //获取到的字符或者数字,存到数组中
            s1.add(a.get(a1));
        //Str_length 字符申长度够了就生成字符串,存到 s2 数组里面
            if (s1.size() == Str_length) {
        //生成字符串
                StringBuilder sb = new StringBuilder();
                for (Object o : s1) {
                    sb.append(o.toString());
                }
        //字符串存到 s2 数组里面
                s2.add(sb);
        // 清空
                s1.clear();
            }
            if (s2.size() == Count) {
                break;
            }
        }
        for (Object str : s2) {
            list.add(str.toString());
        }
        return list;
    }

    public static void main(String[] args) {
        List<String> list = RandomDemo.randomStr(5, 10);
        for (String item : list) {
            System.out.println(item);
        }
    }
}

5 编程题:对给定的字符串去重

// 给定一个输入字符串,能够删除所有连续同样字母(大小写不敏感)。例如,输入为 ABBCCCCCBBAB,输出就是 ABCBAB,又如,输入为 aAC,输出则是 aC
public class Demo {
    public static String deleteRepeat(String str) {
        // 将所有元素转换为大写(大小写不敏感)
        String s = str.toUpperCase();
        StringBuilder sb = new StringBuilder();
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < s.length(); i++) {
        //第一个元素是必定输出的,不用删除的
            if (i == 0) {
                list.add(0);
            } else {
        //根据前后元素比较,如果相同,则跳过,不同,则记录索引
                if (s.charAt(i) != s.charAt(i - 1)) {
                    list.add(i);
                }
            }
        }
        for (Integer n : list) {
        //将记录的索引对应原李符串添加到 stringBuilder 中,形成新的子
            sb.append(str.charAt(n));
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        String str = Demo.deleteRepeat("aAC");
        System.out.println("str = " + str);
    }
}

七 JVM

1 简单介绍一下 JVM 内存模型及其每一部分的作用

  堆。堆是 Java 对象的存储区域,任何用 new 字段分配的 Java 对象实例和数组,都被分配在堆上,Java 堆可使用-Xms -Xmx 进行内存控制,值得一提的是从JDK1.7 版本之后,运行时常量池从方法区移到了堆上。

  方法区。它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,方法区在 JDK1.7 版本及以前被称为永久代,从 JDK1.8 永久代被移除。

  虚拟机栈。虚拟机栈中执行每个方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。

  本地方法栈。与虚拟机栈发挥的作用相似,相比于虚拟机栈为 Java 方法服务,本地方法栈为虚拟机使用的 Native 方法服务,执行每个本地方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。

  程序计数器。指示 Java 虚拟机下一条需要执行的字节码指令。 以上五个区域是 Java 虚拟机内存划分情况,其中方法区和堆被 JVM 中多个线程共享,比如类的静态常量就被存放在方法区,供类对象之间共享,虚拟机栈,本地方法栈,

  pc 寄存器是每个线程独立拥有的,不会与其他线程共享。所以 Java 在通过 new创建一个类对象实例的时候,一方面会在虚拟机栈中创建一个该对象的引用,另一方面会在堆上创建类对象的实例,然后将对象引用指向该对象的实例。对象引用存放在每一个方法对应的栈帧中。

2 说一下堆栈区别?

  基本概念:
  堆内存:在 java 虚拟 jvm 中堆内存主要是存储数组和对象(当然数组也是对象),只要是通过 new 关键字创建的对象都是在堆中,而堆中存放的就是对象的实体,实体用来封装数据的,封装对象的属性,所以堆内存中的对象的存活时间是比较长的,只有没有程序去引用对象时候,才会通过 Java 自带的垃圾回收机制收取,堆内存中对象的存储具有先进先出的特点。

  栈内存:栈内存主要存储的是基本数据类型,局部变量,引用实例变量等,其具有先进后出的特点,变量都有自己的作用域,而当变量离开自己的作用域就会被释放,所以栈内存中更新速度比较快。

  堆栈区别:
  栈内存存储的是局部变量而堆内存存储的是实体;栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。

  堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生 StackOverFlowError 问题。你可以通过-Xss选项设置栈内存的大小。-Xms 选项可以设置堆的开始时的大小,-Xmx 选项可以设置堆的最大值。

  • 14
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泰勒疯狂展开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值