你见过老外的 Java 面试题吗(下)?

finalize 方法调用了多少次

关于 finalize 总结了以下几点:

finalize() 方法由垃圾收集器调用。对于每个对象,垃圾收集器只调用 finalize() 方法一次

finalize() 是 Object 的 protected 方法,子类可以覆盖该方法以实现资源清理工作,GC 在回收对象之前调用该方法。

finalize() 与 C++ 中的析构函数不是对应的。C++ 中的析构函数调用的时机是确定的(对象离开作用域或delete 掉),但 Java 中的 finalize 的调用时机是不确定的

如何理解 finalize() 的调用时机?

当垃圾回收器要宣告一个对象死亡时,至少要经过两次标记过程:

如果对象在进行可达性分析后发现没有和 GC Roots 相连接的引用链,就会被第一次标记,并且判断是否执行 finalize() 方法。

如果对象覆盖 finalize( ) 方法且未被虚拟机调用过,那么这个对象会被放置在 F-Queue 队列中,并在稍后由一个虚拟机自动建立的低优先级的 Finalize 线程区执行触发 finalize() 方法,但不承诺等待其运行结束。

finalization 的目的:对象逃脱死亡的最后一次机会。(只要重新与引用链上的任何一个对象建立关联即可。)但是不建议使用,运行代价高昂,不确定性大,且无法保证各个对象的调用顺序。

可用try-finally或其他替代。

this 和 super 关键字可以同时调用吗

super 从子类中调用父类的构造方法,this() 在同一类内调用其它方法。

尽管可以用 this 调用一个构造器,但却不能调用两个

this 和 super 不能同时出现在一个构造函数里面,因为 this 必然会调用其它的构造函数其它的构造函数必然也会有 super 语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义

从本质上讲,this 是一个指向本对象的指针, 然而 super 是一个Java关键字

你能在执行 main() 方法之前运行一个代码吗

在 Java 中,如果想在 main() 方法之前运行一段代码,只需要定义一个 static {} 静态代码块,就可以让 static 里的代码执行在 main() 方法之前。

public class staticFactory { static { System.out.println("static"); } public static void main(String[] args) { System.out.println("main"); } } // 输出 // static main

为什么 Java 本质上是动态的

Java 本质为静态语言,而不是动态语言。动态语言显著的特点是在程序运行时,可以改变程序结构或变量类型,典型的动态语言有 Python、ruby、javascript 等。Java 不是动态语言,但 Java 具有一定的动态性,表现在以下几个方面:

反射机制

动态字节码操作

动态编译

执行其他脚本代码

解释下守护进程线程

在Java中有两类线程:User Thread(用户线程)Daemon Thread(守护线程)

守护线程 是高优先级线程。JVM 会在终止之前等待任何用户线程完成其任务

用户线程 是低优先级线程。其唯一作用是为用户线程提供服务。

用个比较通俗的比如,任何一个守护线程都是整个 JVM 中所有非守护线程的保姆:

只要当前 JVM 实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

User 和 Daemon 两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread 已经全部退出运行了,只剩下 Daemon Thread 存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon 也就没有工作可做了,也就没有继续运行程序的必要了。

如何实现一个守护线程? NewThread daemonThread = new NewThread(); daemonThread.setDaemon(true); daemonThread.start();

使用守护线程有几点需要注意:

thread.setDaemon(true) 必须在 thread.start() 之前设置,否则会跑出一个 IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。

在 Daemon 线程中产生的新线程也是 Daemon 的。

不要认为所有的应用都可以分配给 Daemon 来进行服务,比如读写操作或者计算逻辑。

解释 >> 和 >>> 运算符之间的区别

虽然它们看上去比较像,但两者之间区别还是很大的。

>> 按位右移运算符。左操作数按位右移右操作数指定的位数。 即:A >> 2得到15即 1111 >>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。即:A>>>2得到15即0000 1111

我们能重载一个静态方法吗

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydwsz.html