一、构造方法Constructor
1. 构造方法的概念
构造方法是类中特殊的方法,通过调用构造方法来完成对象的创建,以及对象属性的初始化操作。
2. 构造方法的定义
【修饰符列表】构造方法名(形式参数列表){ 构造方法体; }
- 构造方法名和类名一致
- 构造方法用来创建对象,以及完成属性初始化操作
- 构造方法返回值类型不需要写,连void也不能写
- 构造方法的返回值类型实际上是当前类的类型
- 一个类中可以定义多个构造方法,这些构造方法构成方法重载
注意:当一个类没有显示的定义任何构造方法时,系统会默认提供无参构造方法(缺省构造器),当显示的定义构造方法之后,系统则不再提供无参构造方法了。所以,建议手动将无参构造方法写上,因为无参构造方法使用的频率较高。
代码如下:
public class Constructor {
public static void main(String[] args) {
Date d1=new Date() ;
d1.show();
Date d2=new Date(2020);
d2.show();
Date d3=new Date(2020,11);
d3.show();
Date d4=new Date(2020,11,26);
d4.show();
}
}
class Date{
int year;
int month;
int day;
Date(){
System.out.println("无参构造方法被调用!");
}
Date(int year){
this.year=year;
System.out.println("带有参数year的构造方法被调用!");
}
Date(int year,int month){
this.year=year;
this.month=month;
System.out.println("带有参数year,month的构造方法被调用!");
}
Date(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
System.out.println("有参构造被调用了!");
}
public void show(){
System.out.println("今天的日期是:"+year+":"+month+":"+day);
}
}
运行结果:
通过该段代码,我们可以看出一个类中可以定义多个构造方法,构造方法是支持重载机制的,具体调用哪个构造方法,取决于调用的时候传递的实际参数列表符合哪个构造方法。
构造方法虽然在返回值类型方面不写任何类型,但是它执行结束之后实际上会返回该对象在堆内存当中的内存地址,这个时候可以定义变量是接收对象的内存地址,这个变量就是我们所说的“引用”。以上程序d1,d2,d3,d4都是引用,我们可以通过该引用访问对象的内存了。
上述代码我们可以看出,没有给属性赋值,会默认输出0,这是因为构造函数中没有给属性赋值,系统会赋默认值。
类加载的时候不会初始化实例变量的空间,都是在构造方法执行的时候才会进行赋值操作。这也是为什么实例变量不能采用类名去访问的原因。
给成员变量赋值的两种方式:
1. get\set方法
2. 构造方法
当我们学习到Java中封装特性的时候,对需要保护的属性使用private关键字进行修饰,然后给这个私有的属性对外提供公开的get\set方法,其中set方法用来修改属性的值,get方法用来读取属性的值。那么有人可能就会有这种疑问:构造方法中已经给属性赋值了,为什么还需要提供get\set方法。
我们要知道,这是两个完全不同的时刻,构造方法中给属性赋值是在创建对象的时候完成的,当对象创建完毕之后,属性可能还是会被修改的,后期要想修改属性的值,这个时候就必须调用set方法了。
二、空指针异常
代码:
public class Nullpointer {
public static void main(String[] args) {
balloon a =new balloon("红色","氢气");
a.show();
//置空引用!
a=null;
//发生空指针异常
a.show();
}
}
class balloon{
String color;
String gas;
balloon(){
}
balloon(String color,String gas){
this.color=color;
this.gas=gas;
}
public void show(){
System.out.println("该气球的颜色是"+color+"气体是"+gas);
}
}
运行结果:
当一个空的引用去访问实例变量时,会出现java.lang.NullPointerException空指针异常错误。这是因为当ball=null执行之后表示“引用balloon”不再保存java对象的内存地址,换句话说通过balloon引用无法找到堆内存当中的java对象了,这种情况下就会发生空指针异常现象。
三、方法调用时参数的传递问题
调用参数传递给方法,这个过程就是赋值的过程,也就是说参数传递和“赋值规则”完全相同。
代码:
public class Transitive {
public static void main(String[] args) {
//基本数据类型的赋值
int a=100;
int b=a;
//引用数据类型的赋值
Bird b1=new Bird("鹦鹉");
Bird b2=b1;
//输出结果
System.out.println("b="+b);
System.out.println("b1=" + b1);
System.out.println("b2="+b2);
}
}
class Bird{
String name;
Bird(String name){
this.name=name;
}
}
运行结果:
内存变化图:
通过内存图我们可以看出“赋值”运算的时候实际上和变量的数据类型无关,无论是基本数据类型还是引用数据类型,一律都是讲变量中保存的“值”复制一份,然后将复制的这个“值”赋上去。他们的区别在于,基本数据类型和堆内存当中的对象无关,如果是引用数据类型由于传递的这个值是java对象的内存地址,所以会导致两个引用指向同一个堆内存中的java对象。也就是说基本数据类型传递的是数值,引用数据类型传递的是地址值。