At Toptal, 我们对Java开发人员进行了彻底的筛选,以确保我们只为您匹配最优秀的人才. 在200多个中,每年有5000人申请加入Toptal网络, 只有不到3%的人能达标. 你将与工程专家(而不是一般的招聘人员或人力资源代表)一起了解你的目标, technical needs, and team dynamics. 最终的结果是:经过专家审查的人才从我们的网络,定制匹配,以满足您的业务需求.
Java mastery, 就像生活中的许多技能一样, 要充分利用它的力量需要时间和健康的好奇心. 因此,如我们的帖子所述 寻找少数精英, an effective recruiting process needs to evaluate many dimensions of a candidate beyond just technical knowledge; attributes such as drive, integrity, 创造力同样是一个软件开发大师的基本属性. 评估候选人的这些方面,然后可以用问题(例如本文中提出的问题)来扩充,以帮助确定哪些人是真正的高质量Java专家.
Abstract classes may not be instantiated directly; only their concrete subclasses are instantiable.
一个类可以被声明为抽象的,即使它没有抽象方法. 这将阻止该类被实例化. This can be useful, for example, 如果类层次结构中的基类没有抽象方法,但本身不打算被实例化.
问:比较和对比已检查和未检查的异常. Provide examples.
未经检查的异常 例外是 not 被认为是可恢复的. Java不会因为它们表示异常而强制您捕获或处理它们, 代码中的意外问题,例如 NullPointerException, ArithmeticException and IndexOutOfBoundsException. 也就是说,这些都是你需要修复或预防的问题. 未检查异常都派生自 RuntimeException.
Checked exceptions 例外情况是 are 被认为是可恢复的. Checked exceptions must explicitly be specified as part of a method’s API; that is, 可能抛出一个或多个受控异常的方法必须将这些潜在异常列为其方法声明的一部分(Java编译器实际上会强制执行这一点)。.
当调用引发异常的方法时,调用者必须处理(i.e.(捕获)这些异常,或者必须自己抛出它们. For example, 如果方法抛出检查异常, 调用者可能决定忽略错误并继续(吞下它), 向用户显示一个对话框, 或者重新抛出异常,让调用链更上层的方法处理它(在这种情况下,它还必须声明它抛出检查异常)。.
There may be times, though, 当您想要限制允许传递给泛型类型参数的类型类型时. For example, 对数字进行操作的方法可能只想接受Number或其子类的实例. 这是在一般情况下使用 有界型参数,其中列出了类型参数的名称,后面跟着 extends keyword. For example:
//确定三个可比对象中最大的
public static > T maximum(T x, T y, T z) {
T max = x; // assume x is initially the largest
if ( y.compareTo( max ) > 0 ) {
max = y; // y is the largest so far
}
if ( z.compareTo( max ) > 0 ) {
max = z; // z is the largest now
}
return max; // returns the largest object
}
与泛型方法一样,类的类型参数部分 generic class 可以使用逗号分隔一个或多个类型参数吗. For example:
public class Cell {
private T val;
public void set(T val){这个.val = val; }
public T get() { return val; }
public static void main(String[] args) {
Cell integerCell = new Box();
Cell stringCell = new Box();
integerCell.(新添加整数(10));
stringCell.add(new String("Hello World"));
System.out.printf("整数值:%d\n\n", integerCell.get());
System.out.printf("字符串值:%s\n", stringCell.get());
}
}
反对多重继承的主要理由是复杂性, 潜在的模糊性, 它可以引入. 最典型的例子就是人们常说的“钻石问题”。, B类和C类继承于A类, 类D同时继承类B和类C. 如果a中的方法被B和C都重写了,就会产生歧义. If D does not override it, then which version of the method does it inherit; that of B, or that of C?
但是如果我们想要模拟助教的角色会发生什么呢?? Typically, a TA is both a grad student and a faculty member. 这就产生了多重继承的经典菱形问题,以及由此产生的关于TA的歧义 getRole() method:
(Incidentally, 注意上面继承图的菱形, 这就是为什么这被称为“钻石问题”.)
Which getRole() 实现应该继承TA? 教员或研究生的证言? 简单的答案可能是让TA类覆盖 getRole() 方法并返回名为“TA”的新定义角色。. 但这个答案也是不完美的,因为它会掩盖一个事实,即助教是, in fact, 既是教员也是研究生. 有多种设计方法和模式可以在没有多重继承的情况下处理这种类型的情况, 这就是为什么一些语言(Java就是其中之一)决定简单地避开多重继承的原因.
Java 8, however, 通过允许在接口上指定默认方法(在Java 8之前),引入了对多重继承的准支持形式, 只有方法签名, 不是方法定义, 允许在接口上使用). Since Java does 允许单个类实现多个接口(而单个类只能扩展单个父类), Java 8中允许在接口中定义方法,这首次在Java中引入了菱形问题的可能性.
For example, if A, B, 和C是接口, B和C可以各自为a的抽象方法提供不同的实现, 导致任何实现B和C的类D出现菱形问题. 类D必须重新实现该方法(其主体可以简单地将调用转发给其中一个超级实现), 否则歧义将作为编译错误而被拒绝.
Gourmet Java
在这里,我们将介绍一些更高级的概念和问题,Java编程大师可能会熟悉这些概念和问题.
问:如何使用外部条件变量可靠地退出线程?
有时,开发人员希望在外部条件为真时终止线程. 考虑下面的例子 bus 继续无限驱动的线程,直到 pleaseStop 变量变为真.
boolean pleaseStop = false; // The bus pull cord.
公共void pleaseStopTheBus() {
pleaseStop = true;
}
公共无效startTheBus() {
new Thread("bus") {
公共无效运行(){
//无限驱动总线.
while (!pleaseStop) {
//花点时间开车到下一站.
}
pleaseStop = false; // Reset pull cord.
}
}.start();
}
看起来简单. However, Java不保证线程边界之间隐式的变量同步, 所以这个线程不能保证可靠地退出, 这让缺乏经验的Java开发人员感到头疼.
要使上述代码正常工作,需要按以下方式同步线程:
volatile boolean pleaseStop = false; // The bus pull cord.
Object driver = new Object(); // We can synchronize on any Java object.
公共void pleaseStopTheBus() {
//在"线程1"中,同步驱动程序对象
Synchronized (driver) {
pleaseStop = true;
}
}
公共无效startTheBus() {
new Thread("bus") {
公共无效运行(){
//无限驱动总线.
while (true) {
//在这里的“线程2”,也同步驱动程序对象
Synchronized (driver) {
if (pleaseStop) {
pleaseStop = false; // Reset pull cord.
return; // Bus stopped.
}
}
//花点时间开车到下一站.
}
}
}.start();
}
Q: How can null 问题重重,怎样才能避免陷阱?
For one thing, null is often ambiguous. 它可以用来表示成功或失败. 或者它可以用来表示值的缺失. 或者在某些上下文中它可能是一个有效值.
In addition, as of JDK 8, Java已经引入了对 Optional 类(或者如果您使用的是较早版本的Java,则可以使用 Optional class in the Guava libraries. Optional 用一个值表示和包装缺席和存在. 而Optional则添加了更多内容 ceremony 到您的代码中,通过强制您展开 Optional to obtain the non-null 值,它避免了可能导致的 NullPointerException.
问:什么是“拳击”?要注意的问题有哪些?
Java的基本类型是 long, int, short, float, double, char, byte and boolean. 通常需要将原始值作为对象存储在各种数据结构中,这些数据结构只接受诸如 ArrayList, HashMap, etc. 因此,Java引入了“装箱”的概念,将原语打包成对象类的等效物, e.g., Integer for int, Float for float, and Boolean forboolean. Of course, as objects, 它们会导致对象分配的开销, 内存膨胀和方法调用, 但他们确实付出了一些代价来达到目的.
“自动装箱”是编译器自动将原语转换为装箱对象,反之亦然. 这只是为了方便,e.g.:
ArrayList ints = new ArrayList();
// Autoboxing. 编译器会自动将"35"转换成一个带框的整数.
ints.add(35);
//上面的表达式等价于:int.(新添加整数(35));