1. 前言
在《还不分明怎么面向对象?》和《面向对象再探索》两篇文章中,都介绍了对于面向对象程序设计的概念和特点。其中也波及到了许多代码,比方:
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 岁了,家住南极,汪汪汪...
如有谬误,还请斧正。