javaEE每日一考(进阶汇总)

day09

1、Java能动态分配数组吗?

可以int[] ints = new int[10]这就是动态分配数组。

2、我怎么知道数组的长度?

数组名.length不就知道了。

3、数组有没有length()这个方法? String有没有length()这个方法

数组没有length()方法,有length属性。String有length()方法

4.请描述冒泡排序的思想

5.请描述数组的初始化方式

有两种,动态初始化和静态初始化。

6、请描述数组中可能会出现的异常

数组下标越界异常。ArrayIndexOutOfBoundsException。空指针异常 NullpointerException。

7、请描述你理解的对象数组

类类型,作为数组的数据类型时,构建的数组就是对象数组。

例如Student[] s = new Student[5]

8、请描述数组的扩容机制

首先定义一个更大类型的数组,再把原来数组元素复制到大的数组中,再让原来数组名指向大数组,最后遍历数组。

9、请描述基本类型数组元素的删除过程

就是使用一个新的数组,并将要保留的元素复制到新数组,从而实现删除效果

10.请描述你理解的动态数组

java 中的动态数组就是 ArrayList,它可以在运行时根据需要自动调整大小,让你可以方便地添加、删除和访问元素,无需手动处理数组大小的问题。它是一个非常实用的数据结构,用来代替传统的固定大小的数组,更加灵活方便

11、请描述你理解的数组拷贝算法思想

就是把一个元素拷贝到另一个元素中

12、请描述你理解的数组反转算法思想

就是把数组中的元素倒着输出。

13、请描述你理解的数组查找算法思想

   算法查找分为线性查找和二分法查找。线性查找就是遍历然后从第一个元素开始挨个查找与目标元素对比。直到找到元素或遍历整个数组。

        二分法查找(前提元素是有序的)就是先从正中间元素开始将目标元素与数组的中间元素进行比较,如果相等,则找到目标元素;如果目标元素小于中间元素,则在左半部分继续查找;如果目标元素大于中间元素,则在右半部分继续查找。通过逐步缩小查找范围,最终可以找到目标元素或确定不存在

day10

1.请描述你理解的二维数组

所谓二维数组,可以简单的理解为是一种“特殊”的一维数组,它的每个数组空间中保存的是一个一维数组。

2.请描述二维数组的遍历过程

通过双层嵌套for循环完成二维数组的遍历。外层循环控制行,内层循环控制列

外层循环每循环一次,内层循环,循环若干次

3.请描述快速排序算法的排序思想
  1. 从待排序的序列中挑选出一个基准元素(一般都是数列中的第一个值)
  2. 将数列中所有比基准元素小的元素摆放在基准元素的左侧,所有比基准元素大的元素摆放在基准元素的右侧(相同的元素可以到任一边)
  3. 按上述步骤(1,2),再对这左右两部分序列分别进行快速排序,直至整个序列变成有序序列。

4.请描述快速排序算法的代码实现过程

 

5.运行时异常与一般异常有何异同

运行时异常都是RuntimeException类及其子类异常,就是我们在开发中测试功能时程序终止,控制台出现的异常,比如:NullpointerException(空指针异常)IndexOutOfBoundsException(数组下标越界异常) ClassCastException(类转换异常)ArrayStoreException(数据存储异常,操作数组时类型不一致) IO操作的BufferOverflowException异常.非运行时异常也叫编译异常,通俗的说就是写代码时候就出现红线,需要try catch或者throws时出现的异常。

6.try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

会被执行,且在return之前执行

7.error和exception有什么区别

error指的是虚拟机无法解决的严重问题,一般不编写针对性的代码处理。

Exception该类型的异常是因为编程时的一些偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理以此尽可能避免这类异常的发生。

8.请仔细阅读下列测试代码,请问如何处理才能使程序正常输出“这是个异常,不是错误”,并且不会报告任何错误或者异常信息?

public class Test{

    public static void main(String[] args) {

        int[] arr ={1,1,1,1};

        for(int i = 0 ; i < 5;i++){

           System.out.println(arr[i]);

        }

        System.out.println("这是个异常,不是错误");

    }

}

9.请描述你理解的try-catch-finally

day11

1.请描述你理解的IO流的作用

用于读写数据

2.请描述I/O流的体系结构

按流向可以分为输入流,输出流。按操作文件类型可以分为字符流,字节流。

3.请描述什么情况下需要写出/读取一个字节数组

如果拷贝文件过大,一次读取一个字节太慢,此时就需要读取一个字节数组。

4.数据读写操作后,为什么要关闭流资源

因为如果在数据读写操作过后不关闭资源会造成资源泄露以及可能会引起文件锁定。

5.字节输入流读取文件时,需要注意什么?

一定要有目标文件,否则会报错。

6.请总结字节流与字符流的区别

字节流由字节组成,可以传输音频,视频,图片,文本等,用二进制处理数据。

字符流由字符组成,只能传输纯文本,采用Unicode编码,按虚拟机的ecode来处理,也就是要进行字符集的转化。

7.请描述字符流的原理

8.请描述字节、字符各自的输入流中read(无参)、read(有参)返回值有什么不同

Read(无参)是读取一个字节或字符,并返回其整数值表示。read(有参)是读取多个也就是一组,并返回其实际读取数

9.flush()和close()的区别

flush将缓冲区的数据刷新到本地文件中,刷新之后还可以继续往文件中写数据。

Close 释放资源,断开通道,无法再往文件中写数据。

10.请描述你理解的转换流

转换流可将字节流转换为字符流,然后可以用到字符流里面特有的方法。

11.请描述你理解的字节缓冲流

字节缓冲流就是用来提升性能的,它通过内部缓冲区来减少与底层数据源的实际读写操作,从而提高数据的读写效率。

12.请描述你理解的字符缓冲流

字符缓冲流也是用来提高程序性能的,它通过内部缓冲区来减少与底层数据源的实际读写操作,从而提高数据的读写效率。它与字节缓冲流的区别是字符缓冲流更适合读取一行,不会考虑字符编码,而字节缓冲流则要考虑字符编码来正确读写文本。

13.谈谈Java IO里面的常用类,字节流,字符流

字节流:

InputStream 和 OutputStream:这是字节流的基本抽象类,分别用于输入和输出字节数据。

FileInputStream 和 FileOutputStream:这些类用于读取和写入文件中的字节数据。

BufferedInputStream 和 BufferedOutputStream:这些类提供了带有缓冲区的字节输入和输出流,用于提高IO性能。

DataInputStream 和 DataOutputStream:这些类允许读写基本数据类型和字符串。

ObjectInputStream 和 ObjectOutputStream:这些类用于读写Java对象,可以实现对象的序列化和反序列化。

字符流:

Reader 和 Writer:这是字符流的基本抽象类,分别用于输入和输出字符数据。

FileReader 和 FileWriter:这些类用于读取和写入文件中的字符数据。

BufferedReader 和 BufferedWriter:这些类提供了带有缓冲区的字符输入和输出流,用于提高文本IO性能,并提供了便捷的读写方法,如 readLine()。

InputStreamReader 和 OutputStreamWriter:这些类用于将字节流转换为字符流,提供了字符编码的支持。

PrintWriter:这个类提供了便捷的写入方法,可以写入各种数据类型,类似于 System.out。

14.Java 中有几种类型的流?JDK为每种类型的流提供一些抽象类以供继承,请说出他们分别是哪些类?

字节流:

InputStream:字节输入流的抽象类,用于读取字节数据。

OutputStream:字节输出流的抽象类,用于写入字节数据。

字符流:

Reader:字符输入流的抽象类,用于读取字符数据。

Writer:字符输出流的抽象类,用于写入字符数据。

这些抽象类为不同类型的流提供了标准接口和方法,具体的流类(如FileInputStream、FileOutputStream、BufferedReader、BufferedWriter等)通过继承和实现这些抽象类来实现各种输入输出需求。这个继承体系使得Java的IO库能够更灵活地处理不同类型的数据和输入输出操作。

15.OutputStream里面的write()是什么意思?

将一个字节写入输出流

16.BufferedReader属于哪种流?他主要是用来做什么的?

缓冲输入流,主要用来提高读取字符串效率的,尤其是逐行读取文本的时候。

17.什么是缓冲区?有什么作用?

缓冲区是内存的一部分空间,用缓冲输入输出的数据。缓冲区又分为输入缓冲区和输出缓冲区。缓冲区又被称为缓存

18.字节流和字符流是什么?怎么转换?

InputStreamReader,OutStreamWriter

19.请描述你对System.out.println();的理解

输出语句的底层就是字节打印流(PrintStream)

20.请描述如何完成对象数据的读写

让对象类实现了 Serializable 接口。使用 ObjectOutputStream 将一个 Student 对象序列化到文件中,然后使用 ObjectInputStream 将序列化后的数据反序列化为对象,并输出对象的属性。

21.如何完成对象的深拷贝

通过实现Serializable接口,利用对象的序列化实现克隆,可以实现真正的深克隆

22.在代码断端要求较为方便地完成数据的换行,写入。该用那种流?

字符缓冲流

day12

1.请描述你对线程的理解

线程包含在进程中,线程是进程的一条执行路径。

2.请描述你对并发和并行的理解

并发是指在一段时间内宏观上同时(交替执行)去处理多个任务

并行指同一时刻,多个任务确实真的在运行

3.请描述线程的创建方式及目前你理解的他们之间的区别

线程创建方式一共有4种。第一种是继承Thread类重写run方法。第二种是实现Runnable接口,重写run方法,然后通过Thread类的对象代理启动和执行我们的线程体run方法。第三种是实现Callable接口,重写call。然后创建

FutureTask对象。第四种 方式就是使用线程池,提前创建好多个线程,放入线程池,使用时候直接获取,使用完放回线程池。

4.请描述线程的常用方法

public Thread() :分配一个新的线程对象。

public Thread(String name) :分配一个指定名字的新的线程对象。

public Thread(Runnable target) :指定创建线程的目标对象,它实现了Runnable接口中的run方法

public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

public void run() :此线程要执行的任务在此处定义代码。

public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。

public String getName() :获取当前线程名称

public void setName(String name)设置该线程名称。

public static Thread currentThread() :返回对当前正在执行的线程对象的引用。在Thread子类中就是this,通常用于主线程和Runnable实现类

public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。

void join() 插入线程。

5.请描述给线程赋值名字的方式

可以在线程的构造方法中指定线程名称,也可以通过setname()重新设置线程名称。

6.new Thread(Runnable)为什么可以接收一个FutureTask参数?

FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值

7.请描述目前你理解的线程生命周期

线程生命周期有5种状态:新建,就绪,运行,阻塞,死亡。其中就绪和运行可规为可运行一大类。

8.请描述你理解的等待与唤醒机制

当前线程执行过程中遇到遇到Object类的wait,Thread类的join,LockSupport类的park方法,并且在调用这些方法时,没有指定时间,那么当前线程会进入WAITING状态,直到被唤醒。

通过Object类的wait进入WAITING状态的要有Object的notify/notifyAll唤醒;

通过Thread类的join进入WAITING状态,只有调用join方法的线程对象结束才能让当前线程恢复;

9.请描述你理解的同步和异步

同步(Synchronization)是管理多线程共享资源访问的机制,避免并发问题;异步(Asynchronous)是任务并行执行的编程方式,提升程序性能和响应性,通过回调或工具处理任务完成。

10.请描述你对临界区的理解

临界区(Critical Section)是多线程编程中的一个概念,指的是一段代码区域,同时只能被一个线程执行,以避免多个线程并发访问共享资源而引发的数据不一致或竞态条件等问题。通过同步机制,如使用synchronized关键字,可以将临界区限制在一个线程内,确保在任何时候只有一个线程可以访问该区域,从而保证数据的正确性和一致性。有效的临界区管理是确保多线程程序正确运行的关键。

11.请描述你对Synchronized的理解

Synchronized是一个线程同步锁。它可以用于方法或代码块,创建临界区确保同一时刻只有一个线程可以进入被同步的代码区域,避免多线程并发访问共享资源导致的数据不一致和竞态条件问题。通过获取对象的锁来实现同步,只有获得锁的线程才能执行被同步的代码。

12.如果把 synchronized(obj) 放在 for 循环的外面,如何理解?

就是把整个循环给锁上了,每次只有一个线程能进入。

13.如果 t1 synchronized(obj1) 而 t2 synchronized(obj2) 会怎样运作?

Obj1和obj2是两个不同的锁对象,互相之间不会产生影响,可以同时被不同线程获取。

14.如果 t1 synchronized(obj) 而 t2 没有加会怎么样?如何理解?

会导致多线程并发访问共享资源obj时可能出现数据不一致的问题。这是因为t1获得了obj的锁,进入了临界区,而t2没有锁限制,可以在任何时间访问obj,这可能导致t1和t2同时读写obj的状态,也就是t2脏读。导致数据不一致。

15.请描述你对线程安全问题的理解

当多个线程同时操作一个共享数据时,可能会出现数据不一致的情况。

16.请描述你对线程同步的理解

线程同步就是一套协调多个线程操作共享数据时,用于保证数据安全的一种机制(工具)

17.请描述你对内置锁的理解

内置锁是Java中通过synchronized关键字实现的基本线程同步机制。每个对象都关联一个内置锁,用于控制多个线程对共享资源的访问。获取内置锁后,线程可以进入临界区执行同步代码,其他线程将被阻塞。内置锁具有互斥性、可重入性和等待通知机制。

18.继承Thread类和是实现Runnable接口有什么区别?

继承Tread类编程简单,可以直接使用Tread类中的方法,可扩展性叫较差,不能再继承其他类。实现Runnable接口扩展性强,实现该接口的同时还可以继承其他的类,但是编程较复杂,不能直接使用Thread类中的方法。

19.锁块中的锁对象有什么注意事项

Java中任意一个对象都有一个内置锁, 所以任意一个对象都可以作为锁对象

同步代码块就是操作共享数据的代码, 也称为临界区代码

注意: 线程想要同步, 必须使用同一个锁对象; 同样,只要使用了同一个锁对象的同步代码块就可以实现同步

注意: 不仅在修改数据时需要同步, 在读取共享数据时也需要同步

20.请就线程提升效率问题谈谈你的理解

线程能最大限度的提高cpu使用效率。

21.显示锁Lock在使用时,需要注意什么?

显示锁在使用时要记得手动开启和关闭锁,而且它只有代码块锁没有方法锁。

day13

1.请描述线程池存在的意义
  1. 提高响应速度(减少了创建新线程的时间)
  2. 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  3. 便于线程管理  corePoolSize:核心池的大小      maximumPoolSize:最大线程数keepAliveTime:线程没有任务时最多保持多长时间后会终止
2.请描述线程生命周期的各个状态的作用及转换流程

3.请描述notify()和notifyAll()的区别

Notify()是唤醒一个锁

notifyAll()是唤醒所有锁。

4.请描述线程池的工作流程

5.请描述线程池的工作原理

1,创建一个池子,池子中是空的

2,提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还池子,下次再提交任务时,不需要创建新的线程,直接复用已有的线程即可。

3,但是如果提交任务时,池子红没有空闲线程,也无法创建新的线程,任务就会排队等待。

6.请描述ThreadPoolExecutor的参数的作用

corePoolSize:   核心线程的最大值,不能小于0

maximumPoolSize:最大线程数,不能小于等于0,maximumPoolSize >=     corePoolSize

keepAliveTime:  空闲线程最大存活时间,不能小于0

unit:                   时间单位

workQueue:      任务队列,不能为null

threadFactory:  创建线程工厂,不能为null     

handler:             任务的拒绝策略,不能为null   

7.请描述自定义线程池的过程

8.请描述JDK中常见线程池的创建

day14

1.请描述JDK中线程池中的线程是如何创建的

        Jdk线程池中的线程是被线程工厂创建出来的。

2.请描述线程池的工作原理

提交任务时,线程池会创建一个线程,这个线程会执行任务,任务执行完毕后,线程会回到线程池;

再次提交任务后,会继续使用这个线程来执行任务,

如果线程池的线程不够了,并且也无法再创建新的线程时,则任务会等待

3.请描述已学过的并发工具类的作用

ConcurrentHashMap:线程安全,并且是分段锁,效率比hashtable高

CountDownLatch: 表示计数器,一个线程运行完之后可以调用countDown()方法来使计数器减1,当计数器为0时,调用了CountDownLatch的await()方法的线程就会解除阻塞状态,继续运行。

CyclicBarrier: 可以使一组线程到达屏障时进入阻塞状态,当最后一个线程也到达屏障时,这些线程就是解除阻塞状态,继续运行

Semaphore: 用来控制每次执行任务时最多几个线程来执行,其他线程进入阻塞状态。

使用方法为创建Semaphore的对象,用对象名.acquire()方法来获取访问,使用完毕之后用对象名.release()方法来释放访问。

Exchanger: 用来控制每次执行任务时最多几个线程来执行,其他线程进入阻塞状态。

使用方法为创建Semaphore的对象,用对象名.acquire()方法来获取访问,使用完毕之后用对象名.release()方法来释放访问

4.请描述你理解的sleep()和wait()方法的区别

1)Sleep() 是 Thread类下的 方法,而 wait() 是 Object类的 的方法

2) sleep() 不需要强制和 synchronized 配合使用,但 wait() 需要和 synchronized 一起用

3)sleep() 在睡眠的同时,不会释放对象锁的,但 wait() 在等待的时候会释放对象锁

4)它们状态 TIMED_WAITING

5.请描述你对线程变量的安全性分析

线程变量的安全性分析是确保多线程程序中的共享变量在并发访问时能够正确地被访问和修改,避免出现数据竞争和不确定的行为。

首先,线程变量的安全性取决于变量的可见性和原子性。

        可见性:多个线程对同一个变量的修改需要能够被其他线程及时地感知到。如果一个线程对变量进行了修改,而其他线程无法看到这个修改,就可能导致不一致的结果。在保证可见性方面,可以使用 volatile 关键字来修饰变量,强制线程从主存中读取变量的最新值;或者使用 synchronized 关键字来保证变量的可见性和原子性。

        原子性:原子操作是指不可再分的操作,要么全部执行成功,要么全部不执行。如果一个操作不是原子操作,那么在多线程环境下可能会出现竞态条件(race condition),导致数据不一致。为了保证变量的原子性操作,可以使用 synchronized 关键字或者使用原子类(如 Atomic* 类)来保证操作的原子性。

在进行线程安全性分析时,需要根据具体的情况选择合适的方法和工具。不同的场景可能需要不同的策略来保障线程安全性,从而确保程序在多线程环境中的正确性和稳定性。

此外,需要考虑线程间的同步和互斥机制,以确保线程安全。

        同步机制:通过使用锁(如 synchronized 关键字或 Lock 接口)来保证多个线程对共享变量的互斥访问。同一时刻只允许一个线程访问共享变量,其他线程需要等待。

        互斥机制:通过使用互斥量或信号量等机制,限制对共享资源的访问。这样可以防止多个线程同时访问和修改同一份数据,避免数据竞争。

        需要注意的是,在使用线程变量时,还要考虑到线程安全性的开销和性能问题。过多的同步和锁可能会导致性能下降,因此需要根据实际情况进行权衡和选择。

        总结起来,线程变量的安全性分析涉及到可见性、原子性、同步和互斥机制等方面的考虑,通过合理地设计和使用这些机制,可以确保多线程程序的正确性和稳定性

day15

一、根据指定的代码描述清楚String字符串在内存中的地址和指向问题
  • 比如

String str1 = “abc”;
System.out.println(str1 == “abc”);

  • 步骤:

1.栈中开辟一块空间存放引用str1,

2.String池中开辟一块空间,存放String常量"abc",

3.引用str1指向池中String常量"abc",

4.str1所指代的地址即常量"abc"所在地址,输出为true

第一题:

String str2 = new String(“abc”);
System.out.println(str2 == “abc”);

步骤:

  1. 栈中开辟一块地址空间存放strl2,
  2. 堆中开辟一快空间,strl2指向这个地址
  3. String池中开辟一块空间存放abc
  4. 堆中开辟的那个空间指向String“abc”
  5. Strl2指代的地址是堆空间中的那块地址,不是string池中的地址,输出为false。

第二题:

String str3 = new String(“abc”);
System.out.println(str3 == str2);

步骤:

1.栈中开辟一块地址空间存放strl3,

2.堆中开辟一快空间,strl3指向这个地址

3.strl3指向堆中的那个地址,那个地址又指向字符串常量池中的abc

4.虽然strl2和strl3,最终指向的值都是abc 但是它俩的堆中地址不一样。所以输出为false

第三题:

String str4 = “a” + “b”;
System.out.println(str4 == “ab”);

步骤:

常量+常量=常量

所以结果为true

第四题:

final String s = “a”;
String str5 = s + “b”;
System.out.println(str5 == “ab”);

步骤:

Final修饰为常量,常量加常量为常量,结果为true

第五题:

String s1 = “a”;
String s2 = “b”;
String str6 = s1 + s2;
System.out.println(str6 == “ab”);

步骤:

变量+变量等于变量。所以结果为false

第六题:

String str7 = “abc”.substring(0, 2);

步骤:

ab

第七题:

String str8 = “abc”.toUpperCase();

步骤:ABC

二、String 对象怎么就不可变?

String底层是字符数组常量,因此String类的所有方法都不会改变源字符串,而是返回一个新的字符串。

因为String底层使用字符数组保存字符串的每个字符, 该字符数组使用final修饰无法重新赋值(地址的改变),  String类也没有提供相应的方法修改value数组的元素, 并且String类还是final修饰的,无法定义子类.

三、请描述你对以下代码的理解
String s1 = "abc";
s1 += "def";
System.out.println(s1);  // s1 = "abcdef"
创建一个引用对象的时候 真正的地址是在堆中分配空间,然后这个堆中空间指向字符串常量池中因为字符串相加而另外开辟的一个元空间,这个空间的值是相加之后的两个字符串的值存放的地点。所以结果也就是abcdef
四.字符串是如何存储的?

Java 中的字符串存储方式主要包括字符串池和堆内存。字符串池用于存储字面量,以实现共享和节省内存,而堆内存用于存储通过构造方法等方式创建的字符串对象。

五、请描述你理解的正则表达式能解决的问题

正则表达式通常被用来检索、替换那些符合某个规则的文本

六、请描述你理解的常量池

   存放常量的池子,就叫常量池。

七、请描述你理解的字符串不可变性

对字符变量重新赋值时,需要重新指定一个字符串常量的位置进行赋值,不能在原有的位置修改。

当对现有的字符串进行拼接操作时,需要重新开辟空间保存拼接以后的字符串,不能在原有的位置修改

八、请描述String、StringBuffer、StringBuilder之间的区别?

1.String 底层采用的是final char[] 进行存储字符串,是不可变的字符序列,每次拼接字符串都会开辟新的内存空间。拼接字符串效率非常低下。​​​​​​​

2.StringBuffer 底层采用char[] 进行存储字符串,数组的长度默认16。是可变的字符序列,StringBuffer对象会根据使用情况扩充字符缓冲(原来的2倍+2这种算法扩充)。拼接字符串效率较String来说提高很多。方法都是被synchronized修饰的,都是线程安全的。

3.StringBuilder和StringBuffer功能一样,只是底层方法没有被synchronized修饰,是线程不安全的,执行效率高于StringBuffer ;

4.所以开发一般对字符串的增加、删除、插入操作一般用StringBuffer效率更高,其他操作用String更为便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值