返回列表 发新帖

【Android入坑系列教程】37.构造函数---面向对象

[复制链接]

62

主题

722

回帖

2756

积分

大学生

Rank: 5Rank: 5

金币
2029
好评
12
信誉
100

考神

发表于 2019-3-26 12:36:36 | 显示全部楼层 | 阅读模式  来自 四川
本帖最后由 pansong291 于 2019-3-27 11:54 编辑

上篇:36.类与对象(二)---面向对象
下篇:38.this引用句柄---面向对象

注意:如果你的回复只是“感谢分享”、“辛苦了”之类的与教程内容无关的字眼,还请不要回复本帖,谢谢合作!!!
注意:如果你的回复只是“感谢分享”、“辛苦了”之类的与教程内容无关的字眼,还请不要回复本帖,谢谢合作!!!
注意:如果你的回复只是“感谢分享”、“辛苦了”之类的与教程内容无关的字眼,还请不要回复本帖,谢谢合作!!!


构造函数的定义与作用
我们先来看一个程序:
class Person
{
    public Person()
    {
        System.
out.println("the constructor 1 is calling!");
    }
    private int age = 10;
    public void shout()
    {

        System.out.println("age is "+age);
    }
}
class TestPerson
{
    public static void main(String[] args)
    {
        Person p1=new Person();
        p1.shout();
        Person p2=new Person();
        p2.shout();
        Person p3=new Person();
        p3.shout();
    }
}
运行结果如下:
the constructor 1 is calling!
age is 10
the constructor 1 is calling!
age is 10
the constructor 1 is calling!
age is 10

通过运行的结果读者会发现,在 TestPerson.main 方法中并没有调用刚才新加的
Person()方法,但它却被自动调用了,而且我们每创建一个 Person 对象,这个方法都会被
自动调用一次。这就是“构造方法”。关于这个 Person 方法,有几点不同于一般方法的特征:
1. 它具有与类相同的名称;
2. 它不含返回值;
3. 它不能在方法中用 return 语句返回一个值
关于第二点,读者也可以理解为它具有固定的返回值,这个返回值就是新构造出来的对象;
关于第三点,它不能在方法中用 return 语句返回一个值不代表不可以用 return 语句提前
返回,只是它不能返回具体的值罢了。
在一个类中,具有上述特征的方法就是“构造方法”。构造方法在程序设计中非常有用,
它可以为类的成员变量进行初始化工作,当一个类的实例对象刚产生时,这个类的构造方法
就会被自动调用,我们可以在这个方法中加入要完成初始化工作的代码。这就好像我们规定
每个“人”一出生就必须先洗澡,我们就可以在“人”的构造方法中加入完成“洗澡”的程
序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一
个一个地告诉他们要“洗澡”了。
虽然初始化在程序设计中是一项非常重要的工作,可是仍然还有很多程序员在编程过程
中时常会疏忽对变量的初始化,使用构造方法就可以避免这种情况,并且可以实现一次完成
对类的所有实例对象的初始化,这免除了调用程序对每个实例对象都要进行初始化的繁琐工
作。
读者站在 Java 设计者的角度去想一想:构造方法的名称和类的名称为什么要相同呢?
这是因为构造方法由 Java 编译器负责调用,而编译器必须知道哪一个才是构造方法,采用
与类同名的方式应该是最简单合理的。
脚下留心:在构造方法里不含返回值的概念是不同于“void”的,对于“public void
Person()”这样的写法就不再是构造方法,而变成了普通方法,很多人都会犯这样的错误,
在定义构造方法时加了“void”,结果这个方法就不再被自动调用了。

构造方法的重载
上一章我们讲了方法的重载,构造方法也可以被重载,这种情况其实是很常见的,先来
看这段程序:
class Person
{
    private String name="unknown";
    private int age = -1;
    public Person()
    {
        System.out.println("constructor1 is calling");
    }
    public Person(String n)
    {
        name = n;
        System.out.println("constructor2 is calling");
        System.out.println("name is "+name);
    }
    public Person(String n, int a)
    {
        name = n;
        age = a;
        System.out.println("constructor3 is calling");
        System.out.println("name and age is "+name+";"+age);
    }
    public void shout()
    {
        System.out.println("listen to me!!");
    }
}
class TestPerson
{
    public static void main(String[] args)
    {
        Person p1=new Person();
        P1.shout();
        Person p2=new Person("Jack");
        P2.shout();
        Person p3=new Person("Tom", 18);
        P3.shout();
    }
}
Person 类里我们又添加了两个构造方法,其中一个构造方法接受外部传入的姓名,
再赋值给类的成员变量,另外一个构造方法接受外部传入的姓名和年龄,再赋值给类的成员
变量。上面定义了多个 Person 构造方法,这就是构造方法的重载。和一般的方法重载一样,
它们具有不同个数或不同类型的参数,编译器就可以根据这一点判断出用 new 关键字产生
对象时,该调用哪个构造方法了。
TestPerson.main 方法中,我们用 new 关键字产生了三个 Person 的实例对象,产生
对象的格式是:
    new 类名(参数列表)
Java 会根据我们在括号中传递的参数,自动为我们选择相应的构造方法,程序运行的
结果如下:
constructor1 is calling
listen to me!!
constructor2 is calling
name is Jack
listen to me!!
constructor3 is calling
name and age is Tom;18
listen to me!!

这三个对象调用了不同的构造方法,可见,因为括号中传递的参数个数或类型不同,调
用的构造方法也不同。
重载构造方法可以完成不同初始化的操作,当我们要创建一个 Person 实例对象的同时,
就直接给对人的姓名和年龄赋值,我们就可以使用下面的方式去产生这个 Person 实例对象。
Person p1=new Person("Tom", 18);
而不必先用 Person p1=new Person();语句产生 Person 实例对象,再单独对这个 Person
实例对象的姓名和年龄赋值。
我们来分析一下 p3=new Person("Tom", 18);语句都干了些什么?
它会做这样几件事:创建指定类的新实例对象,在堆内存中为实例对象分配内存空间,
并调用指定类的构造方法,最后将实例对象的首地址赋值给引用变量 p3。
首先,等号左边定义了一个类 Person 类型的引用变量 p3,等号右边使用 new 关键字创
建了一个 Person 类的实例对象。此时的内存状态如图 3.9 所示:

接着,调用相应的构造方法,构造方法接受外部传入的姓名和年龄,在执行构造方法中
的代码之前,进行属性的显式初始化,也就是执行在定义成员变量时就对其进行赋值的语句,
即程序 Person 类中的:
private String name="unknown"; //显式初始化
private int age = -1;// 显式初始化
此时的内存状态如图 3.10 所示:

然后,执行构造方法中的代码,用从外部接受到的姓名和年龄对成员变量重新赋值。此
时的内存状态如图 3.11 所示:

最后,把刚刚创建的对象赋给引用变量,如图 3.12 所示:

构造方法的一些细节
1).在 Java 的每个类里都至少有一个构造方法,如果程序员没有在一个类里定义构造方
法,系统会自动为这个类产生一个默认的构造方法,这个默认构造方法没有参数,在其方法
体中也没有任何代码,即什么也不做。
下面程序的 Construct 类两种写法完全是一样的效果。
class Construct
{
}
class Construct
{
    public Construct(){}
}
对于第一种写法,类虽然没有声明构造方法,但我们可以用 new Construct()语句来创
Construct 类的实例对象。
由于系统提供的默认构造方法往往不能满足编程者的需求,我们可以自己定义类的构造
方法,来满足我们的需要,一旦编程者为该类定义了构造方法,系统就不再提供默认的构造
方法了。
class Construct
{
    int age;
    public Construct(int x)
    {
        age = x;
    }
}
上面的 Construct 类中定义了一个对成员变量赋初值的构造方法,该构造方法有一个形
式参数,这时系统就不再产生默认的构造方法,我们再编写一个调用 Construct 类的程序。
class TestConstruct
{
    public static void main(String [] args)
    {
        Construct c = new Construct();
    }
}
写好上面的程序,编译器会报错:

错误的原因就是,调用 new Construct()创建 Construct 类的实例对象时,要调用的是
没有参数的那个构造方法,而我们又没有定义无参数的构造方法,但我们定义了一个有参数
的构造方法,系统不再为我们自动生成无参数的构造方法。针对这种情况,我们只要自己定
义构造方法,都需要带上一个无参数的构造方法,否则,就会经常碰到上面这样的错误。
2).思考一下,声明构造方法时,可以使用 private 访问修饰符吗?运行这段程序,看
看有什么结果:
class Person
{
    private Person()
    {
        System.out.println("the constructor 1 is calling!");
    }
}
class TestPerson
{
    public static void main(String[] args)
    {
        Person p1=new Person();
    }
}
程序会报错:

出现这段信息原因是 Person()构造方法是私有的,不可以被外部调用,可见构造方法一般都
public 的,因为它们在对象产生时会被系统自动调用的。

上篇:36.类与对象(二)---面向对象
下篇:38.this引用句柄---面向对象

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

7

主题

2323

回帖

4081

积分

大学生

Rank: 5Rank: 5

金币
635
好评
2
信誉
100
发表于 2020-6-16 07:48:01 | 显示全部楼层  来自 广东
瞅一瞅看一看
回复

使用道具 举报

13

主题

676

回帖

2914

积分

大学生

Rank: 5Rank: 5

金币
626
好评
0
信誉
100

考神

发表于 2020-9-28 18:56:42 来自手机  | 显示全部楼层  来自 山西
真是大佬啊,我完全看不懂…唉我多么希望我也这么厉害
回复

使用道具 举报

44

主题

1494

回帖

4627

积分

大学生

撒野不费

Rank: 5Rank: 5

金币
1760
好评
24
信誉
98

考神MT论坛帅哥MT论坛最佳新人MT论坛新人MT论坛活跃会员

QQ
发表于 2020-10-17 11:28:26 | 显示全部楼层  来自 湖北–恩施
瞅瞅看看
回复

使用道具 举报

0

主题

178

回帖

380

积分

初中生

Rank: 3Rank: 3

金币
174
好评
0
信誉
100
发表于 2021-1-16 20:44:25 | 显示全部楼层  来自 山西
不让感谢,那就只能说:我倒要看看你葫芦里卖的什么药
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表