前言:
Java学习面向对象编程的路线分三步:
①Java类及类的成员:属性、方法、构造器、代码块、内部类
②面向对象特征:封装、继承、多态
③一些关键字的使用:this、super、package、import、static、final、interface、abstract等
面向过程:POP
关注的焦点是过程:过程就是操作数据的步骤。典型的语言:C语言 适合解决简单问题。扩展能力差、后期维护难度较大。
-
不管是面向过程、面向对象,都是程序设计的思路。面向过程和面向对象不是对立起来的。他们是相辅相成的。面向对象离不开面向过程!
-
面向过程:以函数为基本单位,适合解决简单问题。比如:把大象装进冰箱。①打开冰箱②把大象装进冰箱③把冰箱门关住。其实就是:第一步干嘛,第二步干嘛……第n步干嘛。
-
面向对象:以类为基本单位,适合解决复杂问题。比如:造车。车是由什么组成的,发动机、轮胎、底盘……。其实就是:关注组成事物的独立个体,这个个体有什么属性、行为……
面向对象:OOP
参照现实中事物,将事物的属性特征、行为特征抽象出来,用类来表示。典型的语言:Java、C#、C++、Python、Ruby和PHP等 适合解决复杂问题。代码扩展性强、可维护性高。
面向对象完成具体功能的步骤:
步骤1:创建类,并设计类的内部成员(属性、方法)
步骤2:创建类的对象。比如:Phone p1 = new Phone();
步骤3:通过对象,调用其内部声明的属性或方法,完成相关的功能
类:
具有相同特征的事物的抽象描述,是抽象的、概念上的定义。比如:学校
对象:
实际存在的该类事物的每个个体,是具体的,因而也称为实例。比如:西安交通大学
权限修饰符:
- public:公共访问级别,表示该类、方法或变量可以被任何其他类访问。
- private:私有访问级别,表示该类、方法或变量只能在其所属的类内部访问。
- protected:受保护访问级别,表示该类、方法或变量可以在同一个包内的其他类以及子类中访问。
- 默认(无修饰符):默认访问级别,表示该类、方法或变量只能在同一个包内的其他类访问。
Java中内存结构的划分:
-
Java中内存结构划分为:
虚拟机栈、堆、方法区
;程序计数器、本地方法栈 -
虚拟机栈:以栈帧为基本单位,有入栈和出栈操作;每个栈帧入栈操作对应一个方法的执行;方法内的局部变量会存储在栈帧中。
-
堆空间:new 出来的结构(数组、对象):① 数组,数组的元素在堆中 ② 对象的成员变量在堆中。
-
方法区:加载的类的模板结构。
属性:又叫成员变量、field、字段、域
某类事物的状态信息。对应类中的成员变量。比如:学校这个类,每个学校都有校名这个属性。
声明格式:
默认初始化值:
对于属性的理解:属性(成员变量) vs 局部变量
这里也推荐下星火讯飞认知大模型,可以看到挺好用的😉😂😂😂🤤🤤🤤
方法:又叫函数、Method
该类事物要做什么操作,或者基于事物的状态能做什么。对应类中的成员方法。
声明格式:
()里边是参数列表;{}里边是方法体。
返回语句return:
return语句的作用是结束方法的执行,并将方法的结果返回去
如果返回值类型不是void,方法体中必须保证一定有 return 返回值; 语句,并且要求该返回值结果的类型与声明的返回值类型一致或兼容。
如果返回值类型为void时,方法体中可以没有return语句,如果要用return语句提前结束方法的执行,那么return后面不能跟返回值,直接写return ; 就可以。
return语句后面就不能再写其他代码了,否则会报错:Unreachable code
标红:
①必须先声明后使用,且方法必须定义在类的内部②调用一次就执行一次,不调用不执行。③方法中可以调用类中的方法或属性,不可以在方法内部定义方法。
方法的重载:
在同一个类中,可以有多个同名方法,只要它们的参数列表不同即可
方法的重载的要求:“两同一不同”
调用方法时,如何确定调用的是某个指定的方法呢?① 方法名 ② 形参列表
可变个数形参的方法:
格式:(int ... args),可变个数的形参列表使用三个点(...)来表示
/**
* 可变参数
*/
public void test(String a,int... b){
for (int i : b) {
Log.i("test:","b:" + i);
}
}
方法的参数传递机制:值传递
如果形参是基本数据类型的变量,则将实参保存的数据值赋给形参。
如果形参是引用数据类型的变量,则将实参保存的地址值赋给形参。
递归方法:
递归方法构成了隐式的循环
对比:相较于循环结构,递归方法效率稍低,内存占用偏高。
构造器:
声明格式:
作用:
① 搭配上new,用来创建对象 ② 初始化对象的成员变量
举例:
/**
在Java中,一个学校类可以被设计来表示现实世界中的学校。这个类可以包含一系列属性来描述学校的特征,同时提供方法来展示学校的行为。下面是一个示例:
一、属性
name:学校的名称,字符串类型。
address:学校的地址,字符串类型。
principal:校长的名称,字符串类型。
studentsCount:在校学生的数量,整型。
teachersCount:教师的数量,整型。
foundingYear:建校年份,整型或日期类型。
二、方法
getSchoolInfo():获取学校的基本信息,包括名称、地址和校长。
enrollStudent(String studentName):学生入学,增加学生数量。
hireTeacher(String teacherName):聘请新教师,增加教师数量。
graduateStudent(String studentName):学生毕业,减少学生数量。
retireTeacher(String teacherName):教师退休,减少教师数量。
*/
public class School {
//属性
private String name;
private String address;
private String principal;
private int studentsCount;
private int teachersCount;
private int foundingYear;
//构造器
public School(String name, String address, String principal, int foundingYear) {
this.name = name;
this.address = address;
this.principal = principal;
this.foundingYear = foundingYear;
this.studentsCount = 0;
this.teachersCount = 0;
}
//方法
public String getSchoolInfo() {
return "School: " + name + ", Address: " + address + ", Principal: " + principal;
}
public void enrollStudent(String studentName) {
studentsCount++;
System.out.println(studentName + " has enrolled. Total students now: " + studentsCount);
}
public void hireTeacher(String teacherName) {
teachersCount++;
System.out.println(teacherName + " has been hired. Total teachers now: " + teachersCount);
}
public void graduateStudent(String studentName) {
studentsCount--;
System.out.println(studentName + " has graduated. Total students now: " + studentsCount);
}
public void retireTeacher(String teacherName) {
teachersCount--;
System.out.println(teacherName + " has retired. Total teachers now: " + teachersCount);
}
}
代码块:使用频率上来讲:用的比较少。
代码化块又称为初始化块,属于类中的成员,类似于方法,将逻辑语句封装在方法体中,通过{ }包围起来。但其和方法不同,没有方法名、返回、参数,只有方法体,且不用通过对象或类显式调用,而是在加载类时或创建对象时被隐式调用。
分类:
静态代码块:
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块随着类的加载而加载,且只执行一次。
标红:①修饰符可写可不写,写的话只能写static。②有static的叫静态代码块,没有的叫普通代码块。③逻辑语句可以为任何逻辑语句。(输入、输出、循环、方法调用、判断等)⑤{ }最后的;可写可不写。
非静态代码块:
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 除了调用非静态的结构外,还可以调用静态的变量或方法。
- 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
- 每次创建对象的时候,都会执行一次。且先于构造器执行。
-
如果多个重载的构造器有公共代码,并且这些代码都是先于构造器其他代码执行的,那么可以将这部分代码抽取到非静态代码块中,减少冗余代码。
核心问题:
①代码块初始化是在什么时候?静态代码块:随着类的加载而初始化。非静态代码块:随着对象的创建而初始化
②代码块执行顺序是怎样的?静态代码块 ==> main()方法 ==> 非静态代码块
③代码块在继承时,执行顺序是怎样的?父类静态块 ==> 子类静态块 ==> 父类代码块 ==> 父类构造器 ==> 子类代码块 ==> 子类构造器 。
对象的实例变量可以赋值的位置及先后顺序:
① 默认初始化 ② 显式初始化 或 ⑤ 代码块中初始化 ③ 构造器中初始化
④ 有了对象以后,通过"对象.属性"或"对象.方法"的方法进行赋值
执行的先后顺序: ① - ②/⑤ - ③ - ④
内部类:
定义:
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类。当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。
分类:
成员内部类:
- 成员内部类作为类的成员的角色:
- 和外部类不同,内部类还可以声明为private或protected;
- 可以调用外部类的结构。(注意:在静态内部类中不能使用外部类的非静态成员)
- 内部类可以声明为static的,但此时就不能再使用外层类的非static的成员变量;
- 成员内部类作为类的角色:
- 可以在内部定义属性、方法、构造器等结构
- 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
- 可以声明为abstract类 ,因此可以被其它的内部类继承
- 可以声明为final的,表示不能被继承
- 编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)
标红:
- 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式
- 成员内部类可以直接使用外部类的所有成员,包括私有的数据
- 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的
创建成员内部类对象
- 实例化静态内部类
外部类名.静态内部类名 变量 = 外部类名.静态内部类名();
变量.非静态方法();
- 实例化非静态内部类
外部类名 变量1 = new 外部类();
外部类名.非静态内部类名 变量2 = 变量1.new 非静态内部类名();
变量2.非静态方法();
局部内部类:
非匿名局部内部类:
语法格式:
[修饰符] class 外部类{
[修饰符] 返回值类型 方法名(形参列表){
[final/abstract] class 内部类{
}
}
}
- 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。
- 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类
- 和成员内部类不同的是,它前面不能有权限修饰符等
- 局部内部类如同局部变量一样,有作用域
- 局部内部类中是否能访问外部类的非静态的成员,取决于所在的方法
匿名内部类:
因为考虑到这个子类或实现类是一次性的,那么我们“费尽心机”的给它取名字,就显得多余。那么我们完全可以使用匿名内部类的方式来实现,避免给类命名的问题。
new 父类([实参列表]){
重写方法...
}
new 父接口(){
重写方法...
}