关于Java类中的构造方法:
- 构造方法又称为构造函数/构造器/Constructor
- 构造方法语法结构:
[修饰符列表] 构造方法名 (形参列表){
构造方法体;
} - 普通方法语法结构:
[修饰符列表] 返回值类型 方法名(形参列表){
方法体;
} - 对于构造方法来说,“返回值类型”,不需要指定,并且也不能写void,如果写上void,这个方法就变成了普通方法
- 对于构造方法来说,构造方法的方法名必须和类名保持一致
- 构造方法的作用?
构造方法存在的意义,是通过构造方法的调用,可以创建对象 - 构造方法应该怎么调用?
普通方法调用:
类名.方法名(实参列表)修饰符列表有static关键字的
引用.方法名(实参列表)修饰符列表没有static关键字的
构造方法的调用:
new 构造方法名(实参列表) - 构造方法在调用后有返回值吗?
每一个构造方法在执行结束后都有返回值,但是这个“return 值;”语句不需要写,构造方法结束的时候java程序自动返回值。并且返回值类型是构造方法所在类的类型,由于构造方法的返回值类型是类本身,所以返回值类型不需要写 - 当一个类中没有定义任何构造方法的时候,系统会默认给该类构造一个无参数的构造方法,这个构造方法被称为“缺省构造器”
- 当一个类显示的将构造方法定义出来了,那么系统将不再会给这个类提供缺省构造器,建议在实际开发中,手动为当前类提供无参数的构造方法,因为无参数构造方法太常用了。
- 构造方法支持重载机制,在一个类当中编写多个构造方法,这多个构造方法显然构成方法重载
public class ConstructorTest01 {
public static void main(String[] args) {
//创建一个User对象
//调用User类的构造方法来完成对象的创建
//记住只要是标识符后面带括号的,就一定是方法,这里new后面的User不是类名而是构造方法名!!
//而等号左边的User 是一个引用数据类型,指的是通过new来调用User()构造方法,通过User类型的u1变量来存储这个对象的内存地址
//以下程序创建了4个对象,只要构造函数调用就会创建对象,并且一定是在“堆内存”当中开辟空间
User u1=new User();
User u2=new User(10);
User u3=new User("zhangsan");
User u4=new User(10,"zhangsan");
//调用带有static的方法
ConstructorTest01.doSome();
doSome();
//调用不带static的方法
//doOther方法存在于ConstructorTest01类中,所以需要创建ConstructorTest01对象
//创建ConstructorTest01对象,调用无参数构造方法
ConstructorTest01 t=new ConstructorTest01();//没有任何构造方法会默认有缺省构造器
t.doOther();
}
public static void doSome() {
System.out.println("do some!");
}
public void doOther() {
System.out.println("do other!");
}
}
public class User {
//无参数的构造方法
public User() {
System.out.println("User's Default Construction Invoke!");
}
//有参数的构造方法
public User(int i) {
System.out.println("带有int类型参数的构造器");
}
//有参数的构造方法
public User(String name) {
System.out.println("带有String类型参数的构造器");
}
//有参数的构造方法
public User(int i,String name) {
System.out.println("带有int,String类型参数的构造器");
}
}
构造方法的作用:
- 创建对象
- 给实例变量赋值
成员变量之实例变量,属于对象级别的变量,这种变量必须现有对象才能实例变量。
实例变量没有手动赋值的时候,系统默认赋值,那么这个系统默认赋值是在什么时候完成的呢?
是在类加载的时候吗?
不是,因为类加载的时候只加载了代码片段,还没来得及创建对象,所以此时实例变量并没有初始化
实际上,实例变量的内存空间是在构造方法执行过程当中完成开辟的。完成初始化的。系统在默认赋值的时候,也是在构造方法执行过程当中完成的赋值。
实例变量默认值
byte short int long 0
float double 0.0
boolean false
char \u0000
引用数据类型 null
- 实例变量是存储在JVM堆内存java对象内部
对象和引用的概念:
- 对象:目前在使用new运算符在堆内存中开辟的内存空间称为对象
- 引用:是一个变量,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了堆内存当中的对象。
- 所有访问实例相关的数据,都需要通过“引用.”的方式访问,因为只有通过引用才能找到对象
- 只有一个空的引用,访问对象的实例相关的数据会出现空指针异常
class Student{
Computer com; //com是一个引用【实例变量】
public static void doSome(){
Computer cc; //cc是一个引用【局部变量】
}
}
public class ConstructorTest02{
public static void main(String[] args){
//创建对象
Account act1 = new Account();
System.out.println("账号:"+act1.getAccount());//null
System.out.println("余额:"+act1.getBalance());//0.0
Account act2=new Account("110");
System.out.println("账号:"+act2.getActno());//110
System.out.println("余额:"+act2.getBalance());//0.0
Account act3=new Account(10000.0);
System.out.println("账号:"+act3.getActno());//null
System.out.println("余额:"+act3.getBalance());//10000.0
Account act4=new Account("act-001",10000.0);
System.out.println("账号:"+act4.getActno());//act-001
System.out.println("余额:"+act4.getBalance());//10000.0
//通过调用不同的构造方法,传递不同的实参,在读取时,构造方法就会为实例变量赋值。相当于更改默认值
}
}
//账户类
public class Account {
//账号
private String actno;
//余额
private double balance;
//无参数构造器
public Account() {
//初始化实例变量的内存空间
//actno=null;
//balance=0.0;
}
public Account(String s) {
actno = s;
}
public Account(double d) {
balance = d;
}
public Account(String s, double d) {
actno = s;
balance = d;
}
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno = actno;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
Java语言中,方法调用的时候涉及到参数传递的问题
参数传递实际上传递的是变量中保存的具体值。
int i =10;
add(i); 等同于add(10);
public class Test01 {
public static void main(String[] args) {
int i=10;
add(i);//11 add方法调用的时候,传递的实际上只是10这个字面值
System.out.println("main -->"+i);//10
}
public static void add(int i) {
i++;
System.out.println("add -->"+i);//11
}
}
public class Test02 {
public static void main(String[] args) {
//通过调用有参数的构造方法来,创建一个User对象,并且给实例变量赋值。
User u=new User(20);
//传递的是什么?
//传递的是main方法中u引用这个变量中保存的值,是一个内存地址。
add(u);
System.out.println("main -->"+u.age);//访问的是main方法中这个u引用的指向对象中实例变量age属性
//由于在前面代码中,传递给add方法中,指向了同一个内存地址,虽然此时add方法执行结束后弹栈,但是在堆内存中
//所做的对User对象实例变量的更改仍然保留。所以,在读取main方法中u引用指向的同一内存地址,也会受到影响。
//始终牢牢记住,java中参数的传递都是变量中保存的“值”,无论它是字面值还是一个java对象的内存地址。
//按照代码执行顺序,一步一步画图,理解本质的东西。
//同时,局部变量本身也是有它自己的内存地址的,不要把它肚子中保存的内存地址给弄混淆。传递的是肚子里的“值”。
}
public static void add(User u) {
u.age++;
System.out.println("add -->"+u.age);//输出肯定是21
}
}
class User{
//实例变量age
int age;
//需要传递参数的构造方法
public User(int i) {
age=i;
}
}
最终结论:
方法在调用的时候,涉及到参数传递的问题,传递的时候,java只遵循一种语法机制:
那就是将变量中保存的哪个“值”给传过去了,只不过有时候这个值是字面值10,有的时候,这个值它是另外一个堆内存Java对象的内存地址0x1234。