本文详细介绍了java面向对象的相关知识,包括但不限于以下知识:
- 类与对象
- 面向对象三大特征:封装、继承、多态
- 面向对象三大修饰符:(final、abstract、static)
面向对象(JAVA)详解
1.面向对象(类与对象)
1.编程思想
面向过程:
考虑事物的发展顺序
面向对象:
首先考虑事物中存在哪些对象,再建立对象与对象的关系
2.对象
(1)概念
生活中:真实存在的事物就是对象
代码中:使用代码模拟生活中存在的对象
/*万事万物皆对象*/
(2)如何创建一个对象
语法:
数据类型(类名) 对象名 = new 类名(实参列表);
本质:
调用类中的构造函数,
要求:
调用构造函数时,传入的实参列表要与构造函数定义时的形参列表,长度一致,顺序一致,数据类型一致
(3)对象的创建过程
语法:
类名 对象名 = new 类名(实参列表);
创建过程:
1,在堆内存开辟一片运行内存
2,给对象的属性赋初始值(基本数据类型默认为0(值存储在堆中),引用数据类型默认为null(存储的是引用数值所在的地址))
3,执行构造函数中的代码
4,将栈中的引用指向堆中开辟的内存地址
3.类
(1)概念
多个对象抽取其共同点形成的概念,就称为类
(2)如何创建一个类
语法:
访问权限修饰符 class 类名{
}
类名:符合大驼峰命名法,做到见名知意
定义的位置:
因为内部类还没有学习,所有将自定义类定义在 类 以外
(3)类中有什么
属性概念:用于描述对象的静态特征
别名:成员变量
本质:就是在方法外,类中定义的变量
定义的格式:
访问权限修饰符 数据类型 变量名;
注意:只能使用该类对象调用
构造函数概念:用于创建该类对象,因为构造函数的方法名必须与类名一致,所以new调用的就是构造函数
别名:构造方法
本质:一个特殊的方法
定义的格式:
访问权限修饰符 类名(形参列表){
方法体
}
定义位置:
类中,方法以外
注意:1.只能使用new关键字调用
2.如果一个类中没有构造函数,系统会为其提供一个无参的构造函数
方法概念:用于描述对象的动态特征(行为)
别名:函数
本质:包装一段代码的容器
定义的格式:
访问权限修饰符 修饰符 返回值类型 方法名(形参列表){
方法体
return xxx;
}
返回值类型:如果方法有返回值,那么返回值类型就是返回值的数据类型,如果没有就写void
方法名:自定义,符合小驼峰命名法
定义位置:
类中,方法以外
属性的作用:描述对象 静态特征
构造函数的作用:创建该类对象
方法的作用:描述对象的 动态特征
(4)类与对象的关系
生活中:
先有对象后有类
代码中:
现有类后有对象
(5)局部变量与成员变量
1.在类中的位置不同
成员变量:在类中定义
局部变量:在方法中定义或方法的参数
2.在内存中的位置不同
成员变量:在堆内存(成员变量属于对象,对象进堆内存)
局部变量:在栈内存(局部变量属于方法,方法进栈内存)
3.声明周期不同
成员变量:随着对象的创建而存在,随着对象的销毁而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
4.初始化值不同
成员变量:有默认初始化值,引用数据类型默认为null
局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
5.权限修饰符不同
局部变量:无权限修饰符
成员变量:存在权限修饰符
注意:局部变量名称可以和成员变量名称一样,在方法中使用时,采用就近原则(若其为对象可以采用this区分)
(6)静态变量与成员变量的区别
静态变量:
1. 调用方式:类名.属性名或对象名.属性名
2.属于 该类 所有的对象
成员变量:
1.调用方式:对象名.属性名
2.属于 具体 的某一对象
(7)构造函数与方法的区别
1、格式区别
构造方法和类名相同,并且没有返回类型,也没有返回值;不可被重写、不可被继承(可以被调用);可用this、super调用本类和父类的构造函数。
普通成员方法可以任意起名,必须有返回类型,可以没有返回值;可被重写、可被继承;不可用this、super调用本类和父类的构造函数。
2、作用区别
构造方法用于创建对象,并进行初始化值。
普通成员方法是用于完成特定功能的。
3、调用区别
构造方法是在创建对象时被调用的,一个对象建立,只调用一次相应构造函数
普通成员方法是由创建好的对象调用,可以调用多次
4.this的使用
(1)概念
哪一个对象调用this所在的方法,this就代指这个对象
(2)使用
1,当局部变量与成员变量重名时,用于区分成员变量与局部变量,this.属性名表示成员变量(属性)
2,在本类构造函数中,调用其他构造函数
this(实参列表);
注意:
1,必须在构造函数第一行
2,不要形成死循环
3,在本类中调用本类其他属性或方法,此时可以忽略this不写
2.面向对象(封装、继承、多态)
1.封装
(1)优点
思想:包装
优点:
1,美化
2,降低耦合度
3,保护内部
4,方便使用
(2)Java代码中的封装
变量:封装一个可以改变的数据
数组:封装一组数据
方法:封装一段代码
类:封装多个属性与多个方法
java文件:封装一个或多个类
包:封装多个java文件
项目:封装多个包
...
(3)包
本质:一个文件夹
创建包:
选择src文件夹,点击鼠标右键,选择new,选择package
填写包名
注意:
包名使用全小写,不要用数字开头,不要出现特殊符号
包名的命名潜规则:
com.公司名称缩写.作用
注意:.表示下一层文件夹
关键字:package
导包:
关键字:import
为什么要导包:
所需使用的类与当前类不在同一个包中
(4)访问权限修饰符
意思:限制属性,方法,构造函数,类等的使用范围
分类:
关键字 意义 使用范围
public 公共的 当前项目中
protected 受保护的 当前包中或继承关系中
不写 默认的 当前包中
private 私有的 当前类中
总结:
一般情况下:
属性用private修饰,方法与类用public修饰
属性用private修饰后需提供get与set方法
2.继承
(1)优点
概念:
生活中的继承:晚辈获取长辈留下的财产与精神
代码中的继承:
多个类(B1,B2)抽取其共同点形成了一个类(A)
注意:
判断类A是否与类B有继承关系
如果类B与类A存在继承关系,可以让类B继承与类A,此时类B将拥有类A的所有属性与方法,构造函数除外
类B:称为子类
类A:称为父类
优点:
1,减少代码
2,使代码结构清晰
3,降低代码冗余度
总结:
子类将拥有父类的所有属性与方法,构造函数除外(父类构造函数只能使用,不是拥有关系)
(2)继承的语法
语法:
访问权限修饰符 class 子类名 extends 父类名{
属性
构造函数
方法
}
注意:
1,Java只能单继承
2,如果一个类没有写继承,默认继承于Object
3,如果父类中的方法与子类方法名相同,形参列表相同,返回值类型相同,访问权限修饰符子类大于或等于父类该方法,这种方法称为重写
(3)super的使用
作用:子类中使用父类的内容
使用:
属性
特殊情况:子类的属性名与父类属性名相同,如何区分
子类:this.属性名
父类:super.属性名
方法
特殊情况:子类重写父类方法,在子类中使用该方法,如何区分是父类方法还是子类方法
子类:this.方法名(实参列表);
父类:super.方法名(实参列表);
构造函数
情况:创建子类对象时,需要给父类构造函数传值
语法:
super(实参列表);
注意:
1,要在子类构造函数第一行
2,子类构造函数中如果没有调用父类构造函数,那么默认在其第一行有super();调用父类无参构造函数
3,重写父类方法时,若访问权限修饰符比父类小,则会报错
总结:
子类将拥有父类的所有属性与方法,构造函数除外
3.多态(事物 —— 事和物)
(1)概念
一个 事物 的多种形态
(2)代码中的多态(事 —— 方法的重写与重载)
重写:
要求:
发生在继承关系中,子类访问权限修饰符大于或等于父类访问权限修饰符,返回值类型相同,方法名相同,形参列表相同,方法体不同
注意:
当某个对象重写了父类的方法,对象在调用方法名时,遵循就近原则,会调用子类重写后的方法;当子类未重写方法时,对象调用方法,其会调用父类的方法
重载:
要求:
发生在同一个类中,方法名相同,形参列表不同
注意:
当对象重写方法时,除了形参列表不同其余方法变量全部相同时,可以实现方法重载的效果,但此种方法的改变既不叫重写也不叫重载(不在同一个类中)
(3)代码中的多态(物 —— 对象)
物(对象)
如类A继承与类B
类A:子类
类B:父类
(父类对象可以看作是大数据类型,子类对象可以看作是小数据类型,其转换情况符合基本数据类型转换原则)
类名A 对象名A = new 类名A();
//子类对象转父类对象,可以自动转换
类名B 对象名B = 对象名A;
//父类对象转换子类对象,需要强制转换,有风险
类名A 对象名A2 = (类名A) 对象名B;
注意:1,类的所有对象属于引用数据类型,其转换的实质是改变引用的指向
2,子类对象转换为父类对象会丢失自己特有的属性和方法
3.若一个类的本质不是父类,则此父类无法转化为其子类(编写程序不会报错,运行程序会报错)
4.重点:主要看一个类的本质是什么,使用 instanceof 可以某个对象是否的归属某个类的类型(父类或其他子类的类型)
eg:if (animal instanceof Dog)//对象animal是否属于Dog类
3.面向对象(三大修饰符)
1.抽象的
概念:无法描述的,无法实例的
关键字:abstract
可以修饰:
方法
语法格式:
访问权限修饰符 abstract 返回值类型 方法名(形参列表);
注意:
1,抽象方法没有方法体
2,有抽象方法的类一定是抽象类
类
语法格式:
访问权限修饰 abstract class 类名{
属性
方法
构造函数
}
注意:
1,子类继承于抽象类,要么重写所有抽象方法,要么自己也是抽象类
2,抽象类无法直接创建对象
3,抽象类中不一定有抽象方法
4,抽象方法一定在抽象类中
2.最终的
概念:不可修改的,最后的
关键字:final
修饰:
类
意义:最终类,不能被别的类继承
语法:
访问权限修饰符 final class 类名 extends 父类名{
属性
方法
构造函数
}
方法
意思:不可被重写
语法:
访问权限修饰符 final 返回值类型 方法名(形参列表){
方法体
return xxx;
}
属性
意思:不可被修改,称为常量,常量命名全大写
语法:
访问权限修饰符 final 数据类型 属性名;
final修饰的变量就是常量
局部变量
意思:不可被修改,称为常量,常量命名全大写
语法:
finl 数据类型 属性名;
final修饰的变量就是常量
3.静态的
(1)基本概念语法
概念:该类所有对象共有的,属于类
关键字:static
修饰:
属性:
语法:访问权限修饰符 static 数据类型 属性名;
static修饰的属性称为静态成员变量
注意:
1,static修饰的属性属于该类的所有对象,一个对象对其进行修改,所有对象的该属性都将被修改
2,static修饰的属性多了一种调用方式
语法:
类名.属性名;
类名.属性名 = 值;
原来:
对象名.属性名
对象名.属性名 = 值;
方法:
语法:
访问权限修饰符 static 返回值类型 方法名(形参列表){
方法体
}
static修饰的方法称为静态方法
注意:
1,静态方法中只能 直接 使用静态成员(静态属性,静态方法)
2,static修饰的方法多了一种调用方式
语法:
类名.方法名(实参列表);
原来:
对象名.方法名(实参列表);
3,静态方法中不能使用this与super(因为静态变量的声明周期长,其在类加载时创建,在没有对象存在时静态变量就已经存在,故不能在静态方法中调用非静态变量或方法)
代码块:
静态代码块
(2)static 关键字补充
static 关键字
1,静态变量或方法不属于对象,但要依赖于类,即属于类
2,静态变量是全局变量(生命周期从类被加载后一直到程序结束)
3,静态变量只存一份,在静态方法区中存储
4,静态变量是本类所有对象共享的一份,建议不要使用对象名去调用静态数据,直接使用类名调用
5,不能在静态方法中调用非静态变量或方法的原因:因为静态变量的声明周期长,其在类加载时创建,在没有对象存在时静态变量就已经存在,故不能在静态方法中调用非静态变量或方法
4.代码块
概念:一块代码
普通代码块:
类中,方法以外
语法:
{
代码
}
调用:
每次调用该类构造函数创建对象时,由系统调用该类的普通代码块,在执行构造函数前调用
静态代码块:
与static结合使用
语法:
static{
}
调用:
类加载时调用,所以只会调用一次
类的加载时机:
1,第一次创建该类对象时
2,第一次创建子类对象时(先有父,后有子)
3,使用类名调用本类静态属性(只有当JVM加载此类之后,才可以使用该类的静态属性)
4,使用类名调用本类静态方法
5,使用第一次使用反射获取该类对象时
Class.forName("包名.类名");
注意:
1,类只加载一次
2,一个类有静态与非静态属性,先加载静态属性
在继承关系:
1,先加载父类静态,在加载子类静态,父类非静态,子类非静态
2,在 1 条件下,属性 > 方法 > 静态代码块 > 代码块 >构造函数(静态 > 非静态)
3,在使用new关键字调用构造函数创建对象时,先加载属性和方法,再执行构造函数的代码