前言
Java是一门纯面向对象的语言,在面向对象的世界里,一切都为对象。它是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。类与对象是我们学习面向对象最基础的知识,是面向对象实现的基石,可见它是有多么重要
1. 面向对象的含义
面向对象是一种编程思想,与之相对的还有面向过程,我们就拿炒菜这件事来解释一下这两者之间的区别
面向过程:准备食材 — 打开油烟机 — 热锅加油 — 油热放入食材翻炒 — 加入调味品 — 出锅
面向对象:食材、自动炒菜机、人、调味品,由这几个对象,我们就能完成炒菜这一件事
在这个例子中,我们能够看出来面向过程跟面向对象,是两种不同的思维方式,处理问题的思考的角度不一样。面向过程中,我们注重的是炒菜这个过程是如何进行的;但在面向对象中,我们只需要注重完成炒菜需要哪些对象,通过对象之间的交互来完成,将它们组合在一起就行,完全不需要管具体的实现过程
在Java中,一切皆对象,一切都围绕对象进行,我们只需要关心找对象、建对象,用对象等
2. 类的定义和使用
类:是用来对一个物体的属性和功能进行描述的。像生活中我们经常使用的手机,在Java中就可以看成一个类,手机品牌,型号,外观,材料都是它的属性;而打电话,上网,刷视频就是它的功能;这样我们就可以在Java中创建一个手机类
对象:某个类的一个实体。我们可以用手机类创建出一部华为手机,此时这部手机就可以称之为一个对象,创建好了对象后,我们就可以来操作手机的属性和功能
2.1 类的定义格式
// 创建类
class ClassName{field; // 成员变量/字段/属性method; // 成员方法/行为
}
- class是定义类的关键字,ClassName是类的名字,可以根据需求自己命名,取的尽量要有意义
- 类中包含的内容称为类的成员,成员变量是用来描述类的,成员方法是用来说明类具有哪些功能
注意事项:
- 类名要采用大驼峰单词命名法,即每个单词的首字母都要大写
- 一个源文件中只能存在唯一一个主类(用public修饰的类)
- 类的成员变量都有默认值:引用数据类型为null,基本数据类型为各自的0值,boolean类型为false
2.2 类的实例化
类的实例化指的就是用类创建对应的对象,在Java中我们采用new关键字,配合类来实例化对象
类名称 引用名称 = new 类名称( )
例如:
Person person = new Person( );
在上面的例子中,我们使用Person这个类创建了一个person对象,要注意的是,所有类的对象都是引用数据类型。所以person就是引用变量,变量名可以根据自己的需求命名
我们可以把上面的例子再扩充一下,想一下人会有什么属性,有什么行为?
class Person{//成员变量String name; //姓名int age; //年龄String gender; //性别//成员方法void run(){System.out.println(name+"在跑步~~~");}void print(){System.out.println("姓名:"+name+" 年龄:"+age+" 性别:"+gender);}
}public class Test {public static void main(String[] args) {//创建一个实例化对象Person A = new Person();//通过对象来给对象的成员变量进行赋值,并使用成员方法A.name = "小A";A.age = 18;A.gender = "男";A.print();A.run();System.out.println("=========");//创建对象后不给成员变量赋值Person B = new Person();B.print();}
}
输出结果如下:
我们可以用一个图来理解上面的代码
从上面的例子中可以看到:在创建好类后,我们可以通过new来实例化多个对象,使用“对象名.”给成员变量一一赋值,也可以调用类中的成员方法实现各种功能;当我们没有初始化对象时,成员变量都会有各自类型对应的默认值
2.3 类和对象的关系
我们可以把类看成一张产品设计图,在设计图上面有产品的各种属性,还有产品附带的各种功能
有了设计图,我们就可以根据设计图生产大量产品,生产出来的产品也附带有各种功能
这种拿产品设计图来生产产品就等同于类实例化对象,一个类可以实例化出多个对象,而且实例化出来的对象也要占据内存空间,用来存储各自的成员变量
补充说明
下图展示的就是创建对象以及使用对象在计算机中的执行原理
从图中我们可以得知:
- 我们创建出来的对象在栈内存当中,变量里面记住的是对象的地址
- 每次new对象,就是在堆内存中开辟一块内存区域代表一个对象
- 类存在于方法区中
3. this关键字
3.1 什么是this
this就是一个变量,可以用在方法中,来拿到当前对象;哪个对象调用方法,this就指向哪个对象,也就是拿到哪个对象。我们来看一下具体的例子
class Student {public void printThis() {System.out.println(this);}
}public class Test {public static void main(String[] args) {Student student = new Student();System.out.println(student);student.printThis();}
}
在上面的代码中,我们创建了一个学生类,并在里面定义了printThis方法,打印this的值;在Test主类中我们new了一个学生对象student,直接打印了student,同时也调用了printThis方法。
在前面我们有讲到“创建出来的对象在栈内存当中,变量里面记住的是对象的地址”,那现在student里面装的就是对象的地址,我们来看一下运行结果
通过结果我们可以看到:student和this打印出来的结果一模一样,都是对象的地址,也就是说:this指向的就是对象,它就是对象在方法中的分身
3.2 this有什么作用
- this主要用来解决:变量名称的冲突问题
我们还是用上面的学生类来举例子,假设有一个学生,他在一次考试中考了59分,而及格分数要求不小于60分,我们用代码来实现一下这个情景
class Student {double score;public void printfPass(double score) {if(score >= score) {System.out.println("通过考试~~~");} else {System.out.println("考试不及格~~~");}}
}public class Test {public static void main(String[] args) {Student student = new Student();student.score = 59; //考试成绩student.printfPass(60); //及格分数}
}
运行结果如下
为什么会出现这种情况呢?
原因在于:我们的成员变量名和方法的形参名相同,导致考试成绩59压根就没有进入到方法里,本质上是及格分数60分在自己和自己比较,60肯定是不小于60,故输出“通过考试~~~”
因此,我们需要在第一个score前面加上“this.”,这样就是避免变量名冲突产生的问题
class Student {double score;public void printfPass(double score) {if(this.score >= score) { //第一个score前面加上this.System.out.println("通过考试~~~");} else {System.out.println("考试不及格~~~");}}
}public class Test {public static void main(String[] args) {Student student = new Student();student.score = 59; //考试成绩student.printfPass(60); //及格分数}
}
这就是this引用所发挥的作用,除了this引用成员变量外,this还可以引用成员方法。当我们创建多个对象后,它们要使用同一个方法时,就可以在前面加上this引用,这样可以让编译器知道是哪个对象调用的方法
总结一下:
- this就是一个变量,它指向的就是对象,它就是对象在方法中的分身
- this只能在成员方法中使用,不能再类(用static修饰的)方法中使用——这个在后面我们会详细讲解
- 在成员方法中,this只能引用当前一个对象
- 我们在写代码的过程中要习惯性地加上this,这样可以避免访问冲突的问题,减少不必要的麻烦
4. 构造方法
在前面的学习中,我们明白了如何去创建一个对象,但是在初始化对象的时候,我们使用对象引用成员变量一个一个初始化的,这未免有些麻烦
//创建一个实例化对象
Person A = new Person();
//通过对象来给对象的成员变量进行赋值,并使用成员方法
A.name = "小A";
A.age = 18;
A.gender = "男";
A.print();
A.run();
哎,这时候,构造方法就能发挥作用了
4.1 构造方法的定义
构造方法,也叫做构造器。它是一种特殊的成员方法,它可以帮助我们更加方便地去初始化对象。而且构造方法的名字必须跟类名一样,我们在使用new创建对象时,实际上就是调用了当前类的构造方法。下面就是一个Student类的构造方法
class Student {double score;//构造方法public Student(double score) {this.score = score;}
}
4.2 构造方法的语法规则
- 方法名和类名完全相同
- 构造方法没有返回值(也不能写void)
- 在一个类中至少存在一个构造方法,如果没有显示定义,那么编译器就会生成一个默认的无参构造
- 构造方法可以重载(我们可以根据需求来创建不同参数的构造方法)
class Student {String name;int age;String gender;//编译器默认给的无参构造方法public Student() {}//自己创建的有参构造方法public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}
}
public class Test {public static void main(String[] args) {Student student = new Student();Student student1 = new Student("张三",19,"男");}
}
通过构造方法,我们就可以在创建对象的时候边给它赋值,省去了一个一个变量赋值的麻烦
如果我们不自己定义构造方法,那么编译器就会生成一份默认的无参构造方法,但如果我们自己定义了构造方法,编译器就不会生成了,说白了就是“救急不救穷”
4.3 构造方法的重载
关于构造方法的重载,我们得先来认识什么是重载?
重载:就是方法名称相同,但是参数列表不相同(顺序、个数、类型)的情形,这样的同名不同参数的方法之间,就称之为方法的重载
//编译器默认给的无参构造方法
public Student() {}//自己创建的有参构造方法
public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;
}
重载的好处在于:它方便了程序员可以根据不同的参数顺序、个数、类型来自动匹配方法,减少写多个方法名的重复步骤。所以我们在创建对象时,可以根据需要选择是否要初始化对象
小技巧
在idea中,它给我们提供了快速生成构造方法的途径
这样就能让idea自动帮你生成有参构造方法啦
5. 封装
封装是面向对象的三大特征之一,其余两项分别是继承和多态,今天我们着重讲一下封装
5.1 封装的定义
封装:就是当我们用类去设计对象去处理某一个事物的数据时,应该把要处理的数据,以及处理数据的方法,设计到应该对象中去。简单来说——将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互,就是封装
5.2 封装的设计规范
合理隐藏、合理暴露。我们在设计封装的时候要牢记这“八字真言”。就像一辆汽车,它的内部是由很多成员的,比如发动机、油箱等器件,汽车设计者会用外壳把这些内部元器件都隐藏起来,只暴露出方向盘、刹车、油门这些器件供司机使用。这就是所谓的合理隐藏、合理暴露
5.3 设计封装的示例
如果我们想要公开成员,可以使用public来修饰,如果想要隐藏成员,可以使用private来修饰
我们可以发现,成员变量name是用public修饰的,那在我们创建好student对象后,可以用对象引用直接调用它并赋值;而成员变量age是用private修饰的,我们用同样的方法却会报错。这是因为,public是公开的,面向任意包的任意类;而private就只能在当前类使用
如果我们就是想要调用成员变量age,那要怎么做呢?
我们可以在Student类里定义getAge和setAge方法,用来得到age和给age赋值。这两个方法使用public修饰的,相当于age的经纪人,它们可以让对象间接的接触到age,这样就能解决上面的问题了。而成员方法也是同理,用public就表示公开,用private就表示隐藏
在一般情况下,我们会将成员变量设置为private,成员方法设置为public。诚然,实际情况还得根据业务需求来定,这里只是提供参考
小技巧
在idea中,它也给我们提供了快速get和set方法的途径
这样就能让idea自动帮你生成get和set方法啦
结语
今天我们一起学习了Java当中的类与对象,还讲解了this关键字、构造方法以及封装的知识,希望大家能喜欢这篇文章,有总结不到位的地方还请多多谅解,若有出现纰漏,希望大佬们看到错误之后能够在私信或评论区指正,博主会及时改正,共同进步!