• 详解Java的对象创建


    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 numberString 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操作符和构造器。构造器是一个特殊的方法,通过调用构造器,我们可以创建并初始化一个对象出来。

    构造器的特点:

    1. 有一个访问修饰符
    2. 构造器的名字和类名相同
    3. 构造器没有返回值
    4. 构造器要和new操作符一起使用
    5. 构造器可以有0个、1个或多个构造器
    6. 一个类中可以有多个构造器

    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;
    }
    

    这个有参构造器非常简单,分别给na参数传值,然后给对象的属性赋值。美中不足的是参数的变量名取得不够“见名知意”,所以我们通常这样写:

    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岁了,家住南极,汪汪汪...
    

    如有错误,还请指正。

  • 相关阅读:
    Python入门
    实现QQ、微信、新浪微博和百度第三方登录(Android Studio)
    Android 微信第三方登录
    Javascript获取随机数
    JavaScript for循环 闭包 【转】
    JavaScript中数组的增删改查
    【网络基础系列一】客户/服务器模型
    jQuery选择器
    局部代码块
    接口中定义变量
  • 原文地址:https://www.cnblogs.com/xingrenguanxue/p/13391253.html
Copyright © 2020-2023  润新知