- [ 面试 ]

java常见面试题2

2021-03-02  本文已影响0人  好多可乐

一,基础语法

1. JDK,JRE,JVM的区别:

2. 为什么java可以跨平台,实现一次编写,到处运行呢?

3. 常用数字类型的区别

5. 随机数的使用

//生成30~100之间的随机数
public class RandomNum {
    // 方法1
    public int randomNum1() {
        int max = 101;
        int min = 30;
        return new Random().nextInt(max - min) + min;
    }

    // 方法2
    public int randomNum2() {
        int max = 101;
        int min = 30;
        return (int) (Math.random() * (max - min)) + min;
    }
}

6. 列出1-1000的质数

/**
 * 列出1-1000的质数
 * 质数:在大于1的自然数中,只能被1和自身整除的数
 */
public class PrimeNum {
    public static void main(String[] args) {
        for (int i = 2; i <= 1000; i++) {
            boolean flag = true;
            for (int j = 2; j < i; j++) {
                if (i % j == 0) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                System.out.println(i);
            }
        }
    }
}

二,面向对象

1. 面向对象的三大特性是什么:

2. 封装的好处:

3.多态的实现机制

4. 接口和抽象类有哪些异同?

  1. 都是从具体类中抽象出的方法的声明

  2. 都不能被实例化

  3. 都可以包含抽象方法

  1. 抽象类可以包含方法的实现,接口则只能包含方法的声明

  2. 继承类只能继承一个抽象类,实现类可以实现多个接口

  3. 抽象级别:接口>抽象类>实现类

  4. 作用不同:接口用于约束程序行为,继承则用于代码复用

5. 静态和实例变量(方法)的区别?

6. Error和Exception的区别和联系

在这里插入图片描述
7. 类的执行顺序 在这里插入图片描述

执行顺序如下:142356

三,字符串

1. 请写出程序的执行结果

在这里插入图片描述
解析:
字符串保留在常量池中,一旦创建用final修饰
s1==s2 --> true,指向同一个内存地址
s3==s4 --> true,指向同一个内存地址
s4==s5 --> false,s2是引用类型,编译期间无法确认数值,只有运行时才能确认
s4.equals(s5) -->true,equals比较的是内容
s1==s6 -->false, s1是存放在常量池中的,s6是不在常量池进行保存的,因为保存地址不一样,所以是falase

2. String,StringBuilder,StringBuffer的区别?

在这里插入图片描述
答:String是把数据存放在常量池中,因此在线程池中是最安全的,但是执行速度最差,推荐少量字符串操作时候进行使用。

StringBuilder执行效率最高,但是线程不安全(线程安全:在进行多线程处理时,如果多个线程对一个对象同时操作,会不会发生异常),只推荐在单线程情况下大量字符串操作

StringBuffer执行速度在三者中排名中间,线程也是安全的。效率低的原因是更多考虑了多线程的情况,推荐多线程环境下操作

四,集合

1. List和Set的区别?

2. ArrayList和LinkedList的区别?

3. HashSet和TreeSet的区别?

4,TreeSet排序的编码实现

  1. 基于java bean来实现comparable接口,这种排序方式称为自然排序
public class Employee implements Comparable<Employee>{
    private String name;
    private int salary;

    public Employee( String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }
    public int compareTo(Employee o) {
        return this.getSalary().compareTo(o.getSalary());
    }

    @Override
    public String toString() {
        return "Employee{" +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                '}';
    }
}
  1. 实例化TreeSet的时候实现comparator接口,这种排序方式是自定义排序
public class Test {

    public static void main(String[] args) {
        TreeSet<Employee> employees = new TreeSet<Employee>(new Comparator<Employee>() {
            public int compare(Employee o1, Employee o2) {
                return (int) (o1.getSalary() - o2.getSalary());
            }
        });
        employees.add(new Employee(3, "张三", -13001f));
        employees.add(new Employee(32, "张三", -13001.1f));

        System.out.println(employees);
        {
        }
    }
}

5. hashCode()和equals()的区别

两者都是用于比较对象是否相同,但是底层算法完全不同。

五,输入输出流

1. Java IO中有几种类型的流:

在这里插入图片描述
输入/出流:数据链向程序进行输入/输出

字节流:二进制

字符流:可以阅读的字符

常见的流如下:

InputStream/OutputStream:顶层是抽象类,

FileInputStream/FileOnputStream:文件输入/出字节流,用于对二进制文件进行读取/写入

BufferedInputStream/BufferedOnputStream:加入缓存,提高文件的读取/写入效率

Reader/Writer:封装对字符流进行输入/输出的抽象

FileReader/FileWriter:读取/写入文本文件

InputStreamReader/OutputStreamWriter:将输入字节流转换为可读的输入字符流

BufferedReader/BufferedWriter:加入缓存,提高文件的读取/写入效率

2. Java IO中有几种类型的流:

在这里插入图片描述

输入/出流:数据链向程序进行输入/输出

字节流:二进制

字符流:可以阅读的字符

常见的流如下:

InputStream/OutputStream:顶层是抽象类,封装了输入/输出字节流的抽象方法

FileInputStream/FileOnputStream:文件输入/出字节流,用于对二进制文件进行读取 /写入

BufferedInputStream/BufferedOnputStream:加入缓存,提高程序的读取效率。之前FileInputStream进行文件读取的时候是读一个写一个,速度比较慢,采用这个方法可以一次性读取多个文件再进行处理,降低IO和程序处理的压力

Reader/Writer:封装对字符流进行输入/输出的抽象

FileReader/FileWriter:读取/写入文本文件

InputStreamReader/OutputStreamWriter:将输入/输出字节流转换为可读的输入/输出字符流

BufferedReader/BufferedWriter:加入缓存,提高文件的读取/写入效率

3. 利用IO实现文件复制:

编程题:复制文件到指定文件夹

public static void main(String[] args) {
        File source = new File("C:/Users/86189/Pictures/clipboard.png");
        File target = new File("C:/Users/86189/Pictures/clipboard1.png");
        InputStream is = null;
        OutputStream os = null;
        try {
            is = new FileInputStream(source);
            os = new FileOutputStream(target);
            byte[] b = new byte[1024];
            int n = 0;
            while ((n = is.read(b)) != -1) {
                os.write(b, 0, n);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    }

六,垃圾回收与jvm内存

1. JVM的内存组成

在这里插入图片描述
JVM分成共享区和私有区,

2. 简述Java的垃圾回收机制(GC)
GC(Garbage Collection)--回收不再使用的内存
GC负责3项任务:分配内存、确保引用、回收内存
GC回收依据--当对象没有任何作用,则可以被回收。
垃圾回收是双刃剑:
1,对程序开发提供了便捷,
2,垃圾回收要对程序进行不断的监听,所以执行效率,相对于C、C++要低一些。不过随着技术发展和软硬件技术的提高,差距在不断的缩小。
垃圾回收器--使用的是有向图的方式管理和记录,堆内存中的所有对象。通过有向图可以识别哪些对象时可达的。哪些对象是不可达的。对于可达的对象进行保留,不可达的对象视为垃圾,被垃圾回收器处理掉。

3. 垃圾回收(GC)算法:常用的5种算法(扩展问题)

4. 请列举java中内存泄露的场景
内存泄漏--指一个不再被程序使用的对象或者变量,还在内存中占用空间。
C、C++语言中,垃圾回收是需要手动操作的,如果程序员忘记释放,就会造成内存泄漏。
JAVA--有垃圾回收机制,由回收器自动回收,可以极大的降低程序员垃圾回收的工作。但JAVA也会出现内存泄漏的场景。
常见的内存泄漏场景:
1,静态集合类,有些程序员喜欢用静态关键字“static”来修饰变量或对象。这种方法时不可取的,因为对静态对象来说,它存储在方法区中。垃圾回收器不会对“方法区”中的数据进行高频度的回收。
如果使用static 修饰了一个集合,存放的数据量又比较大。而且通常我们方法区的内存是比较小的,时间久了就会产生内存溢出的情况,进而程序崩溃。
2,各种连接--数据库拦截、网络拦截、IO拦截等,只打开,但未关闭。在JVM中这些对象一直是可达状态,因此不会被回收。时间久了就会导致程序崩溃。
3,监听器--因为其往往都是全局存在的,如果监听器中使用的对象或变量,没有进行有效的控制的话,很容易产生内存泄漏。
4,不合理的作用域--java开发中有一个基本的原则,作用域最下化。变量能声明在方法中就不要声明在方法外,能用private 不要用public。(作用域的正确使用是一个java工程师的基本功,只需要它的时候才去创建,如果一个变量的作用范围大于它的使用范围,很有可能导致内存泄漏的情况。。另外如果在平时使用时,没有吧引用对象及时设置成null,也有可能造成内存泄漏)

5. 浅复制和深复制

package com.imooc.interview.clone;

import java.io.*;

public class Dancer implements Cloneable,Serializable{
    private String name;

    private Dancer partner;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Dancer getPartner() {
        return partner;
    }

    public void setPartner(Dancer partner) {
        this.partner = partner;
    }

    public Dancer deepClone() throws IOException, ClassNotFoundException {
        //序列化,将内存中的对象序列化为字节数组
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        //反序列化,将字节数组转回到对象,同时完成深复制的任务
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Dancer)ois.readObject();
    }


    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        Dancer d1 = new Dancer();
        d1.setName("刘明");
        Dancer d2 = new Dancer();
        d2.setName("李敏霞");
        d1.setPartner(d2);
        System.out.println("Partner:" + d2.hashCode());
        //浅复制(继承CloneAble接口,实现clone方法)
        Dancer shallow = (Dancer)d1.clone();
        System.out.println("浅复制:" + shallow.getPartner().hashCode());
        //深复制(继承Serilizable接口,进行序列化和反序列化,实现deepClone方法)
        Dancer deep = (Dancer)d1.deepClone();
        System.out.println("深复制:" + deep.getPartner().hashCode());
    }

}
上一篇下一篇

猜你喜欢

热点阅读