一道百度的面试题,有大神会嘛?

关注者
939
被浏览
110183
这题的本质就是要在看似只能放一个表达式的地方插入任意副作用。Java木有像C那样方便地vfork()的办法——ProcessBuilder可以fork但没办法像C那样分岔用。

已给 @放开那女孩 的回答点赞。这题一看就是个代码注入类问题。

这种思路在不少场景还真的“有用”。例如说我见过有人偷懒,用Java 6开始JDK自带的javax.tools.JavaCompiler API来实现“表达式语言”的功能:写一个类似下面这样的代码模版,然后把用户输入的代码拼接进去,再交给JavaCompiler来动态编译出Class文件然后调用里面的方法:
public class MyExpressionEvaluator {
  public double evaluate(Map<String, Double> input) {
    return <USER INPUT TO BE FILLED IN HERE>;
  }
}
把上面<...>的部分替换成用户输入的表达式字符串,这就得到“表达式语言”了。
——啦啦啦!
在可执行代码里允许用户输入任意字符串作为代码,不注入你还注入谁?>_<

=========================================

也已给 @仓鼠君 的回答点赞。这个是基于对标准库的高度熟悉才做得出来的解法。PrintStream.printf()会返回this,而this肯定不为null,所以System.out.printf("a") == null 肯定为false,正好满足这个需求。

=========================================

这里就帮 @vczh 把Java版写出来:
import java.util.function.BooleanSupplier;

public class xx {
  public static void main(String[] args) {
    if (((BooleanSupplier)(() -> { System.out.print("a"); return false; })).getAsBoolean()) {
      System.out.print("a");
    } else {
      System.out.print("b");
    }
  }
}
很简单的事情。Java 8的lambda是不是半成品很大程度上取决于是否知道如何使用。

当然,即便用这个思路,如果能多写几句代码的话我是不会用lambda的…
public class xx {
  public static void main(String[] args) {
    if (foo()) {
      System.out.print("a");
    } else {
      System.out.print("b");
    }
  }

  public static boolean foo() {
    System.out.print("a");
    return false;
  }
}

有人说用匿名内部类的形式。这个当然也可以的。不用任何Java 8的新功能也一样可以写出来,例如:
public class xx {
  public static void main(String[] args) {
    if (new Object() {
          public boolean foo() {
            System.out.print("a");
            return false;
          }
        }.foo()) {
      System.out.print("a");
    } else {
      System.out.print("b");
    }
  }
}
这里的考察点是:一个匿名内部类的实例,在刚刚new完的时候编译器(javac级别)还知道它的实际类型,所以即便是它所继承的基类 / 所实现的接口没有的方法也照样可以调用。java.lang.Object上有foo()方法么?没有。但是我们的匿名内部类上有,刚new出来的地方就可以调用。

一旦能任意注入副作用,玩法简直多得是了。例如说:
public class xx {
  public static void main(String[] args) {
    if (new Object() {
          public boolean foo() {
            System.out.println("ab");
            throw new RuntimeException();
          }
        }.foo()) {
      System.out.print("a");
    } else {
      System.out.print("b");
    }
  }
}
谁说一定要执行then和else分支的任意一个了。不能都不执行么(ry