精华内容
下载资源
问答
  • 构造函数的执行顺序析构函数析构函数特点析构函数的调用顺序finalize( )函数finalize()特点:Java程序在执行构造函数初始化到底在干嘛构造器实例构造器与构造函数的区别:类构造器()与实例构造器() 以前在学JavaSE...


    以前在学JavaSE的时候就碰见了,构造函数,一直不解构造函数是干什么的,只知道学、用、没深刻理解;今天回过头把它吃透。 💪 💪 💪 💪 💪

    构造函数

    构造函数:Java规定了我们在创建类时,必须有一个构造函数,这个构造函数可以重写,如果我们在创建类的时候没有写构造函数,Java会默认为我们提供一个无参的构造函数。

    public class Dog{
    	String name;
    	public Dog(){   //无参构造方法
    	}
    	public Dog(String name){ //有参构造方法
    		this.name = name;
    	}
    }
    我们在编写代码时,如果没有写构造函数,那么编译器会自动生成一个无参构造方法。
    

    那为什么一定要有构造函数呢,是因为我们在创建对象的时候,要初始化成员变量,即为所有属性和方法都设置成默认值(数字为 0,字符为 null,布尔为 false,而所有引用被设置成 null)。构造函数的任务是初始化一个对象的内部状态,所以用new操作符创建一个实例后,立刻就会得到一个清楚、可用的对象。
    还有小白会问的,Java 为什么必须要初始化赋一个null值?
    在c语言里面,如果我们不给变量赋值的话,它就会产生一个随机指针,而Java不会。jvm会自动为成员变量分配内存空间,设置默认值(String类型为null,boolea类型为false),然后将这个成员变量引用指向这个内存。

    构造函数的特点:

    (1)构造方法名和类名相同。
    (2)构造方法没有返回类型,也不能在方法名前定义void。
    (3)构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。
    (4)构造方法可以重载。
    (5)构造方法只能由编译器调用,程序员不可以。

    构造函数的执行顺序

    tip:方法优先存在于任何变量或者对象,存在于类中,而不是对象中。即构造对象前,方法就存在。

    在java中,实例化一个子类的对象,首先会调用父类的无参构造函数。如果父类没有显式定义构造函数,那么会调用缺省构造函数,这个缺省构造函数是由编译器自动产生的。如果父类显式定义了构造函数,那么编译器就不再为父类生成缺省默认构造函数。
    假设父类中定义了一个带参数的构造函数,而没有定义无参构造函数,这时候实例化一个子类的对象,就会出现编译错误,因为子类首先要调用父类的无参构造函数,但是父类没有显式定义,编译器又不为父类产生缺省构造函数。这时候可以通过在父类中显示定义无参构造函数来解决这个错误。
    this()和super()都可以用来调用构造函数,而this()用于在同一个类内调用其他的构造函数,比如首先在Student类中定义了一个构造函数Student(name,age),又另外定义了一个构造函数Student(name,age,school),那么在第二个构造函数中可以通过this(name,age)的形式来调用第一个构造函数,注意这里this(name,age)必须写在第二个构造函数的首行。而super用于从子类的构造方法中调用父类的构造方法。比如父类Person有构造函数Person(String name, int age),而子类有构造函数Student(String name, int age, String school, String grade),那么就可以在子类构造函数中通过super(name,age)来调用父类构造函数。
    建议:最好为每个类都显示定义无参构造函数。

    1. 调用父类构造函数;
    2. 按代码顺序分别调用实例成员变量的初始化表达式(如果代码块在前,优先执行代码块;如果变量在前,优先变量赋值);
    3. 调用本身构造函数。
    public class Dollar extends Money{
    	Rmb r=new Rmb();
    	public Dollar(){
    		System.out.println("Dollar is construct!");
    	}
    	
    	public static void main(String[] args){
    		new Dollar();
    	}
    }
    
    class Money{
    	public Money(){
    		System.out.println("Money is construct");
    	}
    }
    
    class Rmb{
    	public Rmb(){
    		System.out.println("RMB is construct");
    	}
    }
    
    输出结果:
    Money is construct
    RMB is construct
    Dollar is construct!
    
    从返回结果来看,我们在执行main()函数时,先调用父类的构造函数Money();
    接着执行实例成员变量Rmb,因为Rmb实例未存在,我们要执行Rmb r=new Rmb();这时就要执行Rmb的构造方法Rmb();
    之后,没有其他成员变量了,我们就执行它自己的最构造方法Dollar();
    到此,Dollar对象就真正存在jvm运行态内存中了。
    

    虽说Java与C++的构造器是一样的,但是Java与C++有一个不同之处:Java不但有构造函数,还有一个”初始化块“(Initialization Block)。请大家思考一下,Java的初始化块、静态初始化块、构造函数的执行顺序是什么样的?
    如果不知道的话,看看这里👉👉:Java 初始化的深认知(第二篇)

    析构函数

    在了解了构造函数之后,与它相对的析构函数我们也要了解一下

    析构方法
    首先,我要声明,Java是没有析构函数的,C++才有。
    与 Java 不同,C++ 支持局部对象(基于栈)和全局对象(基于堆)。因为这一双重支持,C++ 也提供了自动构造和析构,这导致了对构造函数和析构函数的调用,(对于堆对象)就是内存的分配和释放。
    在 Java 中,所有对象都驻留在堆内存,因此局部对象就不存在。结果,Java 的设计者觉得不需要析构函数(像 C++ 中所实现的)。
    取而代之,Java 定义了一个特殊的方法叫做finalize() ,它提供了 C++ 析构函数的一些功能。但是,finalize() 并不完全与 C++ 的析构函数一样,并可以假设它会导致一系列的问题。finalize() 方法作用的一个关键元素是 Java 的垃圾回收器。

    析构函数特点

    • 析构函数没有参数,也没有返回值。不能重载,也就是说,一个类中只可能定义一个析构函数
    • 如果一个类中没有定义析构函数,系统也会自动生成一个默认的析构函数,为空函数,什么都不做
    • 调用条件:
      1.在函数体内定义的对象,当函数执行结束时,该对象所在类的析构函数会被自动调用;
      2.用new运算符动态构建的对象,在使用delete运算符释放它时。

    析构函数的调用顺序

    对象是由“底层向上”开始构造的,当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止。因为,构造函数一开始构造时,总是要调用它的基类的构造函数,然后才开始执行其构造函数体,调用直接基类构造函数时,如果无专门说明,就调用直接基类的默认构造函数。在对象析构时,其顺序正好相反。

    每创建一个类的实例都去初始化它的所有变量是乏味的。如果第一个对象在被创建时就完成了所有的初始工作,第二个对象在创建时只需,将是简单的和简洁的。

    new 关键字被jvm识别后,就会在堆上创建对应类的对象,生成一个返回值(对象的内存地址),并且把类变量(静态成员变量)进行第一次初始化,有值的赋值,没有值的就赋0或者null,然后才是调用构造器方法,再进行对象变量的第二次初始化,之后,new动作产生的地址值返回给栈内存中 类的变量,存储起来。 ps new动作产生对象之后,会加载对象变量,以及非静态方法的地址值,这个地址值指向方法区中对应类的实际的非静态方法,也就是说 静态方法 和 非静态方法都存在于方法区的类当中。

    finalize( )函数

    Java 允许使用 finalize() 方法在gc回收前做必要的清理工作。

    某些情况下,当 gc 回收一个对象时,需要完成一些操作。例如,如果一个对象正在处理的是非Java 资源,如文件句柄或window 字符字体,这时你要确认在这个对象被回收之前,这些资源被释放。为处理这样的状况,Java 提供了收尾机制(finalization )。使用该机制可以定义一些特殊的操作,这些操作在一个对象被垃圾回收程序释放前执行。要给一个类增加收尾(finalizer ),你要定义finalize ( ) 方法。Java 回收该类的一个对象时,会先调用这个方法。
    finalize()是在Object 类中定义的,因此所有的类都继承了它,子类要覆盖 finalize() 方法才能执行清理工作。

    protected void finalize() throws java.lang.Throwable {
    		super.finalize();
    		System.out.println("非Java资源已释放");
    		}
    

    当垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的finalize()方法。但是在Java中,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行,显然指望它做收尾工作是靠不住的。

    那么finalize()究竟是做什么的呢?它最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。

    finalize()特点:

    1. 垃圾回收器准备释放内存的时候,会先调用finalize()。
    2. Java中所有类都从Object类中继承finalize()方法。
    3. 垃圾回收和finalize()都是靠不住的,只要JVM还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。

    理解finalize( ) 正好在垃圾回收以前被调用非常重要。例如当一个对象超出了它的作用域时,finalize( ) 并不被调用。这意味着你不可能知道何时、甚至是否、finalize( ) 被调用。因此,你的程序应该提供其他的方法来释放由对象使用的系统资源,而不能依靠finalize( ) 来完成程序的正常操作。

    Java程序在执行构造函数初始化到底是在干嘛

    在了解了构造函数功能之后,我们往深入一点在思考,jvm是如何执行构造函数的?

    众所周知,每一个Java中的对象都至少会有一个构造函数,如果我们没有显式定义构造函数,那么它将会有一个默认无参的构造函数。在编译生成的字节码中,这些构造函数会被命名成<init>()方法,参数列表与Java语言书写的构造函数的参数列表相同。

    类的生命周期为:加载、连接(验证、准备、解析)、初始化、使用和卸载。
    Java程序执行构造函数就是在初始化这个阶段,在这个阶段,jvm会调用 实例构造器<init>() 收集实例代码块实例变量的赋值语句,还有构造函数里面的代码,将其一起执行并初始化赋初值。

    构造器

    概念:构造器是javac编译生成的一个函数,是在字节码层面存在的“函数”。它其实对一些代码的整合后生成的函数。和都是构造器,是编译器生成的。
    (1)实例构造器<init>,是生成对象时执行的。我们在写代码new一个对象,其实执行的就是构造器。整合了父类的实例构造器、实例代码块{}、变量初始化和构造函数的代码。
    (2)类构造器<clinit>,是虚拟机类加载时调用。
    <clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块static{}中的语句合并产生的,其中编译器收集的顺序是由语句在源文件中出现的顺序所决定。
    <init>()是指收集类中的所有实例变量的赋值动作、实例代码块和构造函数合并产生的。

    实例<init>构造器与构造函数的关系:

    构造器是由javac 命令生成.而构造函数则实质为我们写的java代码构造方法(也叫构造函数), <init>构造器的生成和构造函数相互对应,如果我们的java代码没有显示的构造函数,那编译器将会添加一个没有参数的、访问性(public、protected或private)与当前类一致的默认构造函数。并根据默认构造函数生成<init>。

    类构造器()与实例构造器()

    类构造器()与实例构造器()不同,它不需要程序员进行显式调用,虚拟机会保证在子类类构造器()执行之前,父类的类构造()执行完毕。由于父类的构造器()先执行,也就意味着父类中定义的静态语句块/静态变量的初始化要优先于子类的静态语句块/静态变量的初始化执行。特别地,类构造器()对于类或者接口来说并不是必需的,如果一个类中没有静态语句块,也没有对类变量的赋值操作,那么编译器可以不为这个类生产类构造器()。

    展开全文
  • 枚举被设计成单例模式,即枚举类型会由JVM在加载的时候,实例化枚举对象,你在枚举类中定义了多少个就会实例化多少个,JVM为了保证每一个枚举类元素的唯一实例不会允许外部进行new的,所以会把构造函数设计成...

    枚举被设计成是单例模式,即枚举类型会由JVM在加载的时候,实例化枚举对象,你在枚举类中定义了多少个就会实例化多少个,JVM为了保证每一个枚举类元素的唯一实例,是不会允许外部进行new的,所以会把构造函数设计成private,防止用户生成实例,破坏唯一性。
    枚举类型是单例模式的。你需要实例化一次,然后再整个程序之中就可以调用他的方法和成员变量了。枚举类型使用单例模式是因为他的值是固定的,不需要发生改变。

    参考:

    https://zhidao.baidu.com/question/364587486601224772.html

    https://zhidao.baidu.com/question/265224052.html





    展开全文
  • 我相信Joshua Bloch在他的非常好的书《 Effective Java》中首先说了它:与构造函数相比,静态工厂方法是实例化对象的首选方法。 我不同意。 不仅因为我相信静态方法是纯粹的邪恶,而且主要是因为在这种特殊情况下,...

    我相信Joshua Bloch在他的非常好的书《 Effective Java》中首先说了它:与构造函数相比,静态工厂方法是实例化对象的首选方法。 我不同意。 不仅因为我相信静态方法是纯粹的邪恶,而且主要是因为在这种特殊情况下,它们伪装成好的方法,使我们认为我们必须爱上它们。

    翻译自: https://www.theserverside.com/blog/Coffee-Talk-Java-News-Stories-and-Opinions/Constructors-or-static-factory-methods

    展开全文
  • 构造函数就是在实例化过程中被实例化的方法 例如: text t=new text();//这就是构造函数 构造函数是在被实例化的过程中被调用的; 构造函数中的方法是本身存在的只是被隐藏而已 构造函数的名称必须和类名...

    一、构造函数

    构造函数就是在实例化过程中被实例化的方法

    例如:

    text t=new text();//这就是构造函数

    构造函数是在被实例化的过程中被调用的;

    构造函数中的方法是本身存在的只是被隐藏而已

    构造函数的名称必须和类名一样,并且无任何返回值

     

    二、重载

    定义关键字 overload

     方法名一样,但是参数类型不一样, 在这种情况下是允许有重名的方法的,这就被称之重载

     

    三、静态方法和静态成员:

      定义关键字static

    非静态方法需要实例化对象,通过对象来点出方法,一个构造函数被实例化的过程可以实例化多个对象;在产生的数据中不会被覆盖

    静态方法,不需要实例化对象,直接通过类名点出方法,通过类名点出来的方法,在产生的数据会被覆盖

     

    转载于:https://www.cnblogs.com/zhulijun/p/6719163.html

    展开全文
  • 静态构造函数是在构造函数方法前面添加了static关键字之后形成的,并且没有...静态构造函数前面必须是static 关键字。 静态构造函数中不能实例实例变量。(变量可以分为类级别和实例级别的变量,其中类级别的有...
  • 构造函数

    2017-10-24 20:16:31
    构造函数必须很类名相同,没有返回值; 每个类可以有多个构造函数 构造函数伴随着new操作一起调用,而且不能由程序的编写者直接调用,必须要由系统调用。构造函数在对象实例化的时候会被自动调用,且只能运行一次...
  • 静态构造函数是在构造函数方法前面添加了static关键字之后形成的,并且没有修饰符...3、静态构造函数前面必须是static 关键字。如果不加这个关键字,那就是普通的构造函数了。 4、静态构造函数中不能实例实例变...
  • 构造函数的首字母必须大写,用来区分于普通函数 内部使用this对象,来指向即将要生成的实例对象 使用new来生成实例对象 构造函数的作用: 当你需要大批量的写对象的时候,就需要用到构造函数,它可以方便创建多个...
  • 构造函数跟一般的实例方法十分相似;但是与其它方法不同,构造器没有返回类型,不 会被继承,且可以有范围修饰符。 构造器的函数名称必须和它所属的类的名称相同。 它承担着初始化对象数据成员的任务。 如果在编写...
  • 什么是构造函数

    2020-07-30 14:15:00
    1,构造函数必须与类名相同,并且不能有返回值(返回值类型也不能写void) 2,每个类可以有多个构造函数,如果没有类中没有写构造函数,则编译器会自动添加一个无参的构造函数,但该构造函数不会执行任何的代码 3,...
  • 构造函数中的方法本身被隐藏的 public 名(){} 重载 overload 方法名一样,但是参数类型不一样,在这种情况下允许有重名的方法的,这就被称之重载 静态方法 static 非静态方法需要实例化对象,通过对象...
  • 构造函数的定义:专门用于生成对象数据类型的函数,其本质也一种函数。构造函数又具体分为: 1.JavaScrip程序定义好的构造函数,称为内置构造函数; 2.在项目中自行定义的构造函数,称为自定义构造函数构造函数...
  • 2、当父类只有有参构造函数时,子类可以有有参和无参构造函数,子类有参构造函数必须显式调用父类的有参构造函数,子类无参构造函数也必须显式调用父类的有参构造函数,但需给父类有参构造函数赋实参。 ...
  • 如果需要创建对象就需要提供一个static方法来访问本身的构造函数。简单例子: class A { public: static A* createInstance() {return new A();} private: A(){} }; 有兴趣的话可以参考一下singleton设计模式。
  • 既然抽象类并不能实例化,那抽象类中的构造函数存在的意义什么?抽象类必须被子类继承来实现。 子类在调用父类时 无论自己有没有构造方法都会先去执行父类无参的函数。哪怕父类抽象类。虽然抽象类不能被实例化,...
  • 但是这个方法有一个限制,就是要求类必须有默认的构造函数。但我们在做框架的时候,很难保证要动态构造的类实例,都有默认构造函数的,那怎么办呢? 其实用过C++或者Delphi的都知道,其实构造一个对象,分配内存...
  • 静态构造函数不可被直接调用,当创建类实例或引用任何静态成员之前,静态构造函数被自动执行,并且只执行一次。即:静态运行时被加载一次。 非静态每次运行都被加载 非静态类需要你自己去实例化加载它,才能调用 ...
  • 因此子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程。 二、子类的所有构造函数中的第一行,其实都有一条隐身的语句super(); 1、父类有空参:没有有参构造时系统默认给出了,或.
  • 构造函数:在类被实例化的时候被执行的函数,可以设置类的初始默认值,方法必须和类名一致这样才能称为构造函数。new 类名(); 红色箭头所指的我们称之为构造函数 重载:overload方法名一样,但是参数类型不...
  • set注入的缺点无法清晰表达哪些属性是必须的,哪些可选的,构造注入的优势通过构造强制依赖关系,不可能实例化不完全的或无法使用的bean。 二 举例 1 Employee package com.hsp.constructor; public class ...
  • 1.在C#中,一些都对象。你要用一个对象,就必须用new来实例化类(static类例外)。当你用new命令时,系统就会自动调用该类的构造函数,做些初始化之类的工作。至于方法,你只能通过手工方式用...构造函数是可以重
  • 构造函数是一种特殊的函数,用来在对象实例化时初始化对象的成员变量 特点 1.构造函数名字必须与类的名字相同,并且不能有返还值(返还值也不能为)。 2.每个类可以有多个构造函数 3.构造函数可以有0个,1个或1...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,810
精华内容 724
关键字:

构造函数必须是实例方法