java 构造函数调用顺序
java父类方法调用顺序

java父类方法调用顺序
在Java中,当子类继承自父类并且重写了父类的方法时,父类
方法的调用顺序取决于子类的实现方式。
当子类调用父类的方法时,会根据以下几种情况进行调用:
1. 如果子类没有重写父类的方法,那么直接调用父类的方法。
2. 如果子类重写了父类的方法,并且在子类中通过super关键
字调用父类方法,那么首先会执行父类的方法,然后再执行子类的
方法体。
3. 如果子类重写了父类的方法,但在子类中没有通过super关
键字调用父类方法,那么只会执行子类的方法体,而不会执行父类
的方法。
在Java中,方法的调用顺序遵循继承链,即先从子类开始,如
果在子类中找不到对应的方法,则会去父类中寻找。
因此,父类方
法的调用顺序取决于子类对该方法的重写和调用方式。
这种调用方
式保证了程序的灵活性和可维护性,使得子类可以根据需要选择是
否调用父类的方法以及何时调用。
在java中方法的调用

在java中方法的调用
在Java中,方法的调用可以通过以下几种方式来实现:
1. 直接调用静态方法:如果方法是静态方法,可以通过类名直接调用,例如:`ClassName.methodName()`
2. 对象调用方法:如果方法不是静态方法,需要先创建对象,然后通过对象来调用方法,例如:`objectName.methodName()`
3. 方法的递归调用:方法可以在其自身内部被调用,这种调用称为递归调用。
递归调用可以用于解决一些需要重复执行相同操作的问题。
4. 方法的链式调用:在一个方法中调用另一个方法,并将其作为当前方法的返回值,可以实现方法的链式调用。
这种调用方式可以简化代码的编写,提高代码的可读性。
例如:
`objectName.methodName1().methodName2().methodName3()`
5. 方法的重载:同一个类中可以定义多个方法名称相同但参数列表不同的方法,这种情况称为方法的重载。
编译器根据方法的参数列表来确定调用哪个方法。
6. 方法的覆盖:子类可以重写父类的方法,这种情况称为方法的覆盖。
通过子类对象调用被覆盖的方法时,会自动调用子类中的方法。
继承下构造函数的执行顺序

继承下构造函数的执⾏顺序这⾥先给出结论,在贴出代码与执⾏结果~⼀个派⽣类构造函数的执⾏顺序如下:第⼀步执⾏:虚拟基类的构造函数(多个虚拟基类则按照继承的顺序执⾏构造函数)。
第⼆步执⾏:基类的构造函数(多个普通基类也按照继承的顺序执⾏构造函数)。
第三步执⾏:类类型的成员对象的构造函数(按照初始化顺序)。
第四部执⾏:派⽣类⾃⼰的构造函数。
如果⼀个派⽣类不仅继承于⼀个基类,⽽且还有这个基类的成员对象,那么会进⾏两次构造函数的执⾏(⼀个⽤于初始化派⽣类中基类部分的内部成员,另⼀个是初始化派⽣类的基类类型成员变量的内部成员),详细看派⽣类Son2的执⾏结果。
你下⾯声明了A,B,C,D,Object1,Object2留个基类以及Son1,Son2,Son3,Son4,Son5(Son5是⼀个错误的例⼦,编译不能通过)每个基类都有两个构造函数,默认的构造函数不接受参数,输出的Default+字符串带参数的输出的⾃⼰类的特有信息。
(为了⽅便观看,我在后⾯会再贴⼀下结论)参考Son1:可以验证上述派⽣类构造函数的执⾏顺序;参考Son2:可以验证构造函数是严格照上⾯所说的顺序执⾏,与初始化的顺序⽆关。
同时,如果不显⽰的执⾏基类构造函数的初始化,就会按照顺序调⽤默认的构造函数。
参考Son3:可以说明继承下执⾏的构造函数与类类型的成员变量的构造函数是占⽤两个不同的内存地址空间,⼆者不会相互影响。
参考Son4:可以说明,⽆论是否显⽰的初始化类类型的成员变量,都会按照成员变量在类中的声明顺序执⾏构造函数。
参考Son5:这个解决了我之前的疑问,如果在派⽣类的构造函数中初始化类类型的成员对象会怎么样,发现这样是不可取的,因为在类的声明中是不可以实际分配内存的,但是可以声明。
(关于Son5的理解需要进⼀步阐明:这⾥可能涉及到了C++内存分配,拷贝赋值的原理,如果不是很懂的话这⾥我们暂且按我说的⽅式去理解。
)classA{public:A(intnum){Show();}A(){cout<<"Defaultaaa"<<endl;}voidShow(){cout<<"aaa"<<endl;}};classB{public:B(intnum){Show();}B(){cout<<"Defaultbbb"<<endl;}voidShow(){cout<<"bbb"<<endl;}};classC{public:C(intnum){Show();}C(){cout<<"Defaultccc"<<endl;}voidShow(){cout<<"ccc"<<endl;}};classD{public:D(intnum){Show();}D(){cout<<"Defaultddd"<<endl;}voidShow(){cout<<"ddd"<<endl;}};classObject1{public:Object1(intnum){Show();}Object1(){cout<<"DefaultObject1"<<endl;}voidShow(){cout<<"Object1"<<endl;}};classObject2{public:Object2(intnum){Show();}Object2(){cout<<"DefaultObject2"<<endl;}voidShow(){cout<<"Object2"<<endl;}};classSon1:publicA,virtualpublicB,publicC,virtualpublicD{public:Son1():A(1),B(1),C(1),D(1),ob1(1),ob2(1){cout<<"son1"<<endl;}Object1ob1;Object2ob2;};classSon2:publicA,virtualpublicB,publicC,virtualpublicD{public:Son2():C(1),A(1),ob1(1),ob2(1){ //结果仍然是先执⾏A的构造函数,其次是C的,证明与初始cout<<"son2"<<endl; //化的顺序⽆关}Object1ob1;Object2ob2;};classSon3:publicA,virtualpublicB,publicC,virtualpublicD,virtualpublicObject1,publicObject2{public:Son3():ob1(1),ob2(1){cout<<"son3"<<endl;}Object1ob1;Object2ob2;};classSon4:publicA,virtualpublicB,publicC,virtualpublicD,virtualpublicObject1,publicObject2{public:Son4():ob2(1){ //注意,如果Object1没有默认构造函数,这⾥将⽆法编译通过cout<<"son4"<<endl;}Object1ob1;Object2ob2;};//class Son5:publicA,virtual public B,publicC,virtual public D//{//public:// Son5():A(1),B(1),C(1),D(1){// cout<<"son5"<<endl;// ob2=ob1; //这⾥编译不通过,没有与这些操作数匹配的”=”运算符(⼆者类型不同,需要重新定义‘=’) // ob1(1);// ob2(2); //这⾥编译不通过,在没有适当的operate()的情况下调⽤类类型对象// }// Object1 ob1(1); // 这⾥编译不通过,因为类的成员声明不需要分配内存,这样写就相当于执⾏//构造函数并分配内存了// Object2 ob2;//};int_tmain(intargc, _TCHAR* argv[]){cout<<"------------SON1------------"<<endl;Son1son1;cout<<"------------SON2------------"<<endl;Son2son2;cout<<"------------SON3------------"<<endl;Son3son3;cout<<"------------SON4------------"<<endl;Son4 son4;Object1obj;//son4.ob1(1); //这句话是错误的编译不通过,在没有适当的operate()的情况下调⽤类类型对象son4.ob1=obj;system("pause"); //这句只是为了让cmd停留显⽰,以免闪退(VS控制台程序需要)return 0;}以上代码是在VS2012ConsoleApplication控制台下编译测试的,结果如下:再贴⼀遍:参考Son1:可以验证⼀开始介绍的派⽣类构造函数的执⾏顺序;参考Son2:可以验证构造函数是严格照上⾯所说的顺序执⾏,与初始化的顺序⽆关(尽管表⾯上C⽐A初始化的要早)。
java new thread 的构造函数

java new thread 的构造函数Java中的线程是一种执行路径,它独立于主程序的执行。
在多线程编程中,有时候我们需要创建新的线程来执行特定的任务。
Java提供了Thread类来创建新线程,而Thread类的构造函数则是创建新线程的入口。
本文将以“java new thread 的构造函数”为主题,详细解析Java中Thread类的构造函数。
第一部分:Thread类的构造函数简介1. Thread类概述Java中的线程是通过Thread类来表示和控制的。
Thread类是Java中用于线程操作的核心类之一,它提供了一系列的方法和属性用于创建、启动和管理线程的行为。
2. Thread类的构造函数Thread类提供了多个构造函数用于创建线程对象,常用的有以下几种:Thread():创建一个新的线程对象。
Thread(Runnable target):通过实现Runnable接口的对象来创建一个新的线程对象。
Thread(Runnable target, String name):通过实现Runnable接口的对象和指定名称来创建一个新的线程对象。
Thread(String name):通过指定名称来创建一个新的线程对象。
Thread(ThreadGroup group, Runnable target):通过实现Runnable接口的对象和指定的线程组来创建一个新的线程对象。
第二部分:Thread类构造函数的详细解析1. Thread()该构造函数用于创建一个新的线程对象,一个线程对象代表一个可以独立执行的线程。
调用该构造函数后,并不会立即启动线程的执行,需要调用start()方法来启动线程。
示例代码:Thread myThread = new Thread();myThread.start();2. Thread(Runnable target)该构造函数用于通过实现Runnable接口的对象来创建一个新的线程对象。
Java——补充:构造方法super()与构造方法无参有参构造方法this()与构造方法

Java——补充:构造⽅法super()与构造⽅法⽆参有参构造⽅法this()与构造⽅法参考⽂章:构造⽅法在new的时候⾃动执⾏。
且只执⾏⼀次。
new⼀次执⾏⼀次每个类都有构造⽅法,即使不写也有,编译时javac会⾃动检查类是否有构造⽅法,如果有,就执⾏,没有就⾃动添加⼀个如果⽗类有含参构造⽅法,则⼦类也必须添加含参构造⽅法如果⽗类没有含参构造⽅法,⼦类⽆需添加构造⽅法this在构造⽅法之间的应⽤super在构造⽅法中的应⽤⾸先要明⽩super关键字的作⽤:1、super是调⽤⽗类的成员⽅法或成员变量。
但是还有⼀个问题:.也就是说⼦类对象中,⽗类的构造⽅法会先执⾏。
那么为什么要执⾏⽗类构造⽅法呢?假设,创建了⼀个⽗类,含有⼀个成员属性a=1;含有⼀个构造⽅法,将a=5;。
因为如果⼦类创建的对象调⽤⽗类的成员变量a时,在不添加super()时,会得到a=1;如果添加super()就会得到a=5;我们都知道,构造⽅法在创建对象时执⾏,a应该等于5,故如果不调⽤super()就会得到错误的值。
2、super()在构造⽅法中是调⽤⽗类构造⽅法的意思。
当创建⼦类对象时,⽗类对象先进内存。
这样⼦类才能⾃动拥有⽗类的成员。
3、⼦类的构造器,⽆论重载多少个,第⼀⾏必须是super();当你不写时表⽰空参super();是否写参数,要根据⽗类决定,⽗类有参数,那么⼦类的super()必须有参数。
4、构造⽅法⽆法继承,⾃然也没有重写这个概念。
5、super()语句必须是构造⽅法的第⼀⾏代码。
总结⼀下:其实这些内容说⽩了,就是在说⼀句话。
super是⽗类对象引⽤,this是本类对象引⽤。
super(),this()都必须放在构造⽅法的第⼀⾏,super()和this()绝不能⼀块⽤,super(),this()⽆参时可以省略不写。
会报错:快捷键:ctrl+T ⽤于打开继承关系图。
⼦类的构造函数必须要 super() 吗?不是必须,是⾃动必须的情况:————指明调⽤哪个含参构造函数public class Father {public String name;public Father(String name) { = name;}}public class Son extends Father{public Son(String name) {super(name);//必须调⽤,否则他会默认调⽤⽗类的⽆参构造函数,⽽⽗类的⽆参构造函数已经被有参的覆盖,所以找不到}this()只能⽤在构造函数中,且它必须是第⼀⾏语句?1.在构造函数中,如果你不指定构造器之间的调⽤关系,那么编译器会给你加上super();⽬的是在初始化当前对象时,先保证了⽗类对象先初始化。
JAVA基础知识重难点

JAVA基础知识重难点声明:以下内容为个⼈期末对JAVA基础知识的总结,来源于各种资料搜索和个⼈理解整理⽽出,也许有不妥的地⽅,欢迎学习指教1.Java语⾔具有可移植性、可跨平台运⾏特点的原因是什么?Java——编译器——jvm——平台Java⽤编译器编译成.class的字节码⽂件,字节码类似于机器指令,同⼀字节码可以在任何带jvm虚拟机的平台运⾏,从⽽实现java的跨平台性。
所谓语⾔的跨平台性并不是说是源⽂件的跨平台性(如果要这么定义那么任何的语⾔都是跨平台性的),⽽是指源⽂件编译⽣成的⽂件的跨平台性。
因为Java字节码是结构中⽴的,所以Java 的程序是可移植的。
他们可以不经过重新编译⽽在任何⼀个机器上运⾏。
2.为什么说Java语⾔具有健壮、安全的特性?Java 编译器检测出许多别的语⾔只有在⾸次执⾏的时候才会指出的问题。
Java 已经清除了⼏种在其它语⾔中被发现易于出错的编程结构。
Java具有运⾏时异常处理特性,垃圾回收机制,它为健壮性提供了编程⽀持。
Java 实现了⼏种安全机制以保护你的系统遭受危险程序的破坏。
3.简述Java虚拟机(JVM)的作⽤是什么?JVM就是Java虚拟机,它是⼀个虚构出来的计算机,可在实际的计算机上模拟各种计算机的功能。
JVM有⾃⼰完善的硬件结构,例如处理器、堆栈和寄存器等,还具有相应的指令系统。
JVM是java字节码执⾏的引擎,还能优化java字节码,使之转化成效率更⾼的机器指令。
Java程序的跨平台特性主要就是因为JVM 实现的。
在编译java程序时会将写好的源程序通过编译器编译⽣成.class⽂件(⼜称为字节码⽂件),不同的平台对应着不同的JVM,之后就是通过JVM内部的解释器将字节码⽂件解释成为具体平台上的机器指令执⾏,所以就可以实现java程序的跨平台特性。
4.简述JVM的垃圾回收机制。
确保被引⽤对象的内存不被错误的回收。
当⼀个对象不再有任何⼀个引⽤变量指向它时,这个对象就被应⽤抛弃。
java 类加载完成后自动调用的方法
java 类加载完成后自动调用的方法在Java编程语言中,类加载是一个非常重要的过程,而当类被加载完成后,有时我们需要执行一些初始化操作。
本文将详细介绍Java类加载完成后自动调用的方法,帮助读者更好地理解这一机制。
在Java中,当类被加载完成后,有几个特殊的方法会被自动调用,主要包括以下几种:1.静态代码块(Static Block)静态代码块是位于类定义中,且被static关键字修饰的代码块。
它在类加载时执行,并且只会执行一次。
通常用于初始化静态变量或者执行一些只需要执行一次的代码。
```javapublic class MyClass {static {System.out.println("静态代码块执行");}public static void main(String[] args) {MyClass myClass1 = new MyClass();MyClass myClass2 = new MyClass();}}```在上面的例子中,尽管我们创建了两个MyClass对象,但静态代码块只执行了一次。
2.初始化方法(Initializer)除了静态代码块,还可以通过在类中定义一个初始化方法(无返回值且方法名与类名相同),并在该方法中进行初始化操作。
```javapublic class MyClass {public MyClass() {System.out.println("构造方法执行");}{System.out.println("非静态代码块执行");}public static void main(String[] args) {MyClass myClass = new MyClass();}}```在这个例子中,非静态代码块(没有static修饰的代码块)在每次创建对象时都会执行。
3.构造方法(Constructor)构造方法是用于创建对象时初始化对象的方法。
Java中的constructor(整理版)
/** * 实例方法的名字可以与类名同名 * * */ public class DemoMethodNameSameAsClassName e;
public String getDemoName() {
return demoName; }
Java 中的 constructor
1、构造函数的特点
构造函数有以下特点: (1)、构造函数名与类名相同; (2)、构造函数不返回任何值,也没有返回类型,不能有任何非访问性质的 修改符; (3)、每一类可以有零个或多个构造方法; (4)、构造方法在创建对象时自动执行,一般不用显示地直接调用。 其次,就上面几个需要说明的特点进一步进行解释: 特点一:构造函数名与类名相同。这个很简单,只要知道 Java 语言是区分 大小写即可; 特点二:这一特点需要说明,并加以强调。构造函数不返回任何值,也没有 返回类型(有了返回类型的话就是不是构造方法了,而是实例方法),因此在构 造函数前面不可添加各种基本数据类型,也不可添加引用类型。 和实例方法一样,构造器可以有任何访问的修饰符,public、private、protected 或者没有修饰符,都可以对构造方法进行修饰。不同于实例方法的是构造方法不 能有任何非访问性质的修饰符修饰,例如 static、final、synchronized、abstract 等都不能修饰构造方法。(解释:构造方法用于初始化一个实例对象,所以 static 修饰是没有任何意义的;多个线程不会同时创建内存地址相同的同一个对象,所 以 synchronized 修饰没有意义;构造方法不能被子类继承,所以 final 和 abstract 修饰没有意义。) 特点三:每一类可以有零个或多个构造方法。如果类没有构造函数,编译器 会自动添加默认的无参构造函数,当调用默认的构造函数时,就会利用构造函数 为类的成员变量进行初始化,当然不同的类型其默认的初始值不同。一旦用户定 义了构造函数,则不会产生默认的构造函数。当有多个构造函数时,系统会根据 产生对象时,所带参数的不同而选择调用不同的构造函数。 我们知道,java 语言中规定每个类至少要有一个构造方法,为了保证这一点,
java初始化方法
java初始化方法Java是一种面向对象的编程语言,它的初始化方法是程序中非常重要的一部分。
在Java中,对象的初始化可以通过构造函数、静态块和实例块来完成。
下面将详细介绍这三种初始化方法。
一、构造函数构造函数是用于创建对象并初始化对象的特殊方法。
在Java中,每个类都有一个或多个构造函数,用于创建该类的对象。
当一个新对象被创建时,它会自动调用该类的构造函数来完成初始化工作。
1.1 构造函数的特点- 构造函数与类名相同;- 构造函数没有返回值类型;- 构造函数可以有参数或者没有参数;- 如果没有定义任何构造函数,则系统会自动提供一个无参构造函数。
1.2 构造函数示例下面是一个简单的Person类示例:```public class Person {private String name;private int age;public Person(String name, int age) { = name;this.age = age;}public String getName() {return name;}public void setName(String name) { = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}```在上述代码中,我们定义了一个Person类,并为其提供了一个有参数的构造函数。
该构造函数接收两个参数:name和age,并将它们分别赋值给类中的成员变量name和age。
在使用该构造函数创建对象时,需要传递两个参数。
```Person person = new Person("Tom", 18);```二、静态块静态块是在类加载时执行的一段代码块,用于初始化静态成员变量或执行一些特殊的操作。
当Java虚拟机加载一个类时,会先执行该类中的静态块,然后才会执行其他代码。
构造函数的八种方法
构造函数的八种方法构造函数是一种特殊的函数,它在创建对象时用于初始化对象的成员变量。
在不同的编程语言中,构造函数有不同的实现方式,下面我们将介绍构造函数的八种方法。
1. 默认构造函数。
默认构造函数是指在创建对象时没有参数传入的构造函数。
它通常用于初始化对象的成员变量为默认值,或者进行一些基本的初始化操作。
默认构造函数在不显式定义的情况下,编译器会自动生成一个默认的构造函数。
2. 带参数的构造函数。
带参数的构造函数是指在创建对象时需要传入参数的构造函数。
通过传入不同的参数,可以在创建对象时对对象的成员变量进行不同的初始化操作。
带参数的构造函数可以满足不同的对象初始化需求。
3. 拷贝构造函数。
拷贝构造函数是用于创建对象的副本的构造函数。
当使用一个对象初始化另一个对象时,拷贝构造函数会被调用。
拷贝构造函数通常用于深拷贝对象,确保对象的成员变量在内存中是独立的。
4. 委托构造函数。
委托构造函数是指一个构造函数可以调用另一个构造函数来进行对象的初始化操作。
这样可以避免代码重复,并且可以实现不同构造函数之间的复用。
5. 虚拟构造函数。
虚拟构造函数是指在继承关系中,子类可以重写父类的构造函数,以实现特定的初始化操作。
虚拟构造函数可以在对象的多态性中发挥作用,确保对象的正确初始化。
6. 显式构造函数。
显式构造函数是指在创建对象时需要使用关键字来显式调用的构造函数。
通过显式构造函数,可以实现更加严格的对象初始化控制,避免隐式类型转换带来的问题。
7. 删除构造函数。
删除构造函数是指通过关键字将一个构造函数标记为删除,从而禁止使用该构造函数来创建对象。
删除构造函数通常用于阻止特定类型的对象创建,以确保程序的安全性和稳定性。
8. 默认构造函数的继承。
默认构造函数的继承是指子类在没有定义任何构造函数的情况下,会自动继承父类的默认构造函数。
通过默认构造函数的继承,可以确保子类对象的正确初始化。
总结。
构造函数是面向对象编程中非常重要的概念,不同的构造函数方法可以满足不同的对象初始化需求。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
java 构造函数调用顺序
当一个复杂的对象被构造时,它的构造函数按下面的顺序被调用(that the order of constructor calls for a complex object is as follows)
1.其基类(base-class)的构造函数被调用,这个步骤以递归的方式重复,所以最底层(the root of hierarchy)的构造函数首先被执行,然后是它上一层派生类(the next-derived class)...直到最顶层的派生类(the most-derived class).
The base-class constructor is called. This step is repeated recursively such that the root of the hierarchy is constructed first, followed by the next-derived class, etc., until the most-derived class is reached.)
2.如果有包含关系(composition),那么它的成员对象按照声明的顺序被构造.
Member initializers are called in the order of declaration.
3.派生类构造函数的内容(body)被执行.
The body of the derived-class constructor is called.
一个实例:
class Cake{
Cake(){System.out.println("Cake()");}
}
class Meal {
Meal() { System.out.println("Meal()"); }
}
class Bread {
Bread() { System.out.println("Bread()"); }
}
class Cheese {
Cheese() { System.out.println("Cheese()"); }
}
class Lettuce {
Lettuce() { System.out.println("Lettuce()"); }
}
class Lunch extends Meal {
Lunch() { System.out.println("Lunch()"); }
}
class PortableLunch extends Lunch {
//if make derived-class object as the menber of the base-class will lead a infinit e
//loop and program will stop because of the memory consumed
//private Sandwich s=new Sandwich();
private Cake a=new Cake();
PortableLunch() { System.out.println("PortableLunch()");}
}
public class Sandwich extends PortableLunch
{
private Bread b = new Bread();
private Cheese c = new Cheese();
private Lettuce l = new Lettuce();
public Sandwich() {
System.out.println("Sandwich()");
}
public static void main(String[] args) {
new Sandwich();
}
}
输出:
Meal()
Lunch()
Cake()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
main()函数中要构造一个Sandwich的对象,调用(并不是执行)它基类PortableLunch的构造函数,PortableLunch又递归的调用,然后是Meal,Meal是继承的最底层的基类(不算Object)所以它的构造函数首先被执行,然后按次序返回到Lunch, PortableLunch,但在PortableLunch的构造函数被执行之前,它的成员对象Cake a先按照声明的顺序被构造.然后执行PortableLunch(),接着是Sandwich的成员对象,最后是Sandwich().
注:被注释掉的代码,将base-class的对象作为derive-class的成员对象,这样会递归无法结束,最后程序因堆栈耗尽而结束(Exception in thread main ng.StackOverflowError).。