# 面向对象
# 面向过程(POP)和面向对象(OOP)
- 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象,以类或对象为最小单位,考虑谁来做。
- 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
面向对象的三大特征
- 封装
- 继承
- 多态
类(Class)和对象(Object)是面向对象的核心概念
类是对一类事物的描述,是抽象的、概念上的定义
对象是实际存在的该类事物的每个个体,因而也称为实例(instance)
万事万物皆对象
在Java语言范畴中,将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
Scanner,String等
文件:File
网络资源:URL
涉及到Java语言与前端html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。
# 类的结构
属性(成员变量)与局部变量的区别:
1.相同点
- 定义变量的格式:数据结构 变量名 = 变量值
- 先声明,后使用
- 变量都有其对应的作用域
2.不同点
- 在类中声明的位置不同。属性直接定义在类的{}中,局部变量声明在方法内、方法形参、代码块内、构造器内、构造器形参中。
- 关于权限修饰符的不同。属性可以在声明的时候指明其权限,使用权限修饰符:private、public、缺省、protected,局部变量不能使用权限修饰符。
- 默认初始化值。对于属性来说,根据具体的数据类型的初始化值相关。局部变量没有初始化值,一定要显式赋值。
- 在内存中加载的位置。属性(非static)加载到堆空间,局部变量加载到栈空间。
方法的声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
方法的使用中,可以调用当前类的属性或方法,但是方法里面不能定义别的方法。
匿名对象
public class ObjectTest {
public static void main(String[] args) {
//匿名对象
new Phone().sendEmail();
new Phone().playGame(); //两个对象是不一样的
}
}
class Phone{
double price;
public void sendEmail(){
System.out.println("发送邮件");
}
public void playGame(){
System.out.println("玩游戏");
}
}
1.理解:创建的对象,没有显式的赋给一个变量,即为匿名对象
2.特征:匿名对象只能调用一次
# 方法的重载(overload)
概念:在同一个类中,允许存在一个以上的同命方法,只要它们的参数个数或者参数类型不同即可。
- 同一个类,相同方法名。参数列表不同,参数类型不同。
- 与方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系。
可变形参
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest test = new MethodArgsTest();
test.show("Hello","Ja","va","!");
}
//可变形参
public void show(String ... strs){
System.out.println("111");
}
}
1.可变形参的格式:数据类型 ... 变量名
2.当调用可变形参的方法时,传入的参数个数可以是:0,1,2,3...个
3.可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
4.可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载,二者不能共存
5.可变个数形参的方法的形参中,必须声明在末尾
6.可变个数形参的方法的形中,最多只能声明一个可变形参
# 方法参数的值传递机制
方法必须由其调用的类或对象调用才有意义。若方法含有参数:
- 形参:方法声明中的参数
- 实参:方法调用时实际传给形参的数值
Java中方法的参数传递方式只有一种:==值传递==。即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
- 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
- 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
==关于变量的赋值==
- 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
- 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
类的结构之三:构造器
/**
* @author somnus
* @create 2022-04-21 15:29
*
* 一、构造器的作用:
* 1.创建对象
* 2.初始化对象的属性
*
*
* 二、说明:
* 1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
* 2.定义构造器的格式:权限修饰符 类名(形参列表){}
* 3.一个类中定义多个构造器,彼此构成重载
* 4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
* 5.一个类中至少有一个构造器
*
*/
public class PersonTest {
public static void main(String[] args) {
//创建类的对象:new + 构造器
Person p = new Person();
p.eat();
}
}
class Person{
String name;
int age;
//构造器
public Person(){
System.out.println("Person");
}
public Person(String name){
this.name = name;
}
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
属性赋值的先后顺序
/**
* @author somnus
* @create 2022-04-21 15:42
*
* 总结:属性赋值的先后顺序
* 1.默认初始化
* 2.显式初始化
* 3.构造器初始化
*
* 4.通过“对象.方法”赋值
*
*先后顺序:1 - 2 - 3 - 4
*
*/
public class UserTest {
public static void main(String[] args) {
User u = new User();
System.out.println(u.age);
User u1 = new User(2);
System.out.println(u1.age);
}
}
class User{
String name;
int age = 1;
public User(){
}
public User(int a){
this.age = a;
}
}
# JavaBean
- 是一种Java语言写成的可重用组件
- 所谓JavaBean,是指符合如下标准的Java类
- 类是公共的
- 有一个空参的公共的构造器
- 有属性,且有对应的get、set方法
- 用户可以使用JavaBean将功能、处理、值、数据库访问和其它任何可以用Java代码创建的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他的JavaBean、applet程序或者应用来使用这些对象
# 面向对象的三大特征
# 封装性
程序设计追求“高内聚,低耦合”。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
- 低耦合:仅对外暴露少量的方法用于使用
- 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来,这就是封装性的设计思想。
封装性的体现,需要权限修饰符来配合
1.Java规定的4种权限(从小到大排列):private、default、protected、public
2.4种权限修饰符可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
3.修饰类的话只能使用public、default
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
---|---|---|---|---|
private | Yes | |||
(缺省) | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |
对于class的权限修饰符只可以用public和default
- public类可以在任意地方被访问
- default类只可以被同一个包内部的类访问
# 继承性
- 减少了代码的冗余,增强了代码的复用性
- 便于功能的扩展
- 为之后多态性的使用,提供了前提
继承的格式:class A extends class B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
体现:一旦子类A继承父类B以后,子类A就获取了父类B中声明的所有的结构、属性、方法
特别的,父类中声明为private的属性或方法,子类继承父类后,仍然认为获取了父类中私有的结构。
子类继承父类后,还可以声明自己特有的属性和方法:实现功能的扩展。
Java中关于继承性的规定:
1.一个类可以被多个子类继承
2.一个类只能有一个父类:单继承
3.子父类是相对的概念
# 方法的重写
1.重写:子类继承父类以后,可以对父类中同名同参数的方法进行覆盖
2.应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。
3.重写的规定:
- 子类重写的方法的方法名和形参列表父类中被重写的方法相同
- 子类重写的方法的权限修饰符不小于父类中被重写的方法
- 子类不能重写父类中声明为private的方法
- 返回值类型
- 若父类中被重写的方法返回值类型为void,子类重写的方法的返回值类型只能是void
- 父类被重写的方法返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
- 子类中被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型
- 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常
- 子类和父类的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)
# 子类对象实例化过程
1.从结果上来看:(继承性)
子类继承父类后,就获取了父类中声明的所有的方法和属性
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
2.从过程中看:
当我们通过子类的构造器创建子类的对象时,一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,直到调用了java.lang.Object类中的空参构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类的结构,子类对象才可以考虑调用。
明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的对象。
# 多态性
- 多态性是面向对象中最重要的概念,在Java中的体现:
- 对象的多态性:父类的引用指向子类的对象
- 可以直接应用在抽象类和接口上
- Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
- 若编译时类型与运行时类型不一致,就出现了对象的多态性
如何才能使用子类中特有的属性和方法?
向下转型:使用强制类型转换符