这里写目录标题
第八章 面向对象
8.1 面向过程和面向对象
大象装冰箱,总共有几步?
分三步:
1)打开冰箱门
2)把大象装进去
3)关闭冰箱门
面向过程:关注的是解决问题的步骤
面向对象:关注问题中所涉及对象,以及对象的行为
大象装冰箱,总共分几步?
1)冰箱->开门
2)冰箱->关门
3)冰箱->装东西
再组织好对象的行为->问题解决
类:对现实世界中事物的抽象。Student
对象:现实世界中具体的个体。张三、李四 这些具体的学生
*面向对象的特征:抽象、封装、继承、多态*
*OOP: Object Oriented Programming*
类和对象的总结:
1、现实世界都是由很多对象组成的,基于对象的共同特征抽象出类。
2、对象:真实存在的对象
3、类中包含:
1)所有对象所共有的特征–属性(静)
2)所有对象所共有的行为–方法(动)
4、类是对象的模板,对象是类的具体实例。
5、一个类可以创建多个对象:同一个类的不同对象,结构相同,数据不同。
8.2 对象和类
对象是指现实中存在的具体的事物
在代码中,对象是程序运行过程中具体的一个东西(内存)
类是一种概念,是现实中一类事物的抽象描述形式
主要有两个点:事物相同的特征,事物的共同的行为
在Java中,类是一段代码,本质上是一种数据类型
对象与类的关系:
类是对象的抽象描述
对象是类的一个具体化,实例化
问题:
1)输入一个学生的姓名,性别,班级,成绩
8.3 类的组成
对象的特征,用类的属性描述
对象的行为,用类的方法描述
8.3.1 类的定义
语法:
[修饰符] class 类名{
类体
}
修饰符:指定类的作用范围和使用方式
public->类是一个公共的类
在一个.java文件中,应该有且只有一个public的类,这个类的名字必须与文件的名字一致
class:关键字,表示定义的是一个类
类名:给这个类起的名字,还是一个标识符
规范:1,2,3,4
规则:大驼峰(所有单词首字母大写)
{}:{}中的部分叫做类体
类体中可以定义变量或常量,这叫做类的属性
还可以定义方法,叫做类的方法
属性和方法还统称为类的成员
构造方法
块,静态块
注意:类中的属性在定义时,都是有默认值的
1)byte,short,int,long,double,float默认值是0
2)char默认值是空字符
3)boolean默认值是false
4)引用类型默认值是null
8.3.2 类的构造方法
类的构造方法是用来创建对象的
当我们使用new 类名(),创建对象时,实际上就是在调用类的构造方法
语法:
[修饰符] 类名(){
方法体
}
注意:
1)类的构造方法是没有返回值的
2)类的构造方法的方法名必须与类名相同(区分大小写)
3)当一个类没有定义构造方法时,编译器将会创建一个默认的无参的构造方法
如果在类中定义了构造方法,这个默认构造方法将不会被会创建
4)构造方法可以重载
8.3.3 创建对象
语法:
new 类名(参数)
内存
8.3.4 类的属性和方法的调用
在类中定义的属性和方法,都需要先创建对象,在对象上使用
在类的外部,如果要调用属性和方法
可以使用:对象.属性
对象.方法(参数)
在类的内部也可以使用类的属性和方法
直接使用属性和方法名即可
当类的属性与局部变量重名时可以是this调用这个属性
*toString()*
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + ", className=" + className + "]";
}
System.out.println(student.toString());
System.out.println(student);
Student [id=1, name=张三, age=23, className=Java1912]
8.4 面向对象三大特性
四大特性(特点):抽象,封装,继承,堕胎
8.4.1 封装
广义:编写一个类的过程,就是封装的过程
高内聚,低耦合
高内聚:功能高度集中,一个类不应该有过多的功能
低耦合:各个功能之间联系越少也好
狭义:在Java中,要将类的内部信息尽量隐藏起来
1)将类的属性私有化,使用private关键字修饰属性
2)为所有的属性添加公共的get和set方法
单击鼠标右键->Source->Generate Getters and Setters
在弹出的窗口中选择需要生成get和set的属性
8.4.2 继承
继承描述的是类与类之间的关系
父类:被别的类继承的类
子类:继承别的类的类
一个类既可以做父类也可以做子类
首先要想定义好父类,然后在定义子类时,使用extends关键字指定父类
public class Father{
}
public class Son extends Father{
}
在继承关系下:
1)子类会继承父类所有的属性和方法
2)子类还可以扩展自己的属性和方法
3)子类还可以重写父类中的方法
*注意*:
-
一个类最多只有一个直接的父类(单继承)
-
继承是可以传递的
A,B,C是三个类
A是B的父类,B是C的父类
C可以继承B的所有属性和方法,也包括B从A继承的属性和方法
4)构造方法是不会被继承的,但是在子类创建对象时,会先调用父类的构造方法,再调用子类的构造方法
*继承:你继承谁你就是谁,继承是一种严格的父子关系(在父类里面抽取的属性和方法一定是所有子类所共有)*
*(Student继承Person,那么Student就是人)*
面向对象特征:抽象、封装、继承、多态
OOP: Object Oriented Programming面向对象编程
UML: 类图(描述类和类之间的关系)
Java是单继承,就是一个类只能继承extends(inherit)一个类,而java这中面向对象的语言就是对现实
世界的描述,现实世界中是存在很多多继承,但是java里面是支持实现多个接口。
Object是所有类的父类(这个父类不一定是直接父类)
private:只在当前类里面可以访问(子类也不能访问)
public:任何地方都可以访问
protected:
提高代码复用性。
将所有子类共有的属性和方法抽取到父类里面,子类继承父类,那么父类里面的属性和方法相当于子类里面也有。
*子类继承父类*
*父类的属性一般使用protected*
*# protected*
*不写,Java会默认添的:*
1)*无参构造方法*
2)*一个类不继承任何一个类,就会默认继承extends Object类*
3)*在类的构造方法第一句会默认增加super()方法*
8.4.3 多态
相同的或相近的代码,在执行时表现出不同的形态,得到不同的结果
在Java中,多态有两种表现形式
1)方法的重载
在一个类中,出现了方法名相同,但参数列表不同不同的方法
调用方法时,根据方法的实参的类型来决定调用哪个方法
重载是一种编译时多态,编译时就已经决定了调用哪一个方法
在同一个类里面,允许存在一个以上同名方法,只要他们参数类型和参数个数不同即可。
构造方法重载(无参构造方法、有参构造方法)
方法重载特点:*与返回值无关*,只看参数列表。
void show(int a, char b, double c){}
1、void show(int x, char y, double z){} 不是重载,是同一个方法
2、int show(int a, double c, char b){} 是重载,顺序不一样也是重载
3、void show(int a, double c, char b){} 是重载
4、boolean show(int c, char b){} 是重载
5、void show(double c){ } 是重载
6、double show(int x, char y, double z){} 不是重载
2)方法的重写(覆盖)*@Override:*
在继承关系下,子类中出现了与父类中方法名和参数列表一样的方法
上转型对象:子类创建的对象,交给父类的变量保存
方法的重写带来的多态是运行时才会决定调用哪一个方法这个叫做运行时多态
1、子类覆盖父类,必须保证子类权限大于父类权限才可以覆盖,否则会编译失败。
2、如果父类是private的方法,子类是默认方法,那么子类是不知道这个方法的,不是覆盖。
重载(Overload):同一个类中看同名方法的参数列表。(构造方法重载)
重写(Override):父子类方法要一模一样
下转型对象:由父类的对象,强制转换成子类的变量;下转型不一定能成功
面向接口(抽象)编程
Shape shape = new Circle();
shape.draw();
shape = new Square();
shape.draw();
8.5 抽象类和接口
8.5.1 抽象类
抽象类使用abstract关键字修饰的类
抽象类是一种特殊的类,不能创建对象,产生子类,可以通过子类创建对象
语法:
public abstract 接口名{
}
1)有些类,就是不想创建对象,可以定义成抽象类
2)有些类,做为父类使用时,方法可以确定,方法内容不确定,这是可以将父类定义成抽象类,将不确定的方法,定义成抽象方法
8.5.2 抽象方法
抽象方法就是使用abstract关键字修饰的方法
抽象方法只用方法的声明,没有方法的实现
语法
public abstract 返回值类型 方法名(参数列表);
抽象方法没有方法体,是一个不完整的方法,因此在子类中需要补全方法的实现,才能使用
1)抽象方法只能定义在抽象类中,有抽象方法的类一定是抽象类
而抽象类中可以有抽象方法,也可以由有普通方法
2)抽象类的子类,要么实现抽象父类中的所有方法,要么抽象类的子类也只能是一个抽象类
1、抽象方法是没有方法体,如果这个类里面有抽象方法,这个类必须变成抽象类。
2、如果这个类是抽象类,并不要求这个类一定要有抽象方法
3、抽象类里面可以有普通方法,也可以有抽象方法。
4、如果一个类是抽象类,那么这个类就不能被new实例化,只能被其他类继承。
5、抽象方法可以理解为父类(抽象类)定义的一个模板或者规范(自己本身不实现),
子类必须实现这个抽象方法,如果子类不想实现这个方法,那么这个子类也必须要变成抽象类。
8.5.3 接口
接口(interface)是一种比抽象类更抽象的数据类型
在接口中定义的方法,默认都是抽象方法
接口也是不能创建对象的,也想抽象类一样,需要依赖实现类
接口的定义语法:
public interface 接口名{
}
接口的实现
抽象类和接口有何异同
相同点:
1)都不能创建对象
2)都可以包含抽象方法
不同点:
1)抽象类是类,接口是不同于类的一种数据类型
2)抽象类可以包含变量,普通方法,而接口只能包含静态常量和抽象方法
3)单继承多实现,一个类最多只能有一个直接父类,可以同时实现多个接口
8.5.4 为什么要使用接口
在Java中是单继承(一个类只能有一个直接的父类)
在java中是多实现(一个类可以同时实现多个接口)
例:
生产门
Door类,父类
防火门:FireSafeDoor
增加防火功能
防盗门:StealSafeDoor
增加防盗功能
新产品:
防火防盗门
父类
接口类
实现类
8.5.5 面向接口编程
操作对象时,不是一类对象的方式操作,而是以接口对象的方式操作
面向接口编程最大的优点:可以降低类与类之间的耦合(松耦合,解耦)
8.5.6 接口之间的继承
语法:
Public interface 接口名 extends 父接口名 {
}
子接口会继承父接口中所有的抽象方法和静态常量
*接口是一个纯粹的抽象类(接口里面所有的方法都是抽象方法)*
*接口就是一个规范,他没有提供任何是实现,具体的功能由实现接口的子类去实现。*
接口就是一个规范,可插拔(可以被替换,首先定义一个标准(接口),大家都遵守这个标准,就可以实现互相之间替换)
1、接口是一个纯粹的抽象类,接口里面的方法都是抽象方法 public abstract。
2、接口里面所有的属性public static final(可省略不写)
final:最终的意思
final变量:这个变量就不能被修改,常量 ,
接口里面: public static final double PI = 3.1415;
final类:这个类就不能被继承
final方法:这个方法就不能被重写
白炽灯的接口
计算机主板上CPU、内存
以鸟为例
public void test1() {
DaYan daYan = new DaYan();
daYan.egg();
daYan.fly();
daYan.print();
// bird是站在AbstractBird这个类角度去看new出来的DaYan这个对象,
// 所以只能看到egg()这个方法
AbstractBird bird = ***\*new\**** DaYan();
bird.egg();
// bird.fly();
// bird.print();
// 站在能不能飞IFly的角度去看DaYan,只能看到fly()这个方法
IFly fly = new DaYan();
fly.fly();
//fly.egg();
//fly.print();
fly = ***\*new\**** GeZi();
fly.fly();
}
*继承是严格的父子关系,你继承什么你就是什么:鸽子就是鸟。*
*父类是抽取了所有子类的共同特征,父类里面的属性和方法是所有子类所共有的属性和方法。*
*接口是一个标准,一般用在能不能具有某个功能。*
*把能不能飞定义称为一个接口IFly,实现了这个接口的类就具有了这个功能。*
*实现了IAlarm接口就到表具有了报警这个功能*
8.6 面向对象中的关键字
class
public
private
static
final
extends
implements
abstract
interface
this
super
8.6.1 权限修饰符
作用:限定类,属性,方法,构造方法的适用范围
包:package
管理Java代码的一个工具,在不同的包中可以定义相同的java文件
实际上,包就是硬盘上的文件夹
1)报名应该怎么定义
反域名命名法
(功能)
例如:百度地图:map.baidu.com --> 写成代码式:com.baidu.map.功能
公司类型.公司名.项目名.功能模块名.子功能
2)如何访问别的包中的类
3)在定义类时,指明这个类所在的包
public:公共的,任何地方都能访问
private:私有的,只能在类的内部访问
protected:保护的,可以在同包,以及包外的子类中访问
default什么也不写:默认的,同包可以访问
修饰符 | 类内部 | 同包 | 包外子类 | 包外非子类 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
8.6.2 final
1)修饰变量
常量不能被改变的量
2)修饰方法
最终方法:不能被子类重写
3)修饰类
最终类:不能产生子类
8.6.3 static
静态的
1)修饰属性
当使用static修饰属性时,属性就变成了静态属性
静态属性直属于类,不需要依赖对象
静态属性会在JVM加载类信息时创建,放到静态池中
使用:
可以使用类名.静态属性
也可以使用对象.静态属性(不推荐)
没有使用static修饰的属性,成为对象属性/实例属性,必须依赖于对象
2)修饰方法
当使用static修饰方法时,方法就变成了静态方法
静态方法直属于类,不需要依赖对象
使用:
可以使用类名.静态方法()
也可以使用对象.静态方法()(不推荐)
静态方法中只能****直接****使用当前类的静态属性
静态方法中只能****直接****调用当前类的静态方法
如果非要调用非静态属性,非静态方法,请先创建对象
3)修饰类
static在修饰类时,只针对内部类
匿名内部类:(线程)
8.6.4 this和super
1. this
用在类的构造方法或方法中
在构造方法中使用this,代表的是当前被创建出来的对象
在普通方法中使用this,代表的是调用当前方法中的对象
在静态方法中能否使用this? 不能
原因:因为静态方法不依赖于对象
1)
2)在构造方法中使用this();调用当前类的其他构造方法
2. super
1)构造方法中使用super();调用父类的构造方法
2)用在重写方法时
8.6.5 关于方法的重写
1、子类覆盖父类,必须保证子类权限大于父类权限才可以覆盖,否则会编译失败。
2、如果父类是private的方法,子类是默认方法,那么子类是不知道这个方法的,不是覆盖。
重载(Overload):同一个类中看同名方法的参数列表。(构造方法重载)
重写(Override):父子类方法要一模一样
8.6.6 块和静态块
什么是块?类中的花括号{}
什么是静态块?所谓静态块就是之类的使用static修饰的块
子类的静态块,块,构造方法,以及父类的静态块,块,构造方法,应该按照什么顺序执行??
使用static修饰的东西都是静态的,都是直接属于类的,不需要依赖与对象
类的所有对象都会共享它的静态资源
- 属性
1)静态属性:类属性
使用了static修饰的属性
类名:静态属性是不依赖于对象的
2)非静态属性:对象属性,实例属性
没有使用static修饰的属性
- 方法
1)静态方法:类方法
2)非静态方法:对象方法,实例方法
注意:
1)静态方法中只能调用静态方法,要调用非静态方法,要先生成一个对象,在调用
2)静态方法中只能调用静态属性,非静态属性,先生成对象
-
Static 只能修饰内部类
-
块
什么是块?类中的花括号{}
什么是静态块?所谓静态块就是之类的使用static修饰的块
在静态变量定义钱不能访问它的值
JVM创建对象
1)加载类,加载到方法区
2)声明类中的静态资源
3)从上往下一步步地执行静态代码
4)调用构造方法
5)声明类中的非静态资源
6)从上往下执行非静态代码
7)执行构造方法
java类里面定义的静态变量和静态方法是属于这个类的,不属于new出来的Student对象,但是可以被所有的对象所使用,当类加载到内存,静态属性和静态方法就可以调用,这个时候没有new任何对象。
*使用时候:*
1、静态的方法只能访问静态的方法和静态的属性(因为当前对象的实例可以没有创建,
所以静态的方法是没办法调用非静态的方法和属性的)
2、静态的方法中不能写this、super关键字(因为当前的对象实例可能还没有创建,代表当前类对象的this还有代表父类对象的super可能都还没有创建)
非静态的属性和方法(实例属性和方法)必须通过new对象访问,而静态的属性和方法
是属于类的,在类加载到内存中就可以访问,被所有对象所共享。
执行步骤:
(1)父类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
(2)子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
(3)父类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
(4)执行父类构造方法。
(5)子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
(6)执行子类构造方法。
例如:
结果:
User1.User1
Person.static initializer
User3.User3
Student.static initializer
User2.User2
Person.instance initializer
Person.Person
User4.User4
Student.instance initializer
Student.Student