类的定义
类就是对一个实体的属性功能进行描述
类的定义格式
首先要用到class关键字;
其次,类名采用大驼峰形式例如Dog ClassName Student……
最后,类中包含该类的属性,即成员变量;以及该类的功能,即成员方法
例如:Dog类
public class Dog {
//成员变量
public String name;
public int age;
//成员方法
public void bark(){
System.out.println(name+" 正在汪汪叫");
}
public void eat(){
System.out.println(name+" 正在吃饭");
}
}
注意
1.一般,一个文件中只定义一个类
2.main方法所在的类一般要public修饰
3.public修饰的类一般要和文件名相同
4.当一个java文件中只有一个类时,修改Java文件名的同时就可以修改了类名,但当有多个类时,修改Java文件名的同时无法同时修改类名。
类的实例化
什么是实例化
用类创建对象的过程就是实例化
在main方法中创建了dog
1.new关键字用于创建一个对象的实例
2.使用 . 来访问对象中的属性和方法
注意
1.对于Dog dog=new Dog(); Dog是一个类,是用户自定义类型 而dog是main方法中的局部变量,它的内存是在栈上,它存放了一个地址,这个地址指向堆上的一块空间,这块空间是通过new关键字开辟的,用来存放Dog类实例化出的一个对象。
this引用
什么是this引用
this引用指向了当前对象(即用new实例化出的对象)
this引用指向成员变量
在成员方法中对所有成员变量的操作都是通过this引用完成的
class Date{
public int year;
public int month;
public int day;
public void setDate(int y,int m,int d){
this.year=y;
this.month=m;
this.day=d;
}
}
public class Test1 {
public static void main(String[] args) {
Date date=new Date();
date.setDate(1998,12,22);
System.out.println(date.year);
System.out.println(date.month);
System.out.println(date.day);
}
}
this引用调用成员方法
class Date{
public int year;
public int month;
public int day;
public void setDate(int y,int m,int d){
year=y;
month=m;
day=d;
this.print();//这就是调用成员方法,此时在main方法中没必要再打印
}
public void print(){
System.out.println(this.year);
System.out.println(this.month);
System.out.println(this.day);
}
}
public class Test1 {
public static void main(String[] args) {
Date date=new Date();
date.setDate(1998,12,22);
}
}
为什么要有this引用
当成员方法中的形参名不小心与成员变量名相同时
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;
this.print();
}
public void print(){
System.out.println(this.year);
System.out.println(this.month);
System.out.println(this.day);
}
}
public class Test1 {
public static void main(String[] args) {
Date date=new Date();
date.setDate(1998,12,22);
}
}
这时输出的是0 0 0
因为year=year不知道到底是谁给谁赋值
所以应该
注意
1.this只能在成员方法中使用
2.this是成员方法中的第一个隐藏参数,编译器会自动传递,在成员方法执行时,编译器会自动将调用该成员方法的对象的引用传递给该成员方法,this就负责接收这个引用
3.编译时,编译器会在所有没加this.的成员变量前自动添加上this.
public void print(){
System.out.println(year);
System.out.println(month);
System.out.println(day);
}
上面的这个就等价于:
public void print(Date this){
System.out.println(this.year);
System.out.println(this.month);
System.out.println(this.day);
对象的构造及初始化
如何初始化对象
刚刚我们写了一个date类,通过自己写的setDate方法对对象进行了初始化,但这样很麻烦,每次新建一个类就得调用方法
构造方法
为了可以在实例化对象的同时对对象进行初始化,我们引入构造方法的概念
什么是构造方法
构造方法时一个特殊的成员方法,名字必须与类名相同,无任何返回值,void也不可以加。
会在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次
默认的构造方法
这是系统会自动添加的构造方法,无任何参数
构造方法的作用
只负责对对象进行初始化,并不负责给对象开辟空间
那么默认的初始值是什么呢?
对于整型,初始值为0
对于char,初始值为'\u0000'
对于float,是0.0f
对于double,是0.0
对于Boolean,是false
对于引用类型,是null。
构造方法的重载
要想在实例化对象时就给对象赋想要的值,我们就需要自己写一个构造方法,也就是方法的重载,之前讲过,重载就是方法名相同,返回值和参数列表可以不同
但要是写一个构造方法的重载,就不能加任何参数了
这就是自己写的构造方法,那如何实例化对象?如下
date1为什么会报错?
因为我们自己写了一个带参数的构造方法,系统就不会再提供不带参数的构造方法,所以括号里不传参就会报错。
date2就是调用了我们自己写的构造方法,就不会报错
那怎么让date1也不报错?同时写俩个构造方法,一个带参数,一个不带
此时就不会报错
this调用构造方法
这个语法只能是在构造方法中。也就是说,在构造方法中,可以用this调用其他构造方法
这就是在无参的构造方法中调用了有参的构造方法
注意:
1.不要用 . 来调用,直接就是this加括号
2.此调用语句只能出现在构造方法的第一条语句,因为只有执行完一个构造方法了,对象才真正生成,才能执行其他任务
3.不能形成环,如下
static成员
对于一个学生类,他们可以在一个班级,那么班级这个成员变量就可以被设置为static,
static修饰成员变量
在Java中,被static修饰的成员变量叫做静态成员,也叫做类成员,顾名思义,它不属于某个具体的对象,而是所有对象所共享的,它是专属于这个类的。
被static修饰的成员变量被存储在方法区,而不是堆上
举例
如上,通过student1给classroom赋值后,可以直接用student2来访问classroom。这是为什么呢?这就要看看static修饰后的本质了
本质
通过调试,发现classroom不属于任何一个对象,而且编译器提供的构造函数中没有classroom这个选项
它实际上是类的属性,不存储在某个对象的空间中
如何访问被static修饰的成员变量
1.可以用对象来访问
2.可以直接用类来访问
3.因为可以用对象来访问,所以可以在构造方法或普通成员方法中用this引用来访问静态变量
4.更推荐使用类名来访问它
如果这个静态变量的访问权限是private,那如何对他访问呢?
这时就要引入静态成员方法了
statiic修饰成员方法
被static修饰的成员方法是静态成员方法,是类的方法,不是某个对象所特有,
注意
1.在静态方法中不能调用非静态成员变量或非静态成员方法,this也不能在静态成员方法中出现,但非静态成员方法可以调用静态成员方法
这是错误的,因为this引用是依赖具体对象的,而静态方法不依赖对象,它的参数中就没有默认的this,所以不能使用this
2.静态方法无法重写,不能来实现多态,这一点会在多态里面讲
代码块
分类
普通代码块
用{}定义的,放在方法内部的代码块
静态代码块
用static{}定义的,一般用于初始化静态成员变量
特点:
1.它在整个类当中只执行一次,不管生成几个对象
虽然创建了三个对象,但只执行了一次静态代码块
2.它是在类加载的时候就执行
虽然没有创建任何变量,但在main方法中引用了Student类,所以静态代码块也执行了
构造代码块/实例代码块
定义在类中,方法外的代码块,一般用于初始化实例成员变量
特点:
1.它是在创建对象的时候执行,有几个对象就执行几次
执行顺序
会发现,先执行静态代码块,再执行构造代码块,最后执行构造方法,这个大顺序不会被我们所写的代码的顺序影响,即使将构造方法写到静态代码块的上方,它也是最后执行
但要是有俩个同样的代码块,则按先后顺序执行,如下
结果就是按顺序执行,最终班级是1003
实际上,在编译时,会将同类型的代码块编译成一个:
对象的打印
到目前,我们想打印对象,要自己写一个show方法,每次打印都要调用它
那能否不写show方法呢?
重写toString方法
这是直接打印时出现的结果:包名.类名.哈希值 这是怎么出现的?我们来看看源码
最后一张就是追根溯源到了最终的toString方法,它的返回值是String
那要想默认打印出对象的各个属性,就要重写toString方法
这就是打印出来的结果,再极端一点:
所以说,当你重写了toString方法后,就不再调用系统已有的方法了
什么是重写
简单来说就是不改变方法名,参数和返回值,只改变内部的实行方式
这会在多态,动态绑定里面讲到