今天看到了一个比较特别的面试题,考察的是如何改变int的System.out.print的结果。题目如下:

下面的一句话“这是初级java实习生面试题”非常挑衅的激起了大家做题的欲望。

解题思路

解题的思路无外乎是3种方法:
1.作弊大法,因为一些面试题总是会出其不意,面对扯淡的问题就要用扯淡的方法。
2.反射,感觉反射是一种比较“高端”用法,因为很多中间件与框架都是通过反射实现的。
3.数据流。反射的思路是修改对应内存上的内容,当无法修改响应内存的时候就要找其他思路了。这里对应的问题就是,System.out.println是如何打印的。

解题方案

作弊大法

  • System.exit
    这种方法通过退出jvm线程来终止后面的程序运行,看完之后让人比较崩溃,因为业务中遇到 System.exit的场景比较少。
    private static void method(int a, int b) {
System.out.println("a=100");
System.out.println("b=200");
System.exit(0);
}
  • 异常
    上面的方法是线程优雅的自己退出JVM,通过异常就是强制使JVM中介当前线程了。
    private static void method(int a, int b) {
System.out.println("a=100");
System.out.println("b=200");
throw new RuntimeException();
}

反射

反射的方法我一直没有成功,这里提供几个思路

  • 修改缓存池
    因为Integer内部维护了一个IntegerCache内部类,其内部维护了一个Integer[]数组来维护从-128到127的Integer对象。
private static void method(int a, int b) throws Exception {
Class<?> clzz = Integer.class.getDeclaredClasses()[0];
Field field = clzz.getDeclaredField("cache");
field.setAccessible(true);
Integer[] cache = (Integer[]) field.get(clzz);
cache[138]=100;
cache[148]=200;
}

这样就修改了缓存区的内容,但是依然没有完成题目的要求,打印内容没有改变,因为这样改变了所有的Integer缓存区对象,但是当前打印的是int。这种情况下,其他的场景倒是可以改变了。

Integer c =10;
System.out.println(c);
System.out.println(Integer.valueOf(10));
  • 修改对象本身
private static void method(int a, int b) throws Exception {
Field value = Integer.class.getDeclaredField("value");
value.setAccessible(true);
value.set(10,100);
}

效果等于同修改缓存池的方法

修改输出流

了解一点System.out的同学应该很清楚这是通过PringStream流实现的。当然我不是很了解,我是通过反编译看字节码发现的。
测试代码:

public class A {
public static void main(String[] args) {
int a = 9;
System.out.println(a);
}
}

查看字节码:

发现实际在输出屏幕的时候调用的是PrintStream对象的println方法实现的,我们可以通过重写这个方法打印任何内容。

  • 直接替换法
    private static void method(int a, int b) throws Exception {
PrintStream printStream = new PrintStream(System.out) {
@Override
public void print(String s) {
if (s.equals("a=10")) {
super.print("a=100");
} else if (s.equals("b=20")) {
super.print("b=200");
} else
super.print(s);
}
};
System.setOut(printStream);
}

这种方法比较low,属于手动替换的。下面的方法性质相同,不过看上去高端一点。

  • 间接替换法
    private static void method(int a, int b) throws Exception {
PrintStream printStream = new PrintStream(System.out) {
@Override
public void print(String s) {
s = s.replace(a + "", a * 10 + "").replace(b + "", b * 10 + "");
super.print(s);
}
};
System.setOut(printStream);
}

结论

不知道这个面试题的正确答案是什么,这里提供了两种方法解决。很可惜反射没有搞定这个题目,如果哪位同学有更好的方法请留言。

如何修改int的打印内容——史上最难的JAVA面试题的更多相关文章

  1. 史上最全阿里 Java 面试题总结

    以下为大家整理了阿里巴巴史上最全的 Java 面试题,涉及大量 Java 面试知识点和相关试题. JAVA基础 JAVA中的几种基本数据类型是什么,各自占用多少字节. String类能被继承吗,为什么 ...

  2. 史上最全最新Java面试题合集一(附答案)

    下面小编整理了本套java面试题全集,分享给大家,希望对大家的java学习和就业面试有所帮助. 1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: 抽象:抽象是将一类对象的共同特征 ...

  3. 史上最全最新java面试题合集二(附答案)

    下面小编整理了本套java面试题全集,分享给大家,希望对大家的java学习和就业面试有所帮助. 51.类ExampleA继承Exception,类ExampleB继承ExampleA. 有如下代码片断 ...

  4. 「万字图文」史上最姨母级Java继承详解

    摘要:继承是面向对象软件技术中的一个概念.它使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用. 本文分享自华为云社区<「万字图文」史上最姨母级Java继承详解丨[奔跑吧!JAVA] ...

  5. 史上最全的 Java 新手问题汇总

    史上最全的 Java 新手问题汇总   Java是目前最流行的编程语言之一——它可以用来编写Windows程序或者是Web应用,移动应用,网络程序,消费电子产品,机顶盒设备,它无处不在. 有超过30亿 ...

  6. 史上最全的spark面试题——持续更新中

    史上最全的spark面试题——持续更新中 2018年09月09日 16:34:10 为了九亿少女的期待 阅读数 13696更多 分类专栏: Spark 面试题   版权声明:本文为博主原创文章,遵循C ...

  7. 史上最全的java随机数生成算法分享(转)

    这篇文章主要介绍了史上最全的java随机数生成算法,我分享一个最全的随机数的生成算法,最代码的找回密码的随机数就是用的这个方法 String password = RandomUtil.generat ...

  8. 一文深入了解史上最强的Java堆内缓存框架Caffeine

    它提供了一个近乎最佳的命中率.从性能上秒杀其他一堆进程内缓存框架,Spring5更是为了它放弃了使用多年的GuavaCache 缓存,在我们的日常开发中用的非常多,是我们应对各种性能问题支持高并发的一 ...

  9. 史上最全的Java高级技术点,全是Java高级进阶技术,几乎包含了Java后端的所有知识点

    史上最全的Java高级技术点,全是Java高级进阶技术,几乎包含了Java后端的所有知识点 1

随机推荐

  1. 【PHP】this,self,parent的区别(转)

    一. 定义&区别 self: 指向当前类的指针,self是不指向任何已经实例化的对象,一般self使用来指向类中的静态变量. this: 指向当前对象的指针,使用parent来调用父类的构造函 ...

  2. Docker存储

    前言 上一篇文章中简单总结了一下docke的基础使用方法,这次我来总结一下有关docker存储方面的相关知识.本文同样建立在CloudMan的系列教程之上,有兴趣的可以直接移步. 有些人可能觉得这个很 ...

  3. Pandas: 如何将一列中的文本拆分为多行? | Python

    Pandas: 如何将一列中的文本拆分为多行? 在数据处理过程中,经常会遇到以下类型的数据: 在同一列中,本该分别填入多行中的数据,被填在一行里了,然而在分析的时候,需要拆分成为多行. 在上图中,列名 ...

  4. python--代码统计小程序

    有人说,大学生在校期间要码够10W行代码,也有人说,看的不是写代码的行数,而是修改代码的行数... 不管谁说,说的人都挺牛的 咳,首先给自己定个小目标吧,5W行代码!成天写代码,啥时候到5W呢?为了更 ...

  5. vue指令v-else示例解析

    为 v-if 或者 v-else-if 添加 "else 块". <div id="app"> <p v-if="isRender& ...

  6. python进阶(5):组合,继承

    前两天我们认识了面向对象也对面向对象有了初步的认识今天我们先会说一点组合的进阶,今天重点是继承. 一.组合 组合只有一个例子因为组合只作为上一章的补充内容 #老师 课程 生日 class Course ...

  7. WAS应用--虚拟主机

    --WAS应用--虚拟主机 ---------------------2013/11/08 在部署was应用的时候,步骤3<为web模块映射虚拟主机>. 例如有应用orsscheduleE ...

  8. Oracle进阶研究问题收集

    1. buffer busy waits http://www.itpub.net/thread-1801066-1-4.html 2. 深入理解oracle log buffer http://ww ...

  9. java 数组的冒泡排序

    冒泡排序 (1)冒泡排序算法的运作如下:(从后往前) 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最 ...

  10. python------函数嵌套及作用域链

    1.三元运算if条件成立的结果 if 条件 else 条件不成立的结果例如: a=20 b=10 c=a if a>b else b print(c) 2.命名空间 全局命名空间:创建的存储&q ...