🚀 一、面对对象的初步认知
🌟 1.1 什么是面向对象?
Java 是一门纯面向对象的语言(Object Oriented Program,继承OOP),在面向对象的世界里,一切皆为对象,面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事。
🚀 二、类的定义和使用
面向对象程序设计关注的是对象,而对象相当于生活中的实体。
🌟 2.1 认识简单类
类是用来对一个实体(对象)来进行描述的, 主要描述该对象的属性和功能,描述完成之后计算机可以识别。
🌟 2.2 类的定义格式
JAVA中定义类需要用到 class 关键字
// 创建类
class ClassName{
field; // 属性(字段)或成员变量
method(); // 成员方法
}
❗ 注意事项:
class为定义类的关键字,ClassName 是类名,{} 中的内容是类的主体。
成员变量分为普通成员变量和静态成员变量。
成员方法也分为普通成员方法和静态成员方法。
class Person{
String name;
int age;
}
⛅
采用 Java 语言在计算机中定义类,经 javac 编译之后形成 .class 文件,在JVM 的基础上计算机就可以识别了。
❗ 注意事项:
- 类名采用大驼峰定义。
- 成员前修饰词统一为 public ,后面详细解释。
🌟 2.3 练习
定义一个学生类:
class Student{
public String name;
public String gender;
public int age;
public double score;
public void DoClass(){
;
}
public void DoHomework(){
;
}
public void Exam(){
;
}
}
❗ 注意事项:
- 一般一个文件中只会定义一个类。
- main 方法所在的类一般使用 public 修饰。
- public 修饰的类必须和文件名相同。
- 不轻易修改 public 修饰的类的名称。
🚀 三、类的实例化
🌟 3.1 什么是实例化?
定义了一个类,相当于在计算机中新定义了一种数据类型,与 int ,double 类似,新自定义类型。
用类类型创建对象的过程,称为类的实例化。使用 new 关键字,配合类名实例化对象
// 定义一个 狗 类
class PetDog{
// 狗的属性(成员变量)
public String name;
public String color;
// 狗的行为(成员方法)
public void barks(){
System.out.println("汪汪汪~~");
}
public void wag(){
System.out.println("摇尾巴");
}
}
public class Main{
public static void main(String[] args) {
PetDog dogh = new PetDog(); // 通过 new 实例化对象
// 普通成员变量的访问要通过对象的引用:dogh.变量或方法
dogh.name = "大黄";
dogh.color = "黄";
dogh.barks();
dogh.wag();
}
}
那么,接下来有个问题:实例化的对象在内存中是怎样保存的呢?
看下图:
⛅我们可以知道:
dogh 是一个变量,里面存的是地址,这样的变量也叫做引用。
两种特殊写法
// 1
PetDog d1 = null;
// d1 引用不指向任何对象
// 2
PetDog d2 = dogh;
// d2 引用指向 dogh 引用指向的对象
❗ 注意事项:
- new 关键字用于创建一个对象的实例。
- 使用 ‘ . ’ 来访问对象中的属性和方法。
- 同一个类可以创建多个实例
🌟 3.2 类和对象的说明
- 类只是一个模型,用来对一个实体进行描述。
- 类是一种自定义类型,可以用来定义变量。
- 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员。
- 类就像一个设计图,类实例化出的对象就像根据设计图建造出的房子。
🚀 四、this 引用
🌟 4.1 为什么要有 this 引用
看下面的例子:
class PetDog{
// 狗的属性(成员变量)
public String name;
public String color;
// 类的构造方法,后面会详细讲
public void SetDog(String name,String color){
name = name;
color = color
}
}
上面 SetDog 方法作用是将传过来的形参 name 和 color 赋值给实例化的类但是:
形参名和成员变量名相同了,无法分清是谁给谁赋值。
要解决这个问题就要用上 this 引用。
🌟 4.2 什么是 this 引用?
this 引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都通过该引用取访问。
class PetDog{
// 狗的属性(成员变量)
public String name;
public String color;
// 类的构造方法,后面会详细讲
public void SetDog(String name,String color){
// 通过 this 来引用
this.name = name;
this.color = color
}
}
this 引用的是调用成员方法的对象。
this 引用的三种用法:
- this. data 访问类本身成员变量
- this. func( ) 访问类本身成员方法
- this( ) 调用类本身无参构造方法
🌟 4.3 this 引用的特性
❗ 注意事项:
- this 本身无类型,对类的类型引用,哪个对象调用就是哪个对象的类型。
- this 只能在 “成员方法” 中使用
- 在 “成员方法中”,this 只能引用当前对象,不能再引用其它对象。
🚀 五、对象的构造和初始化
🌟 5.1 如何初始化对象
前面的学习我们知道,JAVA 方法内部定义一个局部变量时,必须初始化,否则会编译失败。
public static void main(String[] args) {
int a;
System.out.println(a);
}
// 编译错误,未初始化变量 a
对象的初始化:
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);
}
}
public static void main(String[] args) {
Date d = new Date();
d.printDate();
d.setDate(2021,6,9); // 显式初始化
d.printDate();
}
// 代码可以正常通过编译
通过上面例子可以发现两个问题:
- 每次创建好对象都要 调用 SetDate 才能赋值,比较麻烦。
- 局部变量必须初始化后才能够使用,为什么上面声明后没有给值仍然可以使用?
🌟 5.2 构造方法
5.2.1 概念
构造方法是特殊的成员方法,名字必须与类名相同,创建对象时,编译器自动调用,并且在整个对象生命周期内只调用一次。
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("三个参数的构造方法被调用了");
}
public static void main(String[] args) {
// 创建一个Date类型的对象,没有显式调用构造方法。
Date d = new Date(2021,6,9); // 输出"三个参数的构造方法被调用了"
}
}
构造方法作用只是对对象中的成员初始化,并不负责给对象开辟空间。
5.2.2 特性
- 名字必须与类名相同。
- 没有返回值。
- 创建对象时编译器自动调用,且在对象生命周期内只调用一次。
- 构造方法可以重载(用户根据需求提供不同参数的构造方法)。
public class Date{
public int year;
public int month;
public int day;
// 无参构造方法
public Date(){
year = 1990;
month = 12;
day = 28;
}
// 三个参数构造方法
public Date(int year,int month,int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("三个参数的构造方法被调用了");
}
}
- 如果用户没有显式定义,编译器会生成一份默认无参构造方法。但是一旦用户定义了其它构造方法,编译器就不会生成无参构造方法。这也就是为什么对象未初始化也可以编译成功。
- 构造方法中,可以 this 调用其它构造方法简化代码。
public class Date{
public int year;
public int month;
public int day;
// 无参构造方法
// 在无参构造方法中通过 this 调用三个参数的构造方法
//
public Date(){
this(1900,12,28); // 必须是构造方法中第一条语句
}
// 三个参数构造方法
public Date(int year,int month,int day){
// this(); 不可以在这里同时调用无参构造方法,否则会形成环。
this.year = year;
this.month = month;
this.day = day;
System.out.println("三个参数的构造方法被调用了");
}
}
⛅注意 :
- this(…) 必须是构造方法中第一条语句。
- 不能形成环
- 绝大多数情况下,使用 public 修饰,特殊场景下会被 private 修饰。
🌟 5.3 默认初始化
对于上面第二个问题,为什么局部变量在使用时必须要初始化,而成员变量即使不初始化也可以使用呢?
public class Date{
public int year;
public int month;
public int day;
public static void main(String[] args) {
Date d = new Date();
// 成员变量没有初始化也可以使用
System.out.println(d.year);
// 这里 a 没有初始化,编译报错
//int a;
//System.out.println(a);
}
}
要搞清楚这个过程,就要知道 new 关键字背后发生的一些事情:
Date d = new Date(2021,6,9);
这条简单语句在 JVM 层面要做好多事情:
- 检测对象类是否被加载了,如果没有则加载。
- 为对象分配内存空间。
- 处理并发安全问题
比如:多个线程同时申请对象,JVM 要保证给对象分配的空间不冲突。 - 初始化所分配的空间
对象空间被申请之后,对象的成员已经有了初始值
引用变量的初始值为null - 设置对象头信息,
- 调用构造方法,给对象各个成员赋值。
🌟 5.4 就地初始化
声明成员变量时,直接给出初始值。
public class Date{
public int year = 1900;
public int month = 1;
public int day = 1;
}
// 代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中。
🚀 六、封装
🌟 6.1 封装的概念
面向对象的三大特性:封装、继承、多态。,在类和对象阶段,主要研究的就是封装特性,何为封装呢?简单来说就是套壳屏蔽细节。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
🌟 6.2 访问限定符
JAVA 中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。
⛅说明:
- protected 主要用在继承中。
- default 是是什么都不写时的默认权限。
- 访问权限除了可以控制类中的成员的可见性,还可控制类的可见性。
- 一般情况下成员变量设置为 private ,成员方法设置为 public。
- 不必要公开的数据成员或方法,用 private,具有安全性。
public class test1 {
public static void main(String[] args) {
Person person = new Person();
person.age = 18;
person.sex = 1;
person.setName("dsad");
System.out.println(person.getName()); // // private 修饰变量只能在当前类中使用,这里使用方法调用
}
}
class Person{
int age;
private String name; // private 修饰变量只能在当前类中使用 ,被封装了
// 之后可以使用setname() 和 getName() 方法修改和调用 name 的值,这样可以让 private 变量更加安全。
int sex;
public void setName(String name){
// this 意思是当前对象的引用
this.name = name;
}
public String getName(){
return this.name;
}
// // 编译器可以自动生成 set 和 get方法
// // Generate --> getter and setter
//
// public int getAge() {
// return age;
// }
//
// public void setAge(int age) {
// this.age = age;
// }
//
// public int getSex() {
// return sex;
// }
//
// public void setSex(int sex) {
// this.sex = sex;
// }
}
🚀 七、static 成员
🌟 7.1 static 修饰成员变量
在JAVA 中,被 static 修饰的成员,成为静态成员,也可称为类成员,静态成员不属于某个具体的对象,是所有对象共享的。
⛅静态成员变量特性:
- 不属于某个对象,是类的属性,所有对象共享,不存储在某个对象的空间中。
- 可以通过对象或类名访问,但是推荐通过类名访问。
- 类静态成员存储在方法区内。
- 生命周期是类的生命周期。
public class Student{
public String name;
public String gender;
public int age;
// 静态成员变量
public static String Room = "1128";
public static void main(String[] args){
// 静态成员变量可以通过类名直接访问。
System.out.println(Student.Room);
// 也可以通过对象访问。是所有对象共享的
Student s1 = new Student();
Student s2 = new Student();
System.out.println(s1.Room);
System.out.println(s2.Room);
}
}
❗ 注意:
在普通方法中无法定义静态变量,否则会发生冲突。因为 static 定义的变量属于类变量,其不依赖于对象而存在,但是普通方法必须依赖于对象存在。
🌟 7.2 static 修饰成员方法
Java 中,被 static 修饰的成员方法称为静态成员方法,是类的方法,不是某个对象特有的。静态成员一般是通过静态方法来访问的。
class Student{
// ...
// 静态成员变量
private static String Room = "1128";
// 返回静态成员变量的静态成员方法
public static String getClassName(){
return this.Room;
}
}
public class TextStudent{
public static void main(String[] args){
// 调用静态成员方法访问 private 静态成员变量
System.out.println(Student.getClassName());
}
}
⛅静态成员变量特性:
- 不属于某个具体的对象,是类的方法。
- 建议直接通过 类名.静态方法名的方式调用。
- 不能在静态成员方法中访问任何非静态成员变量。
- 普通方法中可以调用静态方法,但是反过来不可以。因为静态方法不依赖对象,而普通方法依赖于对象而存在。
🌟 7.3 static 成员变量初始化
静态成员变量一般不会放在构造方法中初始化,构造方法中初始化的是与对象相关的实例属性。
静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。
- 就地初始化
public class Stucent{
// 定义时直接给出初始值
private static int a = 10; // 就地初始化
}
- 静态代码块初始化
要了解这块知识我们首先要知道代码块的概念。
🚀 八、代码块
🌟 8.1 代码块的概念及分类
**使用{} 定义的一段代码称为代码块。**根据代码块定义的位置和关键字,分为以下四类:
- 普通代码块
- 构造代码块
- 静态代码块
- 同步代码块(后面多线程部分讲解)
🌟 8.2 普通代码块
定义在方法中的代码块
public class Main{
public static void main(String[] args){
{// 直接使用 {} 定义,
int x = 10;
}
int b = 100;
}
}
⛅ 这种用法较少见
🌟 8.3 构造代码块
定义在类中的代码块(不加修饰的),也叫实例代码块。
构造代码块一般用来初始化实例成员变量。
public class Student{
private String name;
private int age;
// 实例代码块
{
this.name = "hello";
this.age = 18;
}
}
🌟 8.4 静态代码块
使用 static 修饰的代码块称为静态代码块
一般来初始化静态成员变量
public class Student{
private String name;
private int age;
private String gender;
private static String ClassRoom;
// 实例代码块
{
this.name = "hello";
this.age = 18;
this.gender = "man";
}
// 静态代码块
static{
ClassRoom = "1128";
}
}
❗ 注意事项:
- 不管生成多少对象,这个类里的静态代码块都只会执行一次。
- 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的。
- 如果一个类中包含多个静态代码块,编译代码时,编译器按照定义的顺序先后运行。
- 实例代码块只有创建对象时才会执行。静态代码块全部运行完毕后才会执行其他代码。
class A{
static{
System.out.println("A的静态代码块被执行了");
}
{
System.out.println("A的实例代码块被执行了");
}
public A(){
System.out.println("A的构造方法被执行了");
}
}
class B extends A{
static{
System.out.println("B的静态代码块被执行了");
}
{
System.out.println("B的实例代码块被执行了");
}
public B(){
System.out.println("B的构造方法被执行了");
}
}
public class t3 {
public static void main(String[] args) {
B b = new B();
}
}
/* 输出:
A的静态代码块被执行了
B的静态代码块被执行了
A的实例代码块被执行了
A的构造方法被执行了
B的实例代码块被执行了
B的构造方法被执行了
/