问候,哈勃!我提请您注意周五有关Java,Scala,疯狂的程序员和诺言的简短文章。
简单的观察有时会引出不太简单的问题。
例如,这里是一个简单的,甚至是琐碎的事实,它表明在Java中您可以扩展范围内的任何非最终类和任何接口。另一个也很简单的说法是,可以从Java代码中使用为JVM编译的Scala代码。
然而,这两个事实的结合使我感到奇怪:从Java的角度来看,任何类的行为如何?Java在Scala中是密封的,即 不能使用相对于其自身文件的外部代码进行扩展?
从艺术家的角度反编译Scala类。资料来源:https : //specmahina.ru/wp-content/uploads/2018/08/razobrannaya-benzopila.jpg
作为实验兔子,我参加了标准班Option
。通过将其输入到IntelliJ Idea内置的反编译器中,我们得到如下信息:
public abstract class Option
implements IterableOnce, Product, Serializable {
public abstract Object get();
}
但是,反编译后的代码将不是有效的Java代码- 例如,此方法类似于此处描述的问题:
public List toList() {
return (List)(
this.isEmpty()
? scala.collection.immutable.Nil..MODULE$
: new colon(this.get(), scala.collection.immutable.Nil..MODULE$)
);
}
MODULE$ , package object. , , Java , ?
, , ...
Java ( Maven), Scala provided- — , , , :
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.13.1</version>
<scope>provided</scope>
</dependency>
, scala.Option
. Idea, , Scala , sealed-, , , :
package hack;
public class Hacking<T> extends scala.Option<T> {
@Override
public T get() {
return null;
}
public int productArity() {
return 0;
}
public Object productElement(int n) {
return null;
}
public boolean canEqual(Object that) {
return false;
}
}
- , Option Product.
, — . mvn package
— , , jar-, , Java, , , .
, Scala.
… scala-
Scala (, SBT) — lib , , , ; build.sbt , Idea. ( ) :
import hack.Hacking
object Main {
def main(args: Array[String]): Unit = {
implicit val opt: Option[String] = new Hacking()
}
private def tryDo[T](action: => T): Unit = {
try {
println(action)
} catch {
case e: Throwable => println(e.toString)
}
}
}
implicit var
.
tryDo
— , : , , . call-by-name tryDo
, , .
, match
— , sealed class- ( , sealed-, ?)
object Main {
def main(args: Array[String]): Unit = {
tryMatch
}
private def tryDo[T](action: => T): Unit = {
}
private def tryMatch(implicit opt: Option[String]): Unit = tryDo {
opt match {
case Some(inner) => inner
case None => "None"
}
}
}
:
scala.MatchError: hack.Hacking
, : Option — sealed class, ( case Some case None), :
[warn] $PATH/Main.scala:22:5: match may not be exhaustive.
[warn] It would fail on the following input: None
[warn] opt match {
[warn] ^
, .
, - Option:
object Main {
def main(args: Array[String]): Unit = {
tryMap
}
private def tryDo[T](action: => T): Unit = {
}
private def tryMap(implicit opt: Option[String]): Unit =
tryDo(opt.map(_.length))
}
:
java.lang.NullPointerException
, map:
sealed abstract class Option[+A] /* extends ... */ {
final def isEmpty: Boolean = this eq None
def get: A
@inline final def map[B](f: A => B): Option[B] =
if (isEmpty) None else Some(f(this.get))
}
, :
- — None. , isEmpty false.
- , this.get, null.
- null , — length.
- length null NPE.
, NPE , Java ? (, , , ...)
:
object Main {
def main(args: Array[String]): Unit = {
tryContainsNull
}
private def tryDo[T](action: => T): Unit = {
}
private def tryContainsNull(implicit opt: Option[String]): Unit =
tryDo(opt.contains(null))
}
(, , null) , contains -Nullable . , , , Option false — null. ?
:
true
, , , contains map: !isEmpty && this.get == elem
.
, . , null , Option ( , , ) else match.
实际上,本文所需要做的只是一个小实验,以揭示一个JVM上不同语言交互的细微差别。稍加思索的细微差别是显而易见的,但是-就我的口味而言,仍然很有趣。