构造方法和构造函数概念

刚入门可能会分不清构造方法和构造函数这两个概念。
一般我们讲的”构造函数”就是”构造方法”,
在C语言中被习惯称为构造函数,而在Java里我们一般叫做构造方法;
构造方法又分为有参和无参的构造方法;
两种叫法在Java里其实是没有本质区别的。

Java中什么是构造方法

构造方法是一种特殊的方法,具有以下特点。
(1)构造方法的方法名必须与类名相同。
(2)构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。
(3)构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。
(4)一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。
(5)构造方法可以重载,以参数的个数,类型,顺序。

Java构造方法的作用

构造方法作用就是对类进行初始化。 如果你没有定义任何构造方法的类,程序会为你取一个不带任何参数的构造函数,那么你产生类的对象时只能用不带参数的方法,如:class a {}//没有任何构造函数。

在Java中new一个对象的时候要用到构造函数,例如Person person = new Person();这时调用的是Person的无参数构造方法;
Person person = new Person(“李荣浩”,18);这个是调用Person有参数构造方法。

java简述构造方法的特点 简述java中构造方法的概念_构造方法

在JAVA中如果不写构造方法的话,程序会默认加上一个无参数的构造方法,但是如果已经有了一个有参数的构造方法,那么无参数的构造方法就不会默认被加上.例如上图Person类中已经有了一个有参数的构造方法,这时再使用Person person = new Person();来创建对象的时候就会出错,这就是为什么书上要强调写了有参数的构造方法就最好加一个无参数的构造方法.

构造方法和普通方法(也叫成员方法)的区别

构造方法和普通方法在定义上有区别:
1.首先构造方法没有返回值(void也不行),构造方法名必须和类名相同。
2.构造方法可以用来完成,成员属性的初始化工作。
3.每个类必须至少有一个构造方法,只有权限修饰符,方法名必须与类名一致不是自定义的话,编译器会自动给定一个无参构造方法,构造方法是在实例化时必须调用的,作用是初始化属性,没有返回值,不能重写,可以重载,接口没有构造函数,抽象类可以有。
4:构造方法属于系统调用(一般在new时调用),一般不允许程序员显示调用。
5.普通方法不是static修饰的,类实例化后按需要调用,必须有返回值,就算是没有返回值也得是void修饰,可以被重写,可以被重载。通俗说普通方法,就是类的行为举止。表明该做什么事情..等等。

构造方法和普通方法什么时候调用

当你new一个新对象时必须要调用构造方法才行,构造方法一般用来给成员变量赋初值的,而普通方法则是在new完之后再调用的,说白了!构造方式是赋初始值用的!方法是被调用的,new完之后需要哪个就调用哪个!
接下来以Hello1.java和Hello2.java的代码为例详细介绍构造方法和普通方法的调用。

如下图Hello1.java代码所示,我在该类中定义了name,age,salary三个成员变量(本篇文章末会补充讲解成员变量和局部变量),和一个Hello1构造方法,hage(){},hsalary(){},printH(){} 三个普通方法。

java简述构造方法的特点 简述java中构造方法的概念_构造方法_02

java简述构造方法的特点 简述java中构造方法的概念_构造函数_03

在Hello2.java中,我们怎么才能调用到Hello1类中的普通方法,并把参数传递过去呢。

第一步我们需要先new一个Hello1的对象,这里我们就必须先调用构造方法了,Hello1 h1=new Hello1(“李荣浩”);

而且需要注意,因为我们在Hello1类中止只定义了有参的构造方法,没有定义无参的构造方法,所以在new对象的时候只能调用Hello1 h1=new Hello1(“李荣浩”);,如果调用Hello1 h1=new Hello1( );会报错,如果在Hello2类中想调用Hello1 h1=new Hello1( );这个对象,在Hello1类里有有参构造方法的前提下,必须要定义一个无参的和类名一样的构造方法,如public Hello1(){};

第二步,我们就可以用new的h1对象去调用Hello1类中的普通方法了,我们先来看看h1.可以调用到哪些方法,通过下图我们可以看到,在Hello2类中通过构造方法可以调用我们在Hello1类中定义的所有普通方法,这就是构造方法和普通方法的调用。

java简述构造方法的特点 简述java中构造方法的概念_构造函数_04

补充知识点

按照下图中红色方框圈中处,我们将补充以下知识点:
1. 形参,实参
2. 局部变量,成员变量,实例变量
3. 内存分配: 类变量、实例变量、成员变量、局部变量
4. java中this关键字的作用

java简述构造方法的特点 简述java中构造方法的概念_this_05

补充点1:形参和实参

形参是形式参数,参数名可以是任意的,实参是真实存在的参数,其类型要与参数的数据类型一样。
形式类型:是你在定义方法时括号里面的参数。
如:
public void setName(String name)
{
this.name = name;
}
name:就是形式参数。
实参是实际参数,在调用方法时传进去的参数。
实际类型:在调用方法是传进去的参数。
如: setName(“张三”);
“张三”:就是实际类型。
但是要注意形式类型与实际类型的数据类型的匹配。

专业名词解析:
1.形参:用来接收调用该方法时传递的参数。只有在被调用的时候才分配内存空间,一旦调用结束,就释放内存空间。因此仅仅在方法内有效。
2.实参:传递给被调用方法的值,预先创建并赋予确定值。
3.传值调用:传值调用中传递的参数为基本数据类型,参数视为形参。
4.传引用调用:传引用调用中,如果传递的参数是引用数据类型,参数视为实参。在调用的过程中,将实参的地址传递给了形参,形参上的改变都发生在实参上。

案例分析:
1.基础数据类型(传值调用)
传值,方法不会改变实参的值。

java简述构造方法的特点 简述java中构造方法的概念_this_06

2.引用数据类型(引用调用)
传引用,方法体内改变形参引用,不会改变实参的引用,但有可能改变实参对象的属性值。
举两个例子:
 (1)方法体内改变形参引用,但不会改变实参引用 ,实参值不变。

public class TestFun2 {  
public static void testStr(String str){  
    str="hello";//型参指向字符串 “hello”  
}  
public static void main(String[] args) {  
    String s="1" ;  
    TestFun2.testStr(s);  
    System.out.println("s="+s); //实参s引用没变,值也不变  
}  
}

执行结果打印:s=1

(2)方法体内,通过引用改变了实际参数对象的内容,注意是“内容”,引用还是不变的。

public class TestFun4 {  
public static void testStringBuffer(StringBuffer sb){  
    sb.append("java");//改变了实参的内容  
}  
public static void main(String[] args) {  
    StringBuffer sb= new StringBuffer("my ");  
    new TestFun4().testStringBuffer(sb);  
    System.out.println("sb="+sb.toString());//内容变化了  
}  
}

执行结果,打印:sb=my java 。
所以比较参数是String和StringBuffer 的两个例子就会理解什么是“改变实参对象内容”了。

总结:
1.java的基本数据类型是传值调用,对象引用类型是传引用。
2.当传值调用时,改变的是形参的值,并没有改变实参的值,实参的值可以传递给形参,但是,这个传递是单向的,形参不能传递回实参。
3.当引用调用时,如果参数是对象,无论对对象做了何种操作,都不会改变实参对象的引用,但是如果改变了对象的内容,就会改变实参对象的内容。

补充点2:局部变量,成员变量,实例变量

名词解释

类变量:
比较特殊的实例变量,用static修饰的,一个类共用这个变量,所有由这类生成的对象都共用这个变量,类装载时就分配存储空间。一个对象修改了变量,则所有对象中这个变量的值都会发生改变。

实例变量:
从属于类,由类生成对象时,才分配存储空间,各对象间的实例变量互不干扰,能通过对象的引用来访问实例变量。

局部变量:
方法中或者某局部块中声明定义的变量或方法的参数被称为局部变量

以以下两个代码为例:
bianliang1.java

public class bianliang1 {
     static int a = 0; //静态变量     
     int b = 0; //实例变量
}

bianliang2.java

public class bianliang2 {
    public static void main(String[] args) {
        bianliang1 a1 = new bianliang1();
        bianliang1 a2 = new bianliang1();
        a1.a = 3;
        a1.b = 4;
        System.out.println(a1.a);
        System.out.println(a1.b);
        System.out.println(a2.a);
        System.out.println(a2.b);
    }
}

输出结果:
3
4
3
0
* 解释:*

上面代码为什么会输出3 4 3 0;
类变量(即静态变量)是全局变量,所有的实例(如提到的a1、a2)共享的变量。如果你在一个实例中改变了其值,那么所有的实例的这个变量的都会改变,例如 a1.a=10,那么你打印a2.a的值时也是10。
而实例变量是每个实例自己独有的变量,互不干扰。就像你上面提到的,如果a1.b=4,打印a2.b还是0,那就说明a2实例中的b还是默认赋值0,并没有赋值4.

简而言之,类共享类变量,所以a2.a=3操作后 class A中a的值就变为3,自然a2.a输出值为3了。而实例变量b在被操作后,只是对于对象a1的变量b,局部的, 而不是整个类。

其他说法:

关于成员变量、实例变量、类变量、成员方法、实例方法、类方法的区别
简单来说:
类体的定义包括成员变量的定义和方法的定义。
1、成员变量包括实例变量和类变量;而成员方法包括实例方法、类方法,当然还有一种特殊的构造方法。
2、类变量、类方法就是类中的变量、方法,必须是静态的,要加static;故其又称静态变量、静态方法。
3、成员变量、成员方法是对象或实例中的变量、方法,不加static;

类变量:静态域,静态字段,或叫静态变量,它属于该类所有实例共有的属性,在内存中只有一个地方存储这个变量。而且所有的实例都可以修改这个类变量的值(前提是这个类变量没有被final修饰,否则是常量了),而且访问类变量的时候不用实例,直接用类就可以了。

类方法:和类变量一样,可以不用实例,直接用类就可以调用类方法。
实例变量:实例域,实例字段,或叫成员变量。
实例方法:或叫成员方法,必须先有实例,然后才能通过实例调用该实例方法。
使用方法:类方法可以直接调用类变量和类方法
类方法不可以直接调用实例变量和实例方法
类方法中没有this,因为没有实例,this不知道调用哪个实例
类方法可以从类里面直接访问类成员
实例方法可以调用类方法,访问类变量,但是不提倡这样做,会把类方法和类变量混淆成实例方法和实例变量

补充点3:内存分配: 类变量、实例变量、成员变量、局部变量

成员变量有2种:类变量和实例变量
全局变量也叫成员变量

类变量(又叫静态变量):前面加static关键字修饰;

1、jvm把.class类加载到非堆里,然后在堆中为.class的类变量开辟内存;堆中的地址存放于栈以便高速访问;
2、类变量的生命周期一直持续到整个“系统”关闭;
3、一旦赋值它的值就在你new出来的任何一个实例中具有相同的值;

实例变量:前面不加static关键字修饰;
1、当你用java关键字new一个对象时,jvm将在堆里创建对象,并在堆中开辟空间给变量(空间不一定连续),然后根据零散的堆内存地址,通过哈希算法得到“物理地址”;
2、实例变量的生命周期:当实例变量的引用丢失后,将被gc回收,但并不是马上释放堆中内存;
3、每一个new出来的新实例都可以对他赋予自己需要的值
例子

class example{
     static int a = 0;
     int b = 1;
}

a是类变量,b是实例变量
example e1 = new example();
example e2 = new example();
改变e1中a的值会使e2中的a值也改变,而e1中b值的变化不会带来e2中b值的变化;

同一个jvm里,一个类变量只需要分配一个内存空间;对于实例变量,每创建一次对象,都需要为实例变量分配一次内存空间;

实例变量:声明在某方法,或某代码段里(如for循环)
1、执行它时在堆中开辟内存,其引用被置于一个连续的栈中提供高速访问;
2、当局部变量一旦脱离作用域,内存立即释放;

知识点4:java中this关键字的作用

一、this关键字主要有三个应用:
(1)this调用本类中的属性,也就是类中的成员变量;
(2)this调用本类中的其他方法;
(3)this调用本类中的其他构造方法,调用时要放在构造方法的首行。

Public Class Student { 
     String name; //定义一个成员变量name
     private void SetName(String name) { //定义一个参数(局部变量)name
     this.name=name; //将局部变量的值传递给成员变量
 }
}

应用一:引用成员变量

如上面这段代码中,有一个成员变量name,同时在方法中有一个形式参数,名字也是name,然后在方法中将形式参数name的值传递给成员变量name,虽然我们可以看明白这个代码的含义,但是作为Java编译器它是怎么判断的呢?到底是将形式参数name的值传递给成员变量name,还是反过来将成员变量name的值传递给形式参数name呢?也就是说,两个变量名字如果相同的话,那么Java如何判断使用哪个变量?此时this这个关键字就起到作用了。
this这个关键字其代表的就是对象中的成员变量或者方法。也就是说,如果在某个变量前面加上一个this关键字,其指的就是这个对象的成员变量或者方法,而不是指成员方法的形式参数或者局部变量。为此在上面这个代码中,this.name代表的就是对象中的成员变量,又叫做对象的属性,而后面的name则是方法的形式参数,代码this.name=name就是将形式参数的值传递给成员变量。这就是上面这个代码的具体含义。
一般情况下,在Java语言中引用成员变量或者成员方法都是以对象名.成员变量或者对象名.成员方法的形式。不过有些程序员即使在没有相同变量的时候,也喜欢使用this.成员变量的形式来引用变量,这主要是从便于代码的阅读考虑的。一看到这个this关键字就知道现在引用的变量是成员变量或者成员方法,而不是局部变量。这无形中就提高了代码的阅读性。不过话说回来,这是this关键字在Java语言中的最简单的应用。从这个应用中,我们可以看出this关键字其代表的就是对象的名字。
其实如果是局部变量的话,也是相同的道理。如在上面的代码中,name不是形式参数,而是一个局部变量。此时Java也会遇到相同的疑惑,即变量名name代表的到底是局部变量还是形式参数?name=name到底代表的是什么含义?根据局部变量的作用域,在方法内部,如果局部变量与成员变量同名的话,那么是以局部变量为准。可是在name=name这个赋值语句中,将局部变量的值赋值给自己,显然并不是很合适。根据代码的含义,本来的意思应该是将局部变量赋值给成员变量。为了更清晰的表达这个含义,为此最好采用如下的书写格式this.name=name。这里的this关键字含义就是对象名student,为此this.name就表示student.name。

应用二:调用类的构造方法

public class Student { //定义一个类,类的名字为student。 
 public Student() { //定义一个方法,名字与类相同故为构造方法
  this(“Hello!”);
 }
 public Student(String name) { //定义一个带形式参数的构造方法
 }
}

this关键字除了可以调用成员变量之外,还可以调用构造方法。在一个Java类中,其方法可以分为成员方法和构造方法两种。构造方法是一个与类同名的方法,在Java类中必须存在一个构造方法。如果在代码中没有显示的体现构造方法的话,那么编译器在编译的时候会自动添加一个没有形式参数的构造方法。这个构造方法跟普通的成员方法还是有很多不同的地方。如构造方法一律是没有返回值的,而且也不用void关键字来说明这个构造方法没有返回值。而普通的方法可以有返回值、也可以没有返回值,程序员可以根据自己的需要来定义。不过如果普通的方法没有返回值的话,那么一定要在方法定义的时候采用void关键字来进行说明。其次构造方法的名字有严格的要求,即必须与类的名字相同。也就是说,Java编译器发现有个方法与类的名字相同才把其当作构造方法来对待。而对于普通方法的话,则要求不能够与类的名字相同,而且多个成员方法不能够采用相同的名字。在一个类中可以存在多个构造方法,这些构造方法都采用相同的名字,只是形式参数不同。Java语言就凭形式参数不同来判断调用那个构造方法。
在上面这段代码中,定义了两个构造方法,一个带参数,另一个没有带参数。构造方法都不会有返回值,不过由于构造方法的特殊性,为此不必要在构造方法定义时带上void关键字来说明这个问题。在第一个没有带参数的构造方法中,使用了this(“Hello!”)这句代码,这句代码表示什么含义呢?在构造方法中使this关键字表示调用类中的构造方法。如果一个类中有多个构造方法,因为其名字都相同,跟类名一致,那么这个this到底是调用哪个构造方法呢?其实,这跟采用其他方法引用构造方法一样,都是通过形式参数来调用构造方法的。如上例中,this关键字后面加上了一个参数,那么就表示其引用的是带参数的构造方法。如果现在有三个构造方法,分别为不带参数、带一个参数、带两个参数。那么Java编译器会根据所传递的参数数量的不同,来判断该调用哪个构造方法。从上面示例中可以看出,this关键字不仅可以用来引用成员变量,而且还可以用来引用构造方法。
不过如果要使用这种方式来调用构造方法的话,有一个语法上的限制。一般来说,利用this关键字来调用构造方法,只有在无参数构造方法中第一句使用this调用有参数的构造方法。否则的话,翻译的时候,就会有错误信息。这跟引用成员变量不同。如果引用成员变量的话,this关键字是没有位置上的限制的。如果不熟悉这个限制的话,那么还是老老实实的采用传统的构造方法调用方式为好。虽然比较麻烦,但是至少不会出错。

应用三:返回对象的值

this关键字除了可以引用变量或者成员方法之外,还有一个重大的作用就是返回类的引用。如在代码中,可以使用return this,来返回某个类的引用。此时这个this关键字就代表类的名称。如代码在上面student类中,那么代码代表的含义就是return student。可见,这个this关键字除了可以引用变量或者成员方法之外,还可以作为类的返回值,这才是this关键字最引人注意的地方。