1. JDBC(Java Database Connectivity)事务是用于管理数据库操作的一组特性,确保数据的完整性和一致性。以下是对JDBC事务的描述:
- JDBC事务属于Java事务的一种:JDBC事务是Java程序用来管理数据库操作的事务。
- JDBC事务属于本地事务类型:容器事务通常是指在企业级应用服务器(如WebLogic、JBoss等)中,由容器管理的事务。而JDBC事务是由开发者在代码中手动管理的,属于本地事务(Local Transaction)。
- JDBC事务可以保证操作的完整性和一致性:事务的四大特性(ACID)之一就是保证操作的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
- JDBC事务是由Connection发起的,并由Connection控制:在JDBC中,事务的控制是通过
Connection
对象来完成的,包括设置事务的隔离级别、提交(commit)和回滚(rollback)操作。
2. 关于constructor的描述:
- class中的constructor可以省略:在Java中,如果开发者没有显式定义构造器(constructor),编译器会提供一个默认的构造器。
- constructor必须与class同名,但方法不能与class同名:构造器的名称必须与类名完全相同,而方法(包括构造器以外的任何方法)不能与类名相同。
- constructor在一个对象被new时执行:构造器是在创建新对象时通过
new
关键字调用的。 - 一个class可以定义多个constructor:一个类可以定义多个构造器,只要它们的参数列表不同(即构造器重载)。
3.关于变量命名规则的描述:
- 在Java中,变量名可以包含字母、下划线(_)和美元符号($),但数字不能作为变量名的开头。变量名必须以字母、下划线(_)或美元符号($)开始,可以在变量名的中间或结尾处包含数字。
- Java是大小写敏感的,所以
A
和a
是两个不同的变量名。 - 不同类型的变量,可以起相同的名字。在Java中,变量的作用域是重要的,如果你在不同的作用域内声明变量,那么即使变量名相同,它们也代表不同的变量。例如,在成员变量和局部变量中可以有相同的名字,因为它们处于不同的作用域。
4. 在Java中,wait()
方法和 notify()
/notifyAll()
方法与对象的监视器(monitor)有关,它们用于控制线程之间的协调。
wait()
方法:当一个线程执行到wait()
方法时,它会释放调用对象的锁(即对象的监视器),然后让出CPU资源,并进入等待池(waiting pool)等待被唤醒。在等待期间,其他线程可以获取该对象的锁并执行。notify()
方法:用于唤醒在此对象上等待的单个线程。被唤醒的线程将从等待池(waiting pool)进入锁池(blocked pool),并尝试获取对象的锁。notifyAll()
方法:用于唤醒在此对象上等待的所有线程。所有被唤醒的线程将从等待池进入锁池,并尝试获取对象的锁。
需要注意的是,notify()
和notifyAll()
不会释放锁,它们只是唤醒等待的线程。锁的释放是由wait()
方法执行的。而被唤醒的线程需要在锁池中等待重新获取对象的锁后才能继续执行。
5.
- 在Java中,
Void
类是Class
类的静态内部类,而不是子类。Void
类用于表示void
类型的Class对象。 - 并没有一个名为
Wrapper
的类。 - Java中的包装类都是
java.lang.Number
类的子类。Integer
类是java.lang.Number
类的子类,它用于包装int
类型的值。
6. 关于Java并发的描述:
CopyOnWriteArrayList
适用于读多写少的场景。它通过复制底层数组来实现写操作,这样在读操作时不需要加锁,从而提高读操作的并发性能。- ReadWriteLock适用于读多写少的并发场景:
ReadWriteLock
维护了一对相关联的锁——一个用于只读操作的读锁和一个用于写操作的写锁。它允许多个读操作并发进行,但写操作在执行时会阻塞所有的读操作和写操作,适用于读多写少的场景。 ConcurrentHashMap
在进行写操作时,并不是完全不需要加锁,而是采用了一种分段锁的策略,即对部分数据进行加锁,从而允许在读操作时实现更高的并发性。在读操作时,通常情况下是不需要加锁的,因为ConcurrentHashMap
的设计允许多个线程并发地访问不同的段。- 即使给
int
类型的成员变量i
加上volatile
关键字,i++
操作在多线程环境下也不是线程安全的。volatile
关键字确保了变量的可见性,但是i++
操作涉及到多个步骤(读取、增加、写入),这些步骤不能通过volatile
保证原子性。
7. 直接编译不通过。NumberFormatException属于运行时异常。
public class Example1 {
public static void main(String[] args) {
try {
System.out.print(Integer.parseInt("forty"));
} catch (RuntimeException e) {
System.out.println("Runtime");
} catch (NumberFormatException e) { //编译错误:Exception 'java.lang.NumberFormatException' has already been caught
System.out.println("Number");
}
}
}
//只输出 Number
public class Example2 {
public static void main(String[] args) {
try {
System.out.print(Integer.parseInt("forty"));
}
catch (NumberFormatException e) {
System.out.println("Number");
}
catch (RuntimeException e) {
System.out.println("Runtime");
}
}
}
8. 关于this和super关键字的描述:
- this和super不能用在main()方法中。main方法是静态方法,是随着类加载而加载,不参与对象的创建过程。而this与super是表示本类对象和父类对象,是随着对象加载而加载,在对象的上下文中才有意义,所以不能用在main方法中。
this
关键字代表当前对象的引用,而super
关键字用于引用父类(超类)的属性和方法。它们并不直接指向内存地址,而是用于引用对象和父类中的内容。
9. 在Java中,线程的阻塞状态是指线程因为某些原因(如等待监视器锁、等待I/O操作完成等)暂时无法继续执行的情况。
- sleep():
Thread.sleep()
方法会使当前线程暂停执行指定的时间,让出CPU资源给其他线程,但线程本身不会进入阻塞状态,它只是被暂停了。 - suspend():
Thread.suspend()
方法会使线程挂起,即进入阻塞状态,直到另一个线程调用Thread.resume()
方法。不过,需要注意的是,suspend
和resume
方法已经过时(deprecated),因为它们存在很多问题,如可能导致死锁。 - wait():
Object.wait()
方法会使当前线程进入等待状态,直到其他线程调用相同对象的Object.notify()
或Object.notifyAll()
方法。在等待期间,线程会释放对象的监视器。 - yield():
Thread.yield()
方法暗示线程调度器,当前线程愿意让出对CPU的使用权,但这并不是一个阻塞状态,它只是给线程调度器一个提示,实际的行为取决于线程调度器的实现。只是提示线程调度器当前线程愿意让出CPU,而不会进入任何形式的阻塞状态。
10.
String[] arr = new String[10];
System.out.println(arr.length); //10
获取arr数组长度的方法使用.length属性,而size()不是数组属性或者方法
11. 在Java中,内存的分配和释放是由垃圾回收器(Garbage Collector,GC)自动管理的。程序员不能直接控制内存的释放,但可以采取一些措施来建议垃圾回收器回收对象。Java中的垃圾回收是自动的,程序员不能直接控制垃圾回收器的运行。所有的“释放内存”的操作都是建议性的,真正的回收时机和行为由垃圾回收器决定。
12.
- abstract 不能与 final 并列修饰同一个类:
abstract
修饰符表示类是抽象的,意味着它可以包含抽象方法,并且不能被实例化。final
修饰符表示类不能被继承。一个类不能同时是抽象的和最终的,因为这两者是矛盾的。 - abstract 类中可以有 private 的成员:抽象类中可以有各种访问级别的成员,包括
private
成员。private
成员只能在类内部被访问。 - abstract 方法必须在 abstract 类中:抽象方法必须在抽象类中声明,因为非抽象类中包含抽象方法会导致编译错误。
- 抽象类中的方法不一定都是抽象方法:抽象类可以包含抽象方法,也可以包含非抽象的、有具体实现的方法。
- static 方法中不能处理非 static 的属性:
static
方法属于类,而非类的实例。非static
属性属于类的实例。因此,static
方法不能直接访问非static
属性,除非通过类的实例来引用。
13. 懒汉单例模式
懒汉式单例模式指的是在单例类中,提供了一个静态的实例变量,但是没有初始化(即初始化为null),只有当第一次使用的时候才创建实例。
//最基本的懒汉式单例模式通常是不线程安全的。
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//同步整个方法:在 getInstance() 方法上使用 synchronized 关键字,但这会影响性能。
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//同步代码块:只在创建实例的代码块上使用 synchronized,这样可以减少同步的开销。
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
14. 基本数据类型可以自动装箱为包装类型
public class Example {
public static void main(String[] args){
add(10,10); //此处编译不通过。因为add指向不明确,两个方法都匹配。注释掉任一个,另一个都能运行出结果。
}
public static void add(Integer a,int b){
System.out.println("A");
}
public static void add(int a,Integer b){
System.out.println("B");
}
}
15. 在Java中,线程池(ThreadPoolExecutor
)有以下几种状态,这些状态描述了线程池的生命周期:
- Running:这是线程池的正常运行状态,默认状态,初始化状态,即线程池一旦被创建就处于此状态,并且线程池中的任务数为0。在这种状态下,线程池可以接受新任务,并且可以处理阻塞队列中的任务。
- Shutdown:在调用线程池的
shutdown()
方法后,线程池由RUNNING -> SHUTDOWN,线程池进入此状态。此时,线程池不再接受新任务,但是会处理完阻塞队列中已有的任务,即已经提交的任务。 - Stop:在调用线程池的
shutdownNow()
方法后,线程池进入此状态。此时,线程池会尝试停止所有正在执行的任务,并且不再处理阻塞队列中的任务,并且会中断正在处理的任务。调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。 - Tidying:当线程池从非Running状态转换时,它会进入这个状态。在这个阶段,线程池会执行一些清理工作,比如关闭资源。在这个状态下,线程池不接受新的任务,也不处理等待队列中的任务。如果线程状态已经是SHUTDOWN了,并且线程中以及队列中都没有任务时,线程池就会由SHUTDOWN-->TIDYING;如果线程池状态为STOP,那么当线程池把所有的任务都给清理干净时,线程池就会由STOP-->TIDYING。
- Terminated:当线程池完全停止后,包括所有任务都已执行完毕,并且清理工作也已完成,线程池就会进入Terminated状态。线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。