zoukankan      html  css  js  c++  java
  • Java面试系列第3篇-类的加载及Java对象的创建

     下面介绍Java面试中常见的对象加载及创建题目。

    1、Java对象初始化顺序

    先看一下如下笔试题目:

    class Parent {
    	public static int a = 2;
    	public int b = 3;
    	// 2
    	{
    		System.out.println("this is anonymity b=" + b);
    	}
    	// 1
    	static {
    		a = 4;
    		System.out.println("this is static and a=" + a);
    	}
    
    	// 3
    	public Parent() {
    		System.out.println("this is Parent constructor b="+b);
    	}
    
    }
    
    public class Son extends Parent {
    	public int b = 0;
    	// 4
    	public Son() {
    		System.out.println("this is Son constructor b="+b);
    	}
    
    
    	public static void main(String[] args) {
    		new Son();
    	}
    }

    当创建对象时,涉及到静态和非静态变量的初始化、静态和非静态匿名块的初始化以及构造函数的初始化,所以好多面试者不容易记住也不容易理解,下面我把这个类重构一下,变为如下的形式:

    class Parent {
    	public static int a;
    	public int b;
    	
    	
    	public <cinit>(){
    		a = 2;
    		
    		static {
    			a = 4;
    			System.out.println("this is static and a=" + a);
    		}
    	}
    	
    	public <init>(){
    		b = 3;
    		 
    		System.out.println("this is Parent constructor b="+b);
    		 
    		{
    			System.out.println("this is anonymity b=" + b);
    		}
    	}
    }
    
    public class Son extends Parent {
    	public <cinit>(){
    		
    	}
    	
    	public <init>(){
    		System.out.println("this is  Son constructor");
    	}
    	
    	// ...
    }
    

    Javac编译器在生成字节码之前会将类调整为如上的样子,其中合成的函数<cinit>()可以看作静态构造函数,在类的加载阶段调用,而合成的函数<init>()可以看作是实例构造函数,在对象创建的时候调用。调用子类的<cinit>()方法之前必会先调用父类的<cinit>()方法,这是由类的加载顺序决定的。等类加载完成后就可以创建对象了,同样初始化子类必先初始化父类,也就是先调用父类的<init>()方法,后调用子类的<init>()方法。那么现在的调用顺序就是:

    Parent.<cinit>() -> Son.<cinit>() -> Parent.<init>() -> Son.<init>()  

    在重构<cinit>()方法时,将变量的初始化写在前面,匿名块写在后面;在重构<init>()方法时,将变量的初始化写在前面,将构造函数原有的内容写在中间,最后写匿名块的内容。如果有多个变量或匿名块,就按源代码的顺序写即可。

    那么打印的结果肯定一目了然了,打印的结果如下:

    this is static and a=4
    this is anonymity b=3
    this is Parent constructor b=3
    this is Son constructor b=0
    

    如果还想了解更多,比如Javac编译器为什么要进行这样的高速,可以参考《深入解析Java编译器:源码剖析与实例详解》一书。 

    2、对象创建的几种方式

     要熟记对象创建的几种方式,如下:

    (1)使用new 关键字 使用 new 关键字创建对象,实际上是做了两个工作,一是在内存中开辟空间,二是初始化对象;

    (2)使用反射创建对象 反射创建对象分为两种方式,一是使用Class类的newInstance() 方法,二是使用Constructor类的newInstatance() 方法。Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数; Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数;

    (3)使用clone()方法;

    (4)使用序列化。

    最广泛使用的应该就是使用new关键字和使用反射创建了。对于反射创建来说,如下:

    Class.forName(className).newInstance();
    

    调用forName()只会加载类,要得到对象需要调用newInstance()方法。这种创建方式在框架中用的多,就是因为forName()方法的参数是字符串类型,通过这个字符串来指定要加载的类,我们就可以通过配置的形式来指定加载的类型了,用起来很方便。另外需要注意,由于Class.forName()需要调用本地方法加载类,所以过程比较耗时,为了提高反射的性能,可以适当缓存这个获取到的对象。

    3、对象的创建过程

     

  • 相关阅读:
    2013.4.15 Particle Swarm Optimization with Skyline Operator for Fast Cloudbased Web Service Composition
    Adaptive service composition in flexible processes
    2013.4.13 DomainSpecific Service Selection for Composite Services
    2013.4.14 Modeling and Algorithms for QoSAware Service Composition in VirtualizationBased Cloud Computing
    2013.5.29 Towards Networkaware Service Composition in the Cloud
    Efficient algorithms for Web services selection with endtoend QoS constraints
    SQL Server中常用的SQL语句
    接口限流自定义注解
    linux服务器生产环境搭建
    MVEL自定义函数重复掉用报错:duplicate function
  • 原文地址:https://www.cnblogs.com/extjs4/p/12776762.html
Copyright © 2011-2022 走看看