构造方法
回顾:实例化对象的产生格式:
①类名称 ②对象名称 = ③new ④类名称() ;
下面分析这个格式每一部份的组成:
- ①类名称:任何对象都有其对应的类,因为没有类就不知道对象具备的功能;
- ②对象名称:是一个唯一的标记,表示以后要操作的对象的名称;
- ③new:表示开辟新的堆内存空间;
- ④类名称():构造方法。
可以看出,构造方法是使用关键字new实例化新对象时调用的操作方法,构造方法的定义需要遵守如下原则:
- 方法名称必须与类名称相同;
- 构造方法没有返回值类型声明;
- 每个类中至少存在一个构造方法。
- 如果一个类中没有构造方法,那么将自动生成一个无参的 、什么都不做的构造方法。
无参构造方法
范例:定义一个无参的构造方法
class Person { // 定义一个类,注意类名称每个单词首字母大写
private String name ;
private int age ;
// 构造方法名称与类名称相同,并且没有返回值类型声明
public Person() { // 如果类中不写此定义,系统也会创建一个无参无返回值的方法
System.out.println("new对象时调用这个构造方法") ; // 系统创建的无参构造方法不会有任何功能
}
public void setName(String n) {
name = n ;
}
public void setAge(int a) {
if(a > 0 && a < 120){
age = a ;
} else
age = 0 ;
}
public String getName() {
return name ;
}
public int getAge() {
return age ;
}
public void info() { // 一个普通方法
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per = new Person() ; // new时调用构造方法
per.setName("Dexter") ;
per.setAge(20) ;
per.info() ;
}
}
既然构造方法中没有返回数据,为什么不使用void进行定义呢?
- 类中的组成:属性、普通方法、构造方法
- 属性:对象开辟堆内存时就开辟的内存空间;
- 构造方法:使用关键字new的时候调用的;
public Person() ;
- 普通方法:对象已经实例化完成了(空间开辟了、构造方法执行了)再调用的,可以调用多次。
public void Person() ;
通过二者程序上的区别来区分,而不能根据方法名来区分。
对于类中自动生成的无参构造方法实际上是有一个前提:类中没有定义任何构造方法。
有参构造方法
范例:类中定义一个有参构造方法
// 构造方法名称与类名称相同,并且没有返回值类型声明
// 定义了一个有参构造,默认的无参构造不会在编译时自动生成
public Person(String n , int a) { // 如果类中不写此定义,系统也会创建一个无参无返回值的方法
System.out.println("new时调用这个构造方法") ;
}
修改上一个范例的第5行,编译时可以看到:
可以看到是因为new时调用构造方法Person()时参数不匹配。
范例:调用有参构造方法
class Person { // 定义一个类,注意类名称每个单词首字母大写
private String name ;
private int age ;
// 构造方法名称与类名称相同,并且没有返回值类型声明
// 定义了一个有参构造,默认的无参构造不会在编译时自动生成
public Person(String n , int a) { // 如果类中不写此定义,系统也会创建一个无参无返回值的方法
System.out.println("new时调用这个构造方法") ;
setName("Dexter") ;
setAge(20) ;
}
public void setName(String n) {
name = n ;
}
public void setAge(int a) {
if(a > 0 && a < 120){
age = a ;
} else
age = 0 ;
}
public String getName() {
return name ;
}
public int getAge() {
return age ;
}
public void info() {
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per = new Person("Dexter" , 20) ; // new时调用构造方法
per.info() ;
}
}
通过上面代码,可以看出构造方法的作用:
- 构造方法的调用和对象内存的分配几乎是同步完成的,所以可以利用构造方法设置类中的属性内容,即:构造方法可以为类中的属性进行初始化处理。
- 通过构造方法设置内容可以避免重复的setter方法调用,即可以一次性传完所有内容。
- setter方法除了具有设置内容功能以外,也可以承担修改内容的操作。
范例:通过setter修改内容
上一段范例中第34行之后加上per.setAge(25) ;
- setter方法除了具有设置内容功能以外,也可以承担修改内容的操作。
构造方法的重载
- 构造方法本身也是一种方法,而方法就一定可以进行重载,而构造方法的重载更加简单,因为方法名称就是类名称,我们需要做的就只是实现参数的类型或个数不同这一概念。
范例:构造方法的重载
class Person { // 定义一个类,注意类名称每个单词首字母大写
private String name ;
private int age ;
public Person(String n , int a) {
System.out.println("new时调用这个构造方法") ;
setName("Dexter") ;
setAge(20) ;
}
public Person(String n) {
System.out.println("一个参数的构造方法") ;
setName("Dexter") ;
}
public Person() {
System.out.println("无参数时构造方法") ;
}
public void setName(String n) {
name = n ;
}
public void setAge(int a) {
if(a > 0 && a < 120){
age = a ;
} else
age = 0 ;
}
public String getName() {
return name ;
}
public int getAge() {
return age ;
}
public void info() {
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per = new Person("Dexter") ; // new时调用构造方法
// per.setName("Dexter") ;
per.setAge(25) ;
per.info() ;
}
}
可以看到这时new调用的是public Person(String n) {}
这个构造方法。
在进行构造方法的重载时要注意定义时的代码结构:
- 若干个构造方法按照参数的个数采用一定顺序(升降序)排列。
在进行类定义时按照以下结构:
- 第一部分:写属性
- 第二部分:写构造方法
- 第三部分:写普通方法
匿名对象
既然构造方法可以传递属性的内容,为了使用方便往往会使用匿名对象完成
- 范例:匿名对象
对于Person per = new Person("Dexter" , 20) ;
,per
并不是真正的内容,new Person("Dexter" , 20)
才是。就是说per对象并没有被使用到。
Person per = new Person("Dexter" , 20) ; // new时调用构造方法
per.info() ;
可以用
new Person("Dexter" , 20).info() ;
直接取代。
匿名对象存在的问题:
- 匿名对象不会有任何栈空间所指向,所以使用一次之后就将成为垃圾内存空间。
匿名对象的使用是一个经验问题,先从有名对象开始慢慢积累经验。
总结
- 构造方法每个类中至少有一个;
- 不人为定义时系统会自动创建;
- 构造方法的名称与类名称相同,且无返回值无void;
- 构造方法允许重载,重载时只需要考虑参数数量和类型问题。