本文已参与「新人创作礼」活动,一起开启掘金创作之路。
类: 类描述的是一类对象的行为和状态。 对象: 是类的一个实例,有相应的状态和行为。例如,一辆车是一个对象,它的状态有:品牌、颜色、型号、价格;行为有:行驶、加油、熄火、加速等。
一、面向过程和面向对象
- 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
- 我们最开始接触的C语言是面向过程的语言,本篇介绍的语言是面向对象的语言。面向对象是一种解决问题的思想,主要依靠对象之间的交互完成工作。
1、面向过程
==注重完成事情的过程==,缺少中间的每一个环节都不行。 用洗衣服进行举例,是把需要解决的问题拆分成一个一个的方法,通过方法的执行来解决问题。
flowchart LR
拿盆 --> 加洗衣粉 --> 加水--> 洗衣服 --> 拧干 --> 挂衣服
2、面向对象
以面向对象的方式来解决问题,==不会关注事情的过程==,只是通过对象之间的交互来完成操作。 同样以洗衣服举例子,人不需要知道洗衣机是如何工作的,人只需要和衣服、洗衣粉、洗衣机这三个对象交互即可。
flowchart LR
人 --> 衣服--> 洗衣机
人 --> 洗衣粉-->洗衣机
二、类
类是一个模板,它描述一类对象的行为和状态。
下图为例,电影类(class),具体的每一部电影为电影类的对象(Object),对象包含电影的名称、国家、类型等。
1、类的语法格式
class是定义类的关键字,Classname是类的名字,{}中为类的主体
// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method; // 行为 或者 成员方法
}
对洗衣机类进行定义
class WashMachine{ //洗衣机类
public String brand; // 品牌
public String type; // 型号
public String color; // 颜色
public double lenght; // 长
public double weidth; // 宽
public double height; // 高
public double weight; // 重量
public void WashClothes(){ // 洗衣服
System.out.println("洗衣功能");
}
public void dryClothes(){ // 脱水
System.out.println("脱水功能");
}
public void SetTime(){ // 定时
System.out.println("定时功能");
}
}
注: 类名的定义采用==大驼峰==形式
一个类中可以包含以下类型的变量:
- 局部变量: 在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量: 成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量: 类变量也声明在类中,方法体之外,但必须声明为 static 类型。
2、实例化
用类类型创建对象的过程,称为类的实例化。在java中采用new关键字,配合类名来实例化对象。
class Dog{
//狗的属性
public String name;//狗的名字
public String color;//狗的颜色
//狗的行为
public void run() {
System.out.println("奔跑ing");
}
public void wag(){
System.out.println("摇尾巴ing");
}
}
public class Main{
public static void main(String[] args) {
Dog dog1 = new Dog(); //通过new实例化对象
dog1.name = "大黄";
dog1.color = "金黄";
dog1.run();
dog1.wag();
Dog dog2 = new Dog();
dog2.name = "旺财";
dog2.color = "黑黄";
dog2.run();
dog2.wag();
}
}
注:
new关键字用于创建一个对象的实例。- 使用
.来访问对象中的属性和方法。 - 同一个类可以创建对个实例。
三、this引用
java编译器给每个“成员方法“增加了一个隐藏的引用类型参数,该引用参数指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中中所有成员变量的操作,都是通过该引用去访问。 只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
public class Date {
public int year;
public int month;
public int day;
public void setDay(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(this.year + "/" + this.month + "/" + this.day);
}
}
1、this引用的特性
- this为类类型引用,调用哪个对象就是哪个对象的引用类型。
- this只能在成员方法中使用
- 在成员方法中,this只能引用当前对象,不能引用其他对象。
- this是成员方法的第一个隐藏参数,编译器会自动传递。如下图:
注: ==this不为空==。this是否为空这个问题就像是问自己:“我还活着么?”。
四、对象
1、创建对象
对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
- 声明: 声明一个对象,包括对象名称和对象类型。
- 实例化: 使用关键字 new 来创建一个对象。
- 初始化: 使用 new 创建对象时,会调用构造方法初始化对象。
创建对象示例:
public class Puppy{
public Puppy(String name){
//这个构造器仅有一个参数:name
System.out.println("小狗的名字是 : " + name );
}
public static void main(String[] args){
// 下面的语句将创建一个Puppy对象
Puppy myPuppy = new Puppy( "tommy" );
}
}
2、构造方法
- 每个类都有构造方法。如果没有显式地为类定义构造方法,在创建一个对象的时候,至少要调用一个构造方法。
- 构造方法的名称必须与类同名,一个类可以有多个构造方法。Java 编译器将会为该类提供一个默认构造方法。
- 一般使用
public修饰
构造方法示例:
public class Puppy{
//没有返回值类型,设为void也不行
//一般情况下使用public进行修饰
public Puppy(){
}
public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}
注: 构造方法的作用就是对对象中的成员进行初始化,==并不负责给对象开辟空间==。
2.1 默认构造方法
如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
public class Date {
public int year;
public int month;
public int day;
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
Date date = new Date();
date.printDate();
}
}
运行结果:
通过jclasslib插件看编译器的字节码文件,看是否会调用默认构造方法。
注: 一旦用户定义了构造方法,编译器将不再生成。
自定义构造方法,名字会被修改为
<init>:
2.2 构造方法可以进行重载
用户可以根据自己的需求提供不同参数的构造方法
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法
public Date(){
this.year = 2021;
this.month = 9;
this.day = 9;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
Date date = new Date();
date.printDate();
}
}
2.3 通过this简化代码
在构造方法中可以通过this调用其他构造方法来简化代码。
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复
// 此处可以在无参构造方法中通过this调用带有三个参数的构造方法
public Date(){
this(2021, 9, 9); //必须是构造方法的第一条语句
//this.year = 2021;
//this.month = 9;
//this.day = 9;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
}
不能形成环,如下:
public Date(){
this(2021,9,9);
}
public Date(int year, int month, int day) {
this();
}
3、初始化
3.1 默认初始化
public class Date {
public int year;
public int month;
public int day;
public Date(int year, int month, int day) {
//成员变量定义时,没有给初始值可以使用
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
// int a; //不给初始值,编译时会报错
// System.out.println(a);
Date date = new Date(2021,9,9);
date.printDate();
}
}
成员变量可以使用的原因与Date date = new Date(2021,9,9);相关。
当执行这条语句时,JVM需要
- 检测对象对应的类是否加载了,如果没有加载则加载。
- 为对象分配内存空间。
- 处理并发安全问题(给对象分配的空间不冲突)。
- ==初始化所分配的空间。==
- 设置对象头信息。
- 调用构造方法,给对象中各个成员赋值。
对象中成员的初始值为:
| 数据类型 | 默认值 |
|---|---|
| byte | 0 |
| short | 0 |
| int | 0 |
| long | 0L |
| float | 0.0f |
| double | 0.0 |
| char | '\u0000' |
| boolean | fasle |
| 引用类型 | null |
3.2 就地初始化
在声明成员变量时,就直接给出了初始值。
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,9,9);
Date d2 = new Date();
}
}
//代码编译完成后,编译器会将所有给成员初始化的语句添加到各个构造函数中。