1. 前言
在《还不清楚怎样面向对象?》 https://mp.weixin.qq.com/s/_G6RjwthUybz5KsDsLo7kQ 和《面向对象再探究》 https://mp.weixin.qq.com/s/NQK3aYXUh3eOwmwmP_VluQ 两篇文章中, 都介绍了关于面向对象程序设计的概念和特点. 其中也涉及到了许多代码, 比如:
Dog dog = new Dog();
这篇文章就主要来谈谈创建对象时的具体操作.
2. 引入例子
下面是一个 Dog 类:
- /**
- * @author Xing Xiaoguan (xingrenguanxue)
- */
- public class Dog {
- private String name;
- private int age;
- private String address;
- public void say() {
- System.out.println("我叫" + name + ", 今年" + age + "岁了, 家住" + address + ", 汪汪汪...");
- }
- //getters 和 setters
- }
下面是一个 Test 类, 创建了一个 Dog 对象, 然后进行相关操作:
- public class Test {
- public static void main(String[] args) {
- Dog dog = new Dog();
- dog.setName("哮天犬");
- dog.setAge(1);
- dog.setAddress("光明小区")
- dog.say();
- }
- }
输出:
我叫小黑, 今年 1 岁了, 家住光明小区, 汪汪汪...
3. 对象和对象变量
对象是根据类创造出来的, 我们使用的是具体的对象, 而不是类. 要想使用对象, 那对象必须得先被创建出来才行. 下面一行代码是创建对象的语句:
Dog dog = new Dog();
我们将其分成三部分来看:
(1)new: 如果你想创建一个对象, 那么必须使用 new 操作符.
(2)Dog(): 这是一个构造器, 构造器是一个特殊的方法. 通过调用该构造器, 我们可以创建并初始化一个对象出来.
new Dog() 连起来就能正确地创建出一个对象了. 但是我们创造出来的对象并不只会使用一次, 而会使用许多次, 所以我们需要给该对象 "取一个名字", 保证它 "随叫随到". 这就需要第三部分了:
(3)Dog dog: 声明一个 Dog 类型的, 名为 dog 的变量. 它就类似于 int number, 声明一个 int 类型的 number 变量.
然后我们使用 = 进行赋值 (引用), 便给创建出的对象 "取一个名字" 叫 dog, 以后可以称它为 dog 对象.
这里可能会出现一个误区, 认为: Dog dog 部分便能创建出一个 dog 对象, 这是错误的. 应当明确: dog 从头到尾都只是一个变量而已. 这个变量和使用 int number,String str 等方式声明的变量, 除了类型不同之外并无差别.
真正创建出对象的是 new Dog() 部分.
下面解释一下 "取一个名字" 是什么意思.
在 Java 中, 对象变量中存储的并不是对象, 真正的变量在内存的某个地方躺着呢. 该变量记录的是对象在内存中的位置, 我们有了对象变量, 就有了对象的位置, 有了位置, 就能找到真正的对象.
看下面的代码:
- public class Test {
- public static void main(String[] args) {
- Dog dog = new Dog();// 创建出一个 dog 对象
- System.out.println(dog);// 打印 dog
- }
- }
打印结果: basic.Dog@1b6d3586
1b6d3586 便是 dog 对象在内存中的地址.
4. 构造器
前面提到, 创建一个对象的关键在于使用 new 操作符和构造器. 构造器是一个特殊的方法, 通过调用构造器, 我们可以创建并初始化一个对象出来.
构造器的特点:
有一个访问修饰符
构造器的名字和类名相同
构造器没有返回值
构造器要和 new 操作符一起使用
构造器可以有 0 个, 1 个或多个构造器
一个类中可以有多个构造器
4.1. 无参构造器
即没有参数的构造器, 如 Dog(). 无参构造器是 Java 默认的构造器, 如果你在编写类时没有写构造器, 那么 Java 会在类中默认提供一个无参构造器.
在 Dog 类中并没有写构造器, Dog 类默认拥有下面的无参构造器:
public Dog() {
}
4.2. 有参构造器
有参构造器, 即有参数的构造器. 例如:
- public Dog(String n, int a, String addr) {
- name = n;
- age = a;
- address = addr;
- }
这个有参构造器非常简单, 分别给 n,a 参数传值, 然后给对象的属性赋值. 美中不足的是参数的变量名取得不够 "见名知意", 所以我们通常这样写:
- public Dog(String name, int age, String address) {
- this.name = name;
- this.age = age;
- this.address = address;
- }
参数的名字和对象的成员变量名一样, 这样, 参数的意义就很清晰了. 在赋值的时候, 使用 this 关键字区分二者, 因为 this 代表我们所创建的对象, this.name 即对象的成员变量.
有了有参构造器, 我们就可以在创建对象时初始化对象的属性, 比如:
- public static void main(String[] args) {
- Dog dog = new Dog("小狗有参", 1, "地球");
- dog.say();
- }
输出:
我叫小狗有参, 今年 1 岁了, 家住地球, 汪汪汪...
4.3. 多个构造器的使用
先了解一个概念 -- 重载 (overloading). 重载是指在一个类中, 有几个方法的方法名字相同, 而参数不同. 返回值类型可以相同也可以不相同. 注意: 每个重载的方法的参数列表必须独一无二.
注意: 参数列表的独一无二是指参数列表的类型的独一无二.
千万不要以为 func(String name) 和 func(String address) 这两个方法的参数列表是不同的. 它俩应该这样看: func(String) 和 func(String), 所以这俩方法是相同的.
下图是 String 类中的部分方法的重载情况, 可从中体会参数列表的独一无二:
为什么要求参数列表必须独一无二呢?
这就得介绍另一个概念 -- 方法的签名. 方法的签名是指要完整地描述一个方法, 需要指出方法名和参数类型. 注意: 方法的返回类型不是签名的一部分.
所以在 Java 中, 方法名和参数列表能确定一个方法. 不存在方法名和参数列表相同, 而返回类型不同的方法们.
而重载要求的是方法名相同, 参数列表不同. 从方法的签名角度来看, 重载方法之间本就是不同的方法.
由于重载的存在, 我们可以在一个类中编写多个参数列表不同的构造器, 使该类具有多种创建对象的形式. 比如:
- public class Dog {
- private String name;
- private int age;
- private String address;
- public Dog() {// 无参构造器, 有其他构造器存在, 系统不会默认提供
- }
- public Dog(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public Dog(String name, int age, String address) {
- this.name = name;
- this.age = age;
- this.address = address;
- }
- public void say() {
- System.out.println("我叫" + name + ", 今年" + age + "岁了, 家住" + address + ", 汪汪汪...");
- }
- //getters 和 setters
- }
写了三种构造器, 便有三种创建对象的方式:
- Dog dog = new Dog("小狗", 1, "太阳系");
- Dog dog1 = new Dog("小狗 1", 2);
- Dog dog2 = new Dog();
编译器会根据我们提供的参数匹配到合适的构造器.
注意: 无参构造器只有在我们没有编写任何构造器时, 系统才会默认提供. 所以当一个类中有其他构造器时, 如果我们需要无参构造器, 那么必须手动编写出来, 系统不会默认提供.
4.4. 构造器之间的关系
在类中, 一个构造器可以调用另一个构造器. 如下例:
- /**
- * @author Xing Xiaoguan (xingrenguanxue)
- */
- public class Dog {
- private String name;
- private int age;
- private String address;
- public Dog(String name, int age) {
- this(name, age, "银河系");// 调用另一个构造器
- System.out.println("两个参数的构造器");
- }
- public Dog(String name, int age, String address) {
- this.name = name;
- this.age = age;
- this.address = address;
- System.out.println("三个参数的构造器");
- }
- public void say() {
- System.out.println("我叫" + name + ", 今年" + age + "岁了, 家住" + address + ", 汪汪汪...");
- }
- //getters and setters...
- }
使用 Dog(String, int) 创建对象:
- public class Test {
- public static void main(String[] args) {
- Dog dog = new Dog("小狗有参", 1);
- dog.say();
- }
- }
输出:
三个参数的构造器
两个参数的构造器
我叫小狗有参, 今年 1 岁了, 家住银河系, 汪汪汪...
我们在构造器的第一行语句中使用 this(...) 来调用另一个构造器. 注意: 一定要是第一行语句.
5. 对象属性的初始化
所谓初始化, 就是我们在创建对象同时设置对象的属性值.
5.1. 默认的属性值
当我们创建对象时如果不显式地设置属性值, 对象的属性值会被初始化为默认值.
数值的默认值为 0, 布尔值的默认值为 false, 对象引用的默认值为 null.
如下例中的 Dog 类的属性值:
- public class Dog {
- private String name;
- private int age;
- private String address;
- public void say() {
- System.out.println("我叫" + name + ", 今年" + age + "岁了, 家住" + address + ", 汪汪汪...");
- }
- }
创建对象:
- public static void main(String[] args) {
- Dog dog = new Dog();
- dog.say();
- }
输出:
我叫 null, 今年 0 岁了, 家住 null, 汪汪汪...
5.2. 直接设置属性值
我们可以在类中直接设置类的属性值, 这样一来, 根据该类创建的对象的属性值就确定了.
如下例中 Dog 类的属性值:
- public class Dog {
- private String name = "小黑";
- private int age = 2;
- private String address = "太阳系";
- public void say() {
- System.out.println("我叫" + name + ", 今年" + age + "岁了, 家住" + address + ", 汪汪汪...");
- }
- }
这时再创建对象:
- public static void main(String[] args) {
- Dog dog = new Dog();
- dog.say();
- }
输出:
我叫小黑, 今年 2 岁了, 家住太阳系, 汪汪汪...
5.3. 使用构造器初始化
(一) 当构造器中没有显式地设置对象的属性值时, 这些属性值会被初始化为默认值. 如下面的无参构造器:
public Dog() {
}
创建对象:
- public static void main(String[] args) {
- Dog dog = new Dog();
- dog.say();
- }
输出:
我叫 null, 今年 0 岁了, 家住 null, 汪汪汪...
(二) 可以在无参构造器的方法体中初始化属性值:
- public Dog() {
- name = "小黑";
- age = 2;
- address = "宇宙";
- }
创建对象:
- public static void main(String[] args) {
- Dog dog = new Dog();
- dog.say();
- }
输出:
我叫小黑, 今年 2 岁了, 家住宇宙, 汪汪汪...
(三) 也可以使用有参构造器, 对象会按照我们传入的变量初始化属性值:
- public Dog(String name, int age, String address) {
- this.name = name;
- this.age = age;
- this.address = address;
- }
创建对象:
- public static void main(String[] args) {
- Dog dog = new Dog("小黑", 3, "南极");
- dog.say();
- }
输出:
我叫小黑, 今年 3 岁了, 家住南极, 汪汪汪...
如有错误, 还请指正.
来源: https://www.cnblogs.com/xingrenguanxue/p/13391253.html