类和对象(1)
简单认识类
类是用代码的形式来对一个实体(对象)来进行描述的。
主要用代码描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干啥),描述完成计算机就可以识别类其中的代码从而描述对象。
类的定义格式
在java中定义类时需要用到class关键字,具体语法如下
// 创建类
class ClassName{
field; //成员变量 :成员变量可以不赋值,不赋值时它的默认值为基础值。
method; // 成员方法
}
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。
class WashMachine{
public String brand; // 品牌
public String type; // 型号
public double weight; // 重量
public double length; // 长
public double width; // 宽
public double height; // 高
public String color; // 颜色
public void washClothes(){ // 洗衣服
System.out.println("洗衣功能");
}
public void dryClothes(){ // 脱水
System.out.println("脱水功能");
}
public void setTime(){ // 定时
System.out.println("定时功能");
}
}
采用Java语言将洗衣机类在计算机中定义完成,经过javac编译之后形成.class文件,在JVM的基础上计算机就可以识别了。
注意事项
类名注意采用大驼峰定义
成员前写法统一为public,后面会详细解释
此处写的方法不带 static 关键字. 后面会详细解释
注意事项:
1. 一般一个文件当中只定义一个类(并不代表着一个文件只能定义一个类,它能定义多个类,只是一个文件一个类便于我们去操作,以后基本都是一个文件一个类,这样更简便)
2. main方法所在的类一般要使用public修饰( 并不代表main方法所在的类一定要用public修饰,其类也可以不用public修饰,但一般情况我们还是用public修饰,只是需要知道main所在类也可以不用public修饰这个点而已)
3. public修饰的类必须要和文件名相同
4. 不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改(给同学演示)。
类的实例化
定义了一个类,就相当于在计算机中定义了一种新的类型。与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:PetDog类和Student类。它们都是类(一种新定义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。
自定义类型都是引用类型,创建的变量为引用变量。
用定义好的类创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。
注意事项
new 关键字用于创建一个对象的实例.
使用 . 来访问对象中的成员变量和成员方法.
同一个类可以创建多个实例.
用类创建的对象其中的成员变量分布在堆区,成员方法存储在方法区(使用该方法时会在栈区分配空间)
类和对象的说明
1. 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
2. 类是一种自定义的类型,可以用来定义变量.
3. 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量
4. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
this引用
对于一个类去创建多个对象,每个对象都用了类中的成员方法,那么该怎么确定其中的每个方法能对应该对应的对象。这时就出现了this引用。
其实对于类中的普通成员方法,第一个参数其实是该类的类型创建的引用变量this,只是它被隐藏了。对于静态成员方法(类方法)不含this。
对于普通成员方法中的成员变量,前面也自带this.,只是也被隐藏了 。
如下,为正常情况下的,this都被隐藏了
这才是this没被隐藏的真正的情况:
这里还出现了一个问题,当形参名和成员变量名字相同怎么办。
因为形参是局部变量,在Java中局部变量和全局变量名字相同时,优先选择局部变量。
所以此时就是单纯局部变量给局部变量赋值,不影响成员变量,所以导致结果错误。
public class Date {
public int year;
public int month;
public int day;
public void setDate(int year,int month,int day) {
year = year;
month = month ;
day = day;
}
public void print() {
System.out.println("year: "+year + " month : " +month +" day: "+day);
}
public static void main(String[] args) {
Date date2 = new Date();
date2.setDate(1989,11,11);
date2.print();
//此时单纯局部变量给局部变量赋值,成员变量没变依旧是基础值
}
}
结果如下,显示错误。
如果要正确的结果我们应该这样写代码。
public class Date {
public int year;
public int month;
public int day;
public void setDate(int year,int month,int day) {
this.year = year;
this.month = month ;
this.day = day;
}
public void print() {
System.out.println("year: "+year + " month : " +month +" day: "+day);
}
public static void main(String[] args) {
Date date2 = new Date();
date2.setDate(1989,11,11);
date2.print();
//此时局部变量和成员变量名字相同,但在year,month,day前面都加了this.,
所以在this后面的这三个变量被识别为成员变量,从而达到正常想要的效果
}
}
所以我们得出一个结论,成员方法中的成员变量我们都要在前面加个this.,即使不加this也是对的,我们也要加它,这样的写法能使其代码更加严谨。
对象的构造及初始化
初始化分为三种:默认初始化,就地初始化,通过构造方法进行的初始化
默认初始化
就是创建对象后不进行赋值,它们的值直接为其默认的基础值。
就地初始化
在声明成员变量时,就直接给出了初始值。
public class Date {
public int year = 1900;
public int month = 1;
public int day = 1;
public Date(){
}
public Date(int year, int month, int day) {
}
public static void main(String[] args) {
Date d1 = new Date(2021,6,9);
Date d2 = new Date();
}
}
构造方法
构造方法一般都是对普通成员变量进行初始化,初始化的是与对象相关的实例。一般不对静态成员变量初始化。
对象的产生需要两个条件
1. 为对象分配内存
2.调用合适的构造方法
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,没有返回值,void都不能填。在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
执行构造方法的时候是在创建对象的同时执行的
在给对象分配好内存的同时执行了Date构造方法,然后就创建好了对象。所以说整个对象的构造方法只能调用一次,就是在创建的同时调用的构造方法。
public class Date {
public int year;
public int month;
public int day;
// 构造方法:
// 名字与类名相同,没有返回值类型,设置为void也不行
// 一般情况下使用public修饰
// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
public Date(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("Date(int,int,int)方法被调用了");
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
// 此处创建了一个Date类型的对象,并没有显式调用构造方法
Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
d.printDate(); // 2021-6-9
}
}
注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。
特性:
1. 名字必须与类名相同
2. 没有返回值类型,设置为void也不行
3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
如果用户没有定义构造方法,编译器会生成一份默认的构造方法,该默认构造方法一定是无参的,方法内部不含任何代码,只有一个空语句。
注意:一旦用户定义了一个构造方法,编译器则不再生成默认的。
如果有多个构造方法(重载),此时可以使用this的另一个功能。(可以在一个构造方法中通过this使用另一个构造方法)
注意正常情况下一个构造方法内部不能使用另一个构造方法,但通过this我们可以实现该功能。
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复
// 此处可以在无参构造方法中通过this调用带有三个参数的构造方法
// 但是this(1900,1,1);必须是构造方法中第一条语句
public Date(){
//System.out.println(year); 注释取消掉,编译会失败
this(1900, 1, 1);
//this.year = 1900;
//this.month = 1;
//this.day = 1;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
}
注意this该功能要使用必须在构造方法第一条语句上才能使用。
还需注意其不能陷入死循环,如自引用和以下代码,其都会形成一个环从而陷入死循环,系统报错。
绝大多数情况下构造方法使用public来修饰,特殊场景下会被private修饰(后序讲单例模式时会遇到)