一、你在工作中常用的几个设计模式(不少于3种)
1.单例模式
(1)什么是
- 确保一个类只有一个实例,并提供一个全局访问点。
2.工厂模式
(1)什么是
- 定义一个用于创建对象的接口,但让子类决定实例化哪一个类。
3.观察者模式
(1)什么是
- 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
4.策略模式
(1)什么是
- 定义一系列算法,将每个算法封装起来,并使它们可以互换。
二、请写一个简单的 hash 算法,形成一个新的整数数组。
1.思路
SimpleHashAlgorithm
类包含了一个静态方法 hashArray
,该方法接受一个整数数组 inputArray
和一个哈希模数 hashModulus
作为参数。它遍历输入数组,对每个元素应用取模哈希函数,并将结果存储在新的数组 hashedArray
中。最后,hashArray
方法返回这个新的整数数组。
在 main
方法中,我们创建了一个示例输入数组 inputArray
和一个哈希模数 hashModulus
,然后调用 hashArray
方法并打印出哈希后的数组结果。
2.代码
public class SimpleHashAlgorithm {
public static int[] hashArray(int[] inputArray, int hashModulus) {
// 初始化一个新的数组来存储哈希值,大小与输入数组相同
int[] hashedArray = new int[inputArray.length];
// 遍历输入数组中的每个元素
for (int i = 0; i < inputArray.length; i++) {
// 对每个元素应用简单的哈希函数(取模)
int hashValue = inputArray[i] % hashModulus;
// 将哈希值存储在新的数组中
hashedArray[i] = hashValue;
}
// 返回哈希后的新整数数组
return hashedArray;
}
public static void main(String[] args) {
// 示例输入数组
int[] inputArray = {10, 20, 30, 40, 50};
// 哈希模数
int hashModulus = 7;
// 调用hashArray方法并获取哈希后的数组
int[] hashedArray = hashArray(inputArray, hashModulus);
// 打印哈希后的数组
for (int hashValue : hashedArray) {
System.out.print(hashValue + " ");
}
// 输出: 3 6 2 5 1
}
}
三、有3个线程t1.t2.t3,要求 t1.2同时运行,等这两个线程都运行结束后,在运行t3,请写出简
要代码
1.思路
我们创建了三个线程t1、t2和t3。线程t1和t2分别执行一些模拟的工作(在这里是通过Thread.sleep
来模拟的,表示线程正在运行)。线程t3在启动后,会立即调用t1.join()
和t2.join()
,这意味着t3会等待t1和t2都运行结束后才会继续执行自己的任务。
当你运行这个程序时,你会看到t1和t2线程几乎同时开始运行(取决于操作系统的线程调度),并且当它们都运行结束后,t3线程才会开始运行。
2.代码
public class ThreadExample {
public static void main(String[] args) {
// 创建线程t1
Thread t1 = new Thread(() -> {
// 模拟t1线程的工作
System.out.println("t1 线程开始运行");
try {
Thread.sleep(1000); // 假设t1线程需要运行1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 线程运行结束");
});
// 创建线程t2
Thread t2 = new Thread(() -> {
// 模拟t2线程的工作
System.out.println("t2 线程开始运行");
try {
Thread.sleep(1000); // 假设t2线程也需要运行1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2 线程运行结束");
});
// 创建线程t3
Thread t3 = new Thread(() -> {
// 等待t1和t2线程都结束后,t3线程开始运行
try {
t1.join(); // 等待t1线程结束
t2.join(); // 等待t2线程结束
} catch (InterruptedException e) {
e.printStackTrace();
}
// 模拟t3线程的工作
System.out.println("t3 线程开始运行");
try {
Thread.sleep(1000); // 假设t3线程需要运行1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t3 线程运行结束");
});
// 启动线程t1和t2
t1.start();
t2.start();
// 启动线程t3(它会自动等待t1和t2结束)
t3.start();
}
}
四、利用java 反射,如何获取一个java 本体类(不包含super)中全部 public 字段列表,请写
出简要代码
1.思路
首先定义了一个包含几个字段的示例类MyClass
。然后,在main
方法中,我们通过MyClass.class
获取了MyClass
类的Class
对象。接下来,我们调用getFields
方法来获取MyClass
类中所有public
字段的数组。最后,我们遍历这个数组,并打印出每个字段的名称。
当你运行这个程序时,你会看到输出如下:
Public field: publicField1
Public field: publicField2
2.代码
import java.lang.reflect.Field;
public class ReflectionExample {
// 示例类,用于演示反射
public static class MyClass {
public int publicField1;
public String publicField2;
protected int protectedField; // 这个字段不会被获取,因为它不是public
private String privateField; // 这个字段也不会被获取,因为它不是public
}
public static void main(String[] args) {
try {
// 获取MyClass类的Class对象
Class<?> myClass = MyClass.class;
// 获取MyClass类中所有public字段
Field[] publicFields = myClass.getFields();
// 遍历并打印所有public字段的名称
for (Field field : publicFields) {
System.out.println("Public field: " + field.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
五、写出一个int[]数组,快速排序(或任意非冒泡排序)的过程,文字描述或代码描述均可。
1.文字描述
- 选择基准:从数组中选择一个元素作为基准(通常选择第一个元素、最后一个元素或随机一个元素)。
- 分区:重新排列数组,使得所有比基准小的元素都移动到基准的左边,所有比基准大的元素都移动到基准的右边。基准元素在其正确的位置上。
- 递归排序:递归地将小于基准值元素的子数组和大于基准值元素的子数组进行排序。
2.代码描述
public class QuickSortExample {
public static void quickSort(int[] array, int low, int high) {
if (low < high) {
// 找到分区点
int pi = partition(array, low, high);
// 递归地对左子数组和右子数组进行排序
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
private static int partition(int[] array, int low, int high) {
int pivot = array[high]; // 选择最后一个元素作为基准
int i = (low - 1); // 较小元素的索引
for (int j = low; j < high; j++) {
// 如果当前元素小于或等于基准
if (array[j] <= pivot) {
i++;
// 交换array[i]和array[j]
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
// 交换array[i+1]和array[high](或基准)
int temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1; // 返回分区点的索引
}
public static void main(String[] args) {
int[] array = {10, 7, 8, 9, 1, 5};
int n = array.length;
System.out.println(" 排序前的数组:");
printArray(array);
quickSort(array, 0, n - 1);
System.out.println(" 排序后的数组:");
printArray(array);
}
private static void printArray(int[] array) {
for (int i : array) {
System.out.print(i + " ");
}
System.out.println();
}
}
六、 同步锁是一个解决线程间共享变量的基本方法,但如果请求过多,他会阻塞线程,请列出至少3种,不用同步锁也能解决多线程共享变量的方法
1.原子类:Java 提供了 java.util.concurrent.atomic 包中的原子类,如 AtomicInteger、AtomicLong、AtomicBoolean 等,这些类提供了无锁的原子操作,可以在多线程环境下安全地更新共享变量。
2.不可变对象:不可变对象一旦创建后就不能修改,因此在多线程环境中是线程安全的。通过使用不可变对象,可以避免同步锁的使用。
3.线程局部变量:ThreadLocal 提供了线程局部的变量副本,每个线程都有自己独立的变量副本,互不影响,因此不需要同步锁。
1.原子类
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
private static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) {
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.incrementAndGet();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final counter value: " + counter.get());
}
}
2.不可变对象
public class ThreadLocalExample {
private static final ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<>();
public static void main(String[] args) {
Runnable task = () -> {
threadLocalCounter.set(0);
for (int i = 0; i < 1000; i++) {
threadLocalCounter.set(threadLocalCounter.get() + 1);
}
System.out.println("Thread " + Thread.currentThread().getId() + " counter: " + threadLocalCounter.get());
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.线程局部变量
public class ThreadLocalExample {
private static final ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<>();
public static void main(String[] args) {
Runnable task = () -> {
threadLocalCounter.set(0);
for (int i = 0; i < 1000; i++) {
threadLocalCounter.set(threadLocalCounter.get() + 1);
}
System.out.println("Thread " + Thread.currentThread().getId() + " counter: " + threadLocalCounter.get());
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
七、写出在Iinux 查找文件并删除的命令、写出将应用以后台模式运行的命令、写出启动java 应用的命令(要求新生代和老生代配置得当,避免 OOM )
1.写出在Iinux 查找文件并删除的命令
find /path/to/search -name "filename" | xargs rm
2.写出将应用以后台模式运行的命令
nohup your_command &
3.写出启动java 应用的命令(要求新生代和老生代配置得当,避免 OOM )
java -Xms1g -Xmx2g -XX:NewSize=512m -XX:MaxNewSize=1g -jar your_application.jar