不一样的Hello Wold 测试你的Java基础 顺便说下此代码执行原理

0 篇文章 0 订阅

个人说明:如有巧合,纯属意外,若有错误之处,还请大佬们指出。

直接贴代码

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		if(args==null||new Test(){{Test.main(null);}}==null)
		{
			System.out.print("hello ");
		}else {
			System.out.println("world ");
		}
	}

}

上面代码,如果去掉if()里的代码完全可以当做考察人的java基础题,要求让他仅仅在if()里填写代码 而且if和else都要走。。。。当然 以前知道这题目的人就不要鄙视博主了


好了下面来说下执行过程

首先程序运行找到main函数入口  并且在运行时如何用户赋初值的情况下 args是有值得 如何不赋值 args为[] 但不为null 因此第一个条件为false(此处如果不懂就不要往下看了,基础不行)

接下来是

new Test(){{Test.main(null);}}==null

首先new Test()然后后面又接了个{} ,这个表示重写Test类,而{Test.main(null);}表示重写父类构造代码块,所以在new Test()的时候会自动调用父类然后再调用子类,这调用机制和重写父类的方法有点不同,父类的方法需要子类手动调用才能执行。  所以又调用一次main方法入栈,而且赋值类args值为null 所以进入到main方法时 args==null成立 ,走if分支,然后继续,出栈后继续执行 ,由于new出来的对象必定不为Null,所以此时走else分支,程序结束 打印结果 hello world 

这个hello world 巧妙的考察了匿名类的继承,又考察了继承后 构造代码块的调用机制。

由此题可以引出很多思考(如果你是刚毕业的去应聘,面试官可能会问你如下问题)

1.什么是匿名类 他和自定义类有什么区别?

2.为什么匿名类中不能重写静态代码块和重写静态方法,从原理上分析,不是语法上

3.声明一个自定义类,该自定义类会不会初始化成员,什么情况下会初始化自定义里的属性和方法

4.什么是回调?回调分为哪几种,各有什么好处,各举个生活中的例子。

5.回调的实现有哪几种方式(这里指的是语法),那种方式最规范


上面的问题我也没正确答案,大家自行脑补或度娘。

下面是执行原理的详细说明,扯到jvm,不想看的可跳过

类的编译和执行主要包括三个重要的步骤

1.类编译机制

2.类加载机制

3.类执行机制


先上个图简要的了解下源码执行过程


具体的java源码编译成class文件是由下面完成的,如图


此原理可以不做了解,知道就行。

装载class文件:

类装载到jvm中主要由三个类加载器加载的,首先介绍下类加载器,bootstarp classloader , extension classloader , app classloader   第一个是由c++实现的,负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class   , 第二个是负责加载$JAVA_HOME中jre/ext/*.jar里的所有class,第三个是负责加载classpath下的class文件。 类加载器使用的是委托机制,加载一个类前首先会检查自身是否已加载该类,如果没加载 它也不会立即加载,而会选择向父类委托 看父类是否加载过这个类,如果还是没有 还会和之前一样 一直往上找,最终找到最顶层的父类。然后自上而下去尝试加载该类(看该类是否在该加载器所加载的路径下),最终找到该类加载到内存,但也会出现找不到的情况,例如导入第三方jar包时 找不到类会报类不能找到异常(由于第三方jar是class文件,编译期不会有语法检查才会出现这种情况,如果是用户自定义的类就不会出现这种异常)

class执行机制:

类开始执行的时候,jvm首先会创建程序计数器和栈(这两个是线程安全的 每个线程中都会自己创建) ,jvm还会创建所有线程共有的方法区,方法区主要存放类的信息,比如 类的修饰符public ,完整的类名(加载器+对应包名+对应类名),类中的字段,类中的方法以及它们的修饰符,常量池和能够直接引用的静态变量。大家都知道java是以main函数为程序入口的,jvm找到main方法后 就会创建程序计数器和jvm栈,计数器指向当前线程的jvm字节码指令的地址,然后在栈中创建栈贞 栈贞入栈 栈贞中包含了局部变量表,动态链接,操作数栈,方法出口等。如果main函数中还有调用其他方法,那就继续创建栈贞,再入栈,等待最后进去的栈贞出栈才能执行之前的栈贞。数据结构中有名的后进先出。然而在栈贞中执行语句的时候 如果碰到new 的字样  会在堆中将对象实例化,然后栈贞中引用该实例所存在的地址 进行一系列操作。但要说明堆是非线程安全的。最后要说的是本地方法栈,它执行的是native修饰的方法,调用的是c++等其他语言。当执行native方法的时候程序计数器所指向的地址为Null。

问题:

问题一:对象引用的内存结构是什么?

在Java中,对象的引用实际上是指向一个句柄的指针,该句柄包含一对指针,一个指针指向一张表,实际上该表也有两个指针(一个指针指向了包含了对象的方法表,另一个指向了对象类型,表明该对象所属的类型),另一个指针指向一块从Java堆中分配的内存空间,该空间用于存储对象数据。


以上就是我所理解的jvm,大神看到有错还请指出,忽喷,谢谢!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值