java静态方法和实例方法以及父子类初始化加载顺序

一、看似简单的问题 静态方法和实例化方法的区别

Java程序启动class文件被读取时类被加载,如果有static方法,此时会分配内存,非static方法实例化类时才在内存中分配控件存储,引用存储在堆栈中,实体存储在堆中

    最大的区别在于内存。静态方法在程序开始时生成内存,实例方法在程序运行中生成内存,所以静态方法可以直接调用,实例方法要先成生实例,通过实例调用方法,静态速度很快,但是多了会占内存。任何语言都是对内存和磁盘的操作,至于是否面向对象,只是软件层的问题,底层都是一样的,只是实现方法不同。静态内存是连续的,因为是在程序开始时就生成了,而实例申请的是离散的空间,所以当然没有静态方法快,而且静态内存是有限制的,太多了程序会启动不了。

    方法是我们每天都在写得,很多程序员大多都使用实例化方法,而很少使用静态方法,问原因也说不出来所以然,或者简单的回答两者定义的区别,静态方法不需要new就可以使用实例化方法需要new了以后才可以使用。。。。我们真的理解了吗?

从实际项目开发说起,这里有开发项目的三种方式:

开发项目中把BLLDAL分开,在BLL调用DAL的代码。

一、在DAL中使用静态方法,不创建实例直接调用(大概有很多人都使用这种方式开发

class DAL
{
public static string GetUserName(...);
}

BLL 中调用:
DAL.GetUserName();

二、在DAL中使用实例方法,采用静态成员模式(Singleton)通过实例来调用:

class DAL
{
public static readonly DAL dal = new DAL();
public string GetUserName(...);
}

BLL 中调用:
DAL.dal.GetUserName();

三、在DAL中使用实例方法,每次调用之前先创建DAL对象的实例:

class DAL
{
public string GetUserName(...);
}

BLL 中调用:
DAL dal = new DAL();
dal.GetUserName();

---------------------------------------------------------------

开发方式一:我以为在一些情况下(比如调用多个数据库、GetUserName...)内部处理操作部分)会出现线程安全的嫌疑。这种开发方式不用New出对象,所以很普遍。

开发方式二:应该多是应用在cs模式下,DAL在整个项目只会有一个对象存在,如果出现在B/S我想不能兼容多种问题情况。而且也有线程安全的问题。

开发方式三:应该是普遍使用的,能够兼容各种问题,也不会有线程不安全的嫌疑出现。

静态方法和实例方法的区别:

    1.静态方法比较少用,因为他在一启动就实例化了,比较占资源,静态方法在程序开始时生成内存,实例方法在程序运行中生成内存,静态方法配合单例模式还是比较好用的,比较多的用在数据连接上,避免使用的原则就是减少资源消耗,还有会在工具类里面用

    2.静态就是类的,实例就是对象的。静态方法不需要依赖类当中的属性,能在这个方法中封闭的完成一个功能。实例方法更多的会使用到类当中的属性;简单点说,静态方法用来执行无状态的一个完整操作,实例方法则相反,它通常是一个完整逻辑的一部分,并且需要维护一定的状态值。 

    3.静态方法和全局函数差不多的,实例方法是一个类里面的方法,如果从线程安全、性能、兼容性上来看也是选用实例化方法为宜。

我们为什么要把方法区分为:静态方法和实例化方法?

    如果我们继续深入研究的话,就要脱离技术谈理论了。早期的结构化编程,几乎所有的方法都是静态方法,引入实例化方法概念是面向对象概念出现以后的事情了,区分静态方法和实例化方法不能单单从性能上去理解,创建c++,java,c#这样面向对象语言的大师引入实例化方法一定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化方式的区分是为了解决模式的问题。

拿别人一个例子说事:

比如说这个类,每个人都有姓名、年龄、性别、身高等,这些属性就应该是非静态的,因为每个人都的这些属性都不相同;但人在生物学上属于哪个门哪个纲哪个目等,这个属性是属于整个人类,所以就应该是静态的——它不依赖与某个特定的人,不会有某个人是脊椎动物门哺乳动物纲灵长目而某个人却是偶蹄目的。

二、Java静态初始化,实例初始化以及构造方法加载顺序

首先有三个概念需要了解:
一.静态初始化:是指执行静态初始化块里面的内容。
二.实例初始化:是指执行实例初始化块里面的内容。
三.构造方法:一个名称跟类的名称一样的方法,特殊在于不带返回值。
我们先来看一段程序结果:

执行结果:
this is static method~
this is static block
如果把


的注释去掉的话,运行结果为:
this is static method~
this is static block
初始化块:0
this is Book's constructor~

执行顺序:(优先级从高到低。)静态代码块>main方法>实例初始化块>构造代码块>构造方法。”

总结:
仅从代码执行的角度来探讨Java加载类、创建对象的过程,并没有深入到JVM的机制中去。
1.一个对象第一次被创建时,先要加载该对象所属的类,即对应的.class文件,当然如果类已经加载,再次创建该类的对象时,就不再需要重新加载类了。而一个类加载的时候,有三个部分需要加载,一个是静态变量,再然后是静态方法,然后是静态初始化块。(见到第一次执行结果就知道了,由于没有创建实例所以初始化块不执行)
2.然后开始创建该类的实例了,当然如果静态方法跟静态初始化对象中有对象的创建时,就继续加载该对象的类,当然已经加载了该对象的类的话就不需要再次加载了。那么对象实例的创建过程是什么呢?首先是成员变量的引入,然后是实例初始化块,之后才是构造方法,构造方法执行完成之后才算把这个对象给创建出来了。
在这个过程中,真正可以编写执行代码的地方有三个,静态初始化、实例初始化以及构造方法。从以上的分析中我们可以看到,这三个代码块的执行顺序是先类的静态初始化,再实例初始化,最后执行构造方法。也就是说,静态初始化是属于类加载的过程,所以它只执行一次,而实例初始化是每个对象创建时都会执行一次,而构造方法跟实例初始化其实也差不多,不过它在实例初始化之后执行,而且构造方法可以重载多个,执行哪个构造方法是根据你的选择来的。
可以把main () 函数加一条语句看看:


此时执行结果为:
this is static method~
this is static block
初始化块:0
this is Book's constructor~
初始化块:1
this is Book's constructor~
这说明实例初始化是每个对象创建时都会执行的。

三、Java中父类与子类的加载顺序

  1. class Parent {  
  2.     // 静态变量  
  3.     public static String p_StaticField = "父类--静态变量";  
  4.     // 变量(其实这用对象更好能体同这一点,如专门写一个类的实例)  
  5.     
  6.     //如果这个变量放在初始化块的后面,是会报错的,因为你根本没有被初始化  
  7.     public String p_Field = "父类--变量";  
  8.     // 静态初始化块  
  9.     static {  
  10.         System.out.println(p_StaticField);  
  11.         System.out.println("父类--静态初始化块");  
  12.     }  
  13.     // 初始化块  
  14.     {  
  15.         System.out.println(p_Field);  
  16.         System.out.println("父类--初始化块");  
  17.     }  
  18.     // 构造器  
  19.     public Parent() {  
  20.         System.out.println("父类--构造器");  
  21.     }  
  22. }  
  23. public class SubClass extends Parent {  
  24.     // 静态变量  
  25.     public static String s_StaticField = "子类--静态变量";  
  26.     // 变量  
  27.     public String s_Field = "子类--变量";  
  28.     // 静态初始化块  
  29.     static {  
  30.         System.out.println(s_StaticField);  
  31.         System.out.println("子类--静态初始化块");  
  32.     }  
  33.     // 初始化块  
  34.     {  
  35.         System.out.println(s_Field);  
  36.         System.out.println("子类--初始化块");  
  37.     }  
  38.     // 构造器  
  39.     public SubClass() {  
  40.         //super();  
  41.         System.out.println("子类--构造器");  
  42.     }  
  43.     // 程序入口  
  44.     public static void main(String[] args) {  
  45.         System.out.println("*************in main***************");  
  46.         new SubClass();  
  47.         System.out.println("*************second subClass***************");  
  48.         new SubClass();  
  49.     }  
  50. }  
输出结果
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
*************in main***************
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
*************second subClass***************
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
  • 22
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值