大数据面试总结

1、冒泡排序、选择排序

冒泡排序:主要的思路就是从一个元素开始,与相邻的元素进行比较,如果比他大,就交换元素,使较大的元素元素排在后面,直到最后一个元素。

public class BubbleSort {
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n; i++) {
            // 每轮遍历将最大的数移到末尾
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j+1]) {
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));  // [11, 12, 22, 25, 34, 64, 90]
    }
}

选择排序:双重循环遍历数组,每经过一轮比较,找到最小元素的下标,将其交换至首位。

public static void selectionSort(int[] arr) {
    int minIndex;
    for (int i = 0; i < arr.length - 1; i++) {
        minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[minIndex] > arr[j]) {
                // 记录最小值的下标
                minIndex = j;
            }
        }
        // 将最小元素交换至首位
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}
2、二分查找

二分查找又被称为折半查找,是在一组有序的数据中查找一个数据,效率一般会比较高。

(这里数据使用的是升序排序)通过中间索引来确定中间元素的值,将需要查询的数据与中间元素的数据进行比较,比中间数据要大,就在中间数据的右边,此时范围就在中间元素到最后一个元素,然后通过确定这个范围中的中间元素,再进行判断以此类推,如果比原先的元素小,范围就是在第一个元素到第一个中间元素之间,再依次类推。

需要注意的是:如果数据的个数使偶数个,一般是取右边的。


public class BinarySearch {
    public static void main(String[] args){
        int[] array = {1,5,8,11,19,22,31,35,40,45,48,49,50};
        int target=48;
        int idx=binarySearch(array,target);
        System.out.println(idx);
    }

    //二分查找,找到返回目标值下标,没找到返回-1;
    public static int binarySearch(int[] a,int target){
        int L=0;
        int R=a.length-1;
        int M;
        while (L<=R){
            M=(L+R)/2;
            if(a[M]==target)
                return M;
            else if(a[M]>target)
                R=M-1;
            else if(a[M]
3、 hashmap和hashtable的区别?hashmap的底层实现原理?
a、hashtable和hashmap的区别:

1、hashtable是线程安全的,会在每一个方法中都添加方法synchronize(同步机制)方法,所以线程是安全的,对于hashmap来说,方法中是没有同步机制,所以hashmap是线程不安全的。

2、两个继承的父类也是不同的,hashtable的父类是继承Dictionary类,然而对于hsahmap是继承AbstractMap类,但是hashmap和hashtable都实现了map接口。

3、在hashtable中的,key和value是不可以为null的,但是在hashmap中,null是可以作为主键,且只能存在一个,但是可以一个或者是多个键对应的值可以是null。

4、两者内部的数组的初始化和扩容的方式也是不同的,hashtable在不指定容量大小的前提下默认是11,hashmap默认是16。

b、hashmap的底层实现的原理:

原因是hashmap的底层是数组和红黑树组成的,通过哈希算法将映射到数组中的索引位置,从而进行快速的查询和存储。

底层是通过重写hashcode和equals()方法,hashcode()方法的主要的作用是计算哈希码,equals()方法的主要的作用的是判断当前的key与查询的key的值是否相同。

put方法原理

put的方法主要是用于将键值对插入到hashmap中,用底层的源码可以知道,会先计算key的哈希值,并调用putval()方法进行插入。ptuval()的核心就是通过哈希码来定位同桶,然后向桶中插入数据,如果桶是空的,那么就直接向桶中插入新的节点,如果桶不是空的,就会遍历红黑树,判断key是否存在,如果存在,那个原先旧的value就会被新的value所代替。如果遍历,可以key不存在,就会将新节点插入到链表的末端,当达到链表长度的阙值就将链转化成红黑树。

hashmap自动扩容:

主要的步骤就是调用resize()方法,会创建一个新的数组,重新计算哈希码和索引位置,然后分配到新的桶中。默认扩容后的数据的容量的大小是等于原先旧的2的n倍。

get方法原理:

会根据需要查询的key通过哈希算法计算出哈希码,通过哈希码来确定对应的桶的位置,如果桶是空的,那么就返回null,值不存在,如果桶不是空的,就遍历链表或者是红黑树,通过equals()方法来比较传入的键与当前的键是否相同。相同就输出,不同就继续遍历。

4、arraylist和linklist的区别?

1、数据及其内部结构不同,arraylist的内部是使用数组的形式进行存储数据,linkedlist的内部是使用双向链表进行存储数据。

2、arraylist是线程不安全的,linkedlist是线程安全的,所以arraylist的性能会linkedlist的性能比较好。

3、根据索引查询的速度不同,arraylist的查询的速度会比linkedlist的速度要快。

5、stringbuilder和stringbuffer的区别?String的特殊性?
String的特殊性?

string的特殊性是string的不变性,一个string对象一旦被创建好就无法修改了,当对一个string对象进行修改的时候,本质还是创建了一个新的string对象用来接收,原先的string对象没有被修改。

stringbuilder和stringbuffer的区别?

1、stringbuilder和stringbuffer都是可变的,可以对其进行修改,并不会产生新的对象。

2、stringbuffer是线程安全的,stringbuilder是线程不安全的。

3、在单线程的环境下,stringbuffer的性能比stringbuilder低。

6、switch支持哪几种数据类型?跟版本相关,注意string类型的区别?

主要支持的数据类型有:整型、字符型、枚举类型、字符串类型、以及java7后面的表达式类型(switch表达式)。

7、面向对象的特点?

1、封装:封装就是将数据和操作进行封装在一起,然后对外提供一个接口供外界使用,不仅保护数据的完整性,还可以提高代码的复用性和可维护性,降低模块之间的耦合性。

2、继承:  一个类可以继承另一个类的属性和方法,也可以添加和修改自己的属性和方法,提高代码的可维护性和复用性。      

3、多态:同一个对象可以表现出多种形态。

4、抽象:将事务的本质和共性特征抽象出来,形成抽象类或者是接口。

8、字节流和字符流区别?

1、处理单元不同,字节流是以字节作为处理单元,字符流是以字符作为处理单元的,字节流主要使用处理二进制数据,对于字符流一般是用来处理文本数据。

2、处理数据的速度不同,字节流的读取和写入的速度比字符流的速度要快,因为字符流的底层是需要先将字符数据转化成字节数据在进行处理,然而对于字节流来说,底层是就是字节数据,所以处理速度要比字符流快。

3、数据的表现形式是不同的,字节流是以字节数据的形式读取和写入数据,所以支持的类型比较多,例如文本、视频、图像等,然而字符流底层是字符数据,所以只能读取和写入文本数据。

4、缓冲区大小是不同的,字节流的缓冲区一般比字符流的缓冲区要大,因为字节流处理的数据比字符流数据量要大,所以缓冲会比字符流要大。

9、锁的概念

提出锁的原因是在并发编程中,会出现多个进程同时运行抢占公共资源,导致出现一些并发问题。

在java中,锁是一种多线程同步机制,主要使用控制多个线程对公共资源的访问,保证线程之间的互斥性,即同一个时刻只有一个线程可以访问公共资源。

锁主要分成两种:显式锁、隐式锁。

显式锁:

显式锁是通过Java中的Lock接口及其实现类来实现的,它提供了更灵活、更强大的锁机制,相比隐式锁具有更多的优势。

隐式锁:

又被称为内置锁或synchronized锁,是Java语言提供的一种简单且方便的锁机制,可以通过在方法或代码块中使用synchronized关键字来实现对共享资源的同步访问

10、实现多线程的几种方式?

1. 继承Thread类:在Java中可以通过继承Thread类来实现多线程。通过重写Thread类中的run()方法,可以定义需要在多线程中执行的任务。

public class MyThread extends Thread {
    public void run(){
        // 在这里编写线程要执行的任务
    }
}
// 创建并启动线程
MyThread thread = new MyThread();
thread.start();

2. 实现Runnable接口:Java中还可以通过实现Runnable接口来实现多线程。与继承Thread类相比,实现Runnable接口更常用,因为它可以避免单继承的限制,并且使代码更加清晰。

public class MyRunnable implements Runnable{
    @Override
    public void run(){
        // 在这里编写线程要执行的任务
    }
}
// 创建并启动线程
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();

3、实现Callable接口:实现Callable之后,需要实现call()方法,方法中写我们需要的操作,然后创建实现接口类的对象,将对象作为参数创建FurtureTask对象,再将task对象作为参数创建thread对象,调用start方法开启线程,还可以使用task对象的get方法获取返回值。他们的区别是前二者不能获取返回值,callable接口可以获得返回值,一般在实际使用中,更多使用实现接口的方式开启线程,因为接口不会占用类的继承位置

import java.util.concurrent.Callable;
 
//1.创建一个实现Callable的实现类, 可以通过设置泛型,指定call方法返回的类型
class CallableThread implements Callable {
 
    @Override
    public Integer call() throws Exception {
        return null;
    }
 
}

4、使用线程池的方式:创建一个线程池,在Java中创建一个线程池可以通过java.util.concurrent.Executors工厂类来实现

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {

    public static void main(String[] args) {
        // 创建一个固定大小为5的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 提交10个任务到线程池处理
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executorService.submit(() -> {
                System.out.println("Executing task " + taskId + " via " + Thread.currentThread().getName());
                // 这里可以放置实际任务代码
            });
        }

        // 一旦提交了所有任务,就关闭线程池,不再接受新任务
        executorService.shutdown();
        
        // 注意:调用shutdown()方法并不会立即关闭线程池,而是等待所有任务执行完毕后才会关闭。
        // 如果需要立即关闭线程池,可以调用shutdownNow()方法,它会尝试停止所有正在执行的任务,
        // 并返回那些尚未开始执行的任务列表。
    }
}
11、设计模式中的单例模式:(饿汉式、懒汉式)

单例模式:保证类在程序中只存在一个实例对象,而不会创建多个实例对象,可以提高效率。在单利模式中一般只提供一个getInstance()方法来获取实例对象,不提供setInstance()方法,目的是为了避免再实例化出其他实例对象。

单例模式中有两种模式:懒汉式、饿汉式

懒汉式:

当类在加载的时候并不会直接被实例化,而是在调用的时候才会被实例化,这样就保证在不需要的时候就可以不用实例化。懒汉式在多线程模式下线程是不安全的。

package thread.example;
//单线程的懒汉模式
public class LazySingle {
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static LazySingle getInstance() {
        if(instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}
饿汉式:

指的是当类在加载的时候就会被实例化,后续在使用的时候只能有一个实例。在多线程的过程中,以为已经提前实例化,所以线程是安全的。

package thread.example;
//饿汉模式
public class HungrySingle {
//在类加载的时候就实例化了,类加载只有一次,所以值实例化出了一份该实例对象
    private static HungrySingle instance = new HungrySingle();
    public static HungrySingle getInstance() {
        return instance;
    }
}
12、什么是修饰符:

在java中,修饰符是一种用于修改类、方法、变量和其他实体的访问权限、行为或者是特征的关键字。

1、访问修饰符:

public:允许任何位置都进行访问

private:指的是仅允许在定义的类中进行访问

protected:允许在定义的类、子类和同一包中进行访问。

default:在同一个包内可见,不使用任何修饰符。

2、非访问修饰符:

static:用于将字段或者方法标记成动态,可以在没有对象实例的情况下访问。

final:用于修饰不可改变的类、方法或者是变量

abstract:用于创建抽象类和抽象方法

synchronized:用于保证在多线程环境中的同步访问

volatile:用于声明在多线程中共享的变量,以确保线程之间的可见性

transient:用于阻止变量在序列化过程中的持久化

native:用于指示方法中使用非java代码实现。

13、常用的类有哪些:

object类、string类、时间日期类、包装类、与数学相关的类

14、什么是io流:

在java中的io流分别是input和output,简单地说就是将外部的数据写入到内存中以及将内存数据写入到存储设备中。

15、JVM的原理是什么

jvm的主要的组成架构是程序计数器、java虚拟机栈、本地方法栈、堆、方法区

程序计数器:是一块较小的存储空间,是当前线程正在执行的那条字节码指令的地址。

java虚拟机栈:是描述java方法运行过程的模型。

本地方法栈:是为 JVM 运行 Native 方法准备的空间,由于很多 Native 方法都是用 C 语言实现的,所以它通常又叫 C 栈

堆:堆是用来存放对象的内存空间,几乎所有的对象都存储在堆中。

方法栈:Java 虚拟机规范中定义方法区是堆的一个逻辑部分。方法区存放以下信息:

        1、已经被虚拟机加载的类信息

        2、常量

        3、静态变量

        4、即时编译器编译后的代码

16、linuk中查看进程的命令
ps -aux
17、查看磁盘空间的命令:
top
18、在centos7中关闭防火墙的命令:
systemctl stop firewalld.service #停止firewall,临时关闭
systemctl disable firewalld.service #禁止firewall开机启动,永久禁止

查看防火墙的状态
systemctl status firewalld.service

  启动防火墙
systemctl start firewalld.service

关闭networkmanage服务:防止一个系统更新过后ip地址发生改变
    systemctl status NetworkManager #查看NetworkManager状态
    systemctl stop NetworkManager    #停止NetworkManager
    systemctl disable NetworkManager#禁止NetworkManager开机启动


19、linux中的解压的方式:
tar -zxvf 

你可能感兴趣的:(大数据面试总结,面试,java,职场和发展)