面向对象编程语言
1.面向对象的初步认识
在大多数编程语言中根据解决问题的思维方式不同分为以下两种编程语言:
1.面向过程编程:关注解决问题的过程本身 ,分析出解决问题需要的每一个步骤
2.面向对象编程:它面对的事物是一个对象(具体的实体),解决问题的过程本身不关注,只需要依赖对象调用即可
以每天下楼吃饭为例:
面向过程 | 面向对象 | |
---|---|---|
1. | 下楼找餐厅 | 下楼找餐厅 |
2. | 看菜品,并熟悉掌握要吃的每一道菜的来源,制作流程,烹饪手法等具体细节 | 开吃了 (不关注具体菜的细节) |
3. | 吃这道菜 | 吃完了 |
2.Java的面向对象编程
Java是一门面向对象的编程语言(OOP),“万物皆对象”.
关于面向对象语言的两个核心概念:
(1)类和对象
类: 一类事物的抽象,属于这个事物的模板,在现实世界中类就是任意一类事物 ,在程序中类就是一个描述这类事物的类文件
对象:在这一类事物中,具体的某一个个体就是对象 ,在程序中对象就是由类new出来的有内存空间的实例
例如 :学生是一个类 ,具体的某一个学生就是对象
类和对象的关系
类和对象的关系:类是抽象的,而对象是具体的,对象是由类创建的实例(通过类new出来的引用)
类的组成:人类
类名:给某一类事物取的名字:People
静态的特征称为属性:姓名,年龄,身高,体重
动态的行为称为方法:吃饭,睡觉,打游戏
类的实现:
在一个类文件中(people),定义属性和方法
定义属性: 数据类型 属性名=[初始值]
对象的实现:
通过类名创建这个类的对象
注意:类就是一个抽象模版,在未创建具体对象之前并未分配内存空间.在其它方法中不能通过类名直接访问该类的属性和方法,需要创建该类的对象后才能访问即必须由类的对象访问 .
(2)面向对象语言的特征
面向对象的三大特征:封装,继承,多态
1.封装(隐藏 :encapsulation)
将类中成员属性进行隐藏即私有化,并提供公有的访问属性的方法,这是为了最大程度保护类中属性的隐蔽性(即不被其它对象轻易改变).同时将类中的成员方法公开.
public class People {
//属性封装
private String pname;
private int age;
private String sex;
// 提供 getter 和 setter
public String getPname(){
return pname;
}
public void setPname(String pname){
this.pname=pname;
}
public int getAge(){
return age;
}
public void setAge(int age){
// 对成员属性的隐蔽性 可以防止随意对属性更改
if(age>100 || age<0){
System.out.println("赋值的年龄不合法");
return;
}
this.age = age;
}
public String getSex(){
return sex;
}
public void setSex(String sex){
this.sex= sex;
}
// 通常为了方便给属性赋值,会提供有参构造
public People(String pname ,int age,String sex){//有参构造器
this.pname = pname;
this.age = age;
this.sex = sex;
}
public People(){//无参构造器
}
public void study(String place){//方法封装
System.out.println(name+"正在"+place+"学习")
}
}
//对于boolean类型的属性,需要使用isXxx返回属性的值。
例如:
private boolean flag;
public boolean isFlag(){//获取flag值的方法
return flag;
}
public void setFlag(boolean flag){//设置(修改)flag的值
this.flag=flag;
}
访问修饰符的权限
用于修饰类,属性,方法的关键字都称为访问修饰符 .访问修饰符决定了其它类是否可以直接访问,不能直接访问时需要通过特定的接口(即访问方法)才能访问
1.public:公共的
可被同一个项目的所有类访问(项目可见性)
2.protected:受保护的
可以被自身的类访问
可以被同包下的其他类访问
对于不同包的,存在父子关系的子类可以访问
3.[default]:默认的,可省略不写,如String name;
可以被自身类访问
可以被同包下的其他类访问
4.private 私有的
只能被自身类访问
static关键字
static表示“静态” ,它可以修饰 属性,方法,代码块 , 在一个类中除了可以定义成员属性、成员方法和构造器以外,还可以定义静态的部分(静态属性,静态方法,静态代码块)
被static修饰的组件(属性,方法,代码块)存储于方法区的静态内存区,可以通过对象访问也可以通过类名访问即不依赖对象.在类一加载时会给static修饰的属性和方法分配内存区,这个内存分布在方法区的静态内存区中,**后续所有对象操作的是同一个内存区.静态成员属于类,非静态成员属于对象.静态成员变量操作共享空间,普通成员变量(非静态成员变量)操作各自对象空间.
2.继承( inheritance)
当多个类中都存在相同的属性和行为时,可以将这些共有的属性和行为定义到一个新的类中,让其它类复用这个新类的属性和行为,这种关系就是继承关系
继承的语法:
先定义父类
public class 父类名{
}
再定义子类
public class 子类名 extends 父类名{
}
子类继承父类,子类拥有父类的哪些属性和方法?
可访问: 子类拥有(继承)父类的公有的属性和方法,同包下面的属性和方法以及不同包下的受保护的属性和方法也可以访问 (即可被访问的属性和方法:父类中public,protected和默认修饰符修饰的).
不可访问: 子类不能继承父类的私有的属性和方法以及不同包的默认属性和方法(只能通过接口访问即调用) ,以及父类的构造器(父类是无(有)参对应的子类只能调用父类的无(有)参)(通过super调用).
子类继承父类,子类如何访问父类的属性和方法:
属性:子类通过super关键字访问父类的属性,子类通过this关键字访问自身的属性
方法:子类通过super关键字访问父类的方法,子类通过this关键字访问自身的方法
注意:这里的super和this关键字可以省略,省略后子类通过“就近原则”访问属性和方法(子类中存在就访问子类的,子类中不存在,就访问父类的):
super.属性
super.方法(参数)
构造器:子类通过super([参数列表]) 调用父类的构造器, 子类通过this([参数列表])调用自身的其他构造器,其中 super([参数列表]) 必须写在子类构造器的首行
通过在子类构造器中手动调用父类的有参构造器给父类的属性赋初始值(初始化),且调用父类的有参构造器的语句要放在首行,否则子类构造器中默认调用父类的无参构造器(若存在)
多层次继承:
Java中类只能是单继承,一个类只能有一个直接父类的父类,从而可实现多层次继承
子类 -》 父类 -》 父类的父类
创建子类对象时,优先创建父类对象,再创子类对象, 执行顺序 最上层父类的构造器 -》 父类构造器 -》子类构造器。
扩展问题:当一个类中存在static元素时,它们的执行顺序是如何?
顺序: 最上层父类的静态块 - 》 父类的静态块-》 子类的静态块- 》最上层 父类的构造块和构造方法
-》父类的构造块和构造方法- 》 子类的构造块和构造方法
重写:
子类可以继承父类的方法,但是当父类的方法不能满足子类的需要时,子类可以重写父类的方法
重写的必要条件:
1、分别存在具有父子关系的不同类中
2、子类重写的方法的方法名,参数列表和返回值类型必须与父类中的方法完全一样,方法的具体实现可不一样(即只是方法体不同)
3、子类重写的方法的访问修饰符的权限必须大于或等于父类的访问修饰符的权限
注意: 子类的对象 调用父类方法时,如果子类重写了父类的方法,则执行子类的方法,没有重写执行父类的方法. (若在子类中重写父类方法,则子类调用时调用的是子类自身的方法,未重写则调用的是父类的方法,但父类调用的都是自身的方法)
3.多态(polymorphism)
继Java面向对象三大特征中封装和继承之后的第三个特征. 为了适应需求的多种变化,类可以呈现多种形态,使代码更加通用.同一种行为对于不同的事物呈现的不同形态就是多态的表现.
比如在继承关系中,对于父类中的同一方法,不同子类的对象可能呈现不同的状态
生活中的多态:同一个飞的行为,不同的事物飞的方式也不同,比如飞机飞,小鸟飞,无人机飞都不一样.
定义:同一种行为,具有多个不同的表现形式
实现多态的前提(条件):
基于继承关系或基于实现关系的
子类或实现类必须对方法进行重写(没有重写的方法 不具有多态行为)
父类的引用指向子类对象或者接口的引用指向实现类的对象
多态的对象转型:
为什么需要做类型换行呢?有时候我们需要调用子类特用的方法时必须用子类的引用,所以多态对象下父类引用需要强转.
1、子类对象转父类对象时,称为向上转型,是默认转换,自动转型
Cat cat = new Cat();
// 猫类 可以是一只动物 an4的本质还是 猫对象
Animal an4 = cat; // 子类对象转成父类对象 ,是自动转型
cat.eat();
an4.eat();
2、父类的引用转成子类对象,称为向下转型,向下转型需要强转 , 为了避免转换错误,需要先判断数据类型是否匹配
// 创建一个动物类, 将动物类转成子类引用
Animal an5 = new Cat();
// an5.catchMouse(); // 动物类型对象不能访问 它子类特有的方法
if(an5 instanceof Cat) {//instanceof : 判断该对象是否属于 这个类型
Cat cat2 = (Cat) an5;
cat2.eat();
cat2.catchMouse();
}
if(an5 instanceof Dog) {
Dog dog2 = (Dog)an5;
}else{
System.out.println("不能转成dog");
}
在多态环境中,方法和属性的调用规则:
属性: 当子类和父类中存在相同属性时 ,以 对象的左边引用类型为依据,所谓“看左边”
方法: 以当前new出来的对象为依据,如果方法重写了,就调用子类方法,如果方法没有重写就调用父类方法
静态方法:与属性类似,重写的静态方法,也是以“左边”类的引用为依据.
(3)构造器(constructor)
定义:在创建对象时被自动调用的特殊方法,也称为构造方法.在一个类中除了包含属性和方法外,还可以包含构造器即构造方法.(构造器在创建对象时使用,因此也可以通过构造器给成员属性赋初始值)
注意:构造器不是方法
每一个类都自带一个无参构造器,也可以在这个类中定义多个构造器,多个构造器之间称为“构造器重载”
(4)抽象类
定义
在已有类的基础上,由于特殊情况将该类设置为抽象的,这个类就是抽象类
语法:
public abstract class 类名{
//类的元素
}
需要定义抽象类的情况:
1、当这个类不需要创建具体的实例时(即不需要用来创建对象使用,起父类作用),可将类定义为抽象的
2、当这个类中存在没有具体实现的方法时(即没有方法体的方法),可以将这个类定义抽象的
抽象类的特点:
抽象类 不能实例化(不能new) ,通常抽象类被当作父类使用
抽象类中 可以有抽象方法( 没有方法体的方法) 也可以有普通方法(非抽象方法)
抽象类被当作父类使用时,它的子类必须重写(或者说实现)父类的抽象方法
(5)接口
定义
接口用于对某类事物的功能的声明,而没有实现具体功能.接口提供了对软件开发的标准规范.
利用接口的“多实现”完善了Java 的单一继承.
语法:
public interface 接口名{
//抽象方法定义
}
一个类实现该接口,必须实现该接口的所有抽象方法,这个类也称为实现类
public class 实现类名 implements 接口名{
实现接口的所有方法
}
接口定义的实现类对象 和 实现类定义的实现类对象的区别:
接口定义的实现类对象只能调用接口中定义的方法, 实现类定义的实现类对象既可以调用实现类里的方法,也可以调用接口里的方法.
接口中的成员组成部分的特点:
接口中定义的变量默认全部是 public static final 修饰的
接口中的静态方法可以直接调用
接口中不能写构造器(因为接口不能实例化,不需要构造器)
接口中的方法全部都是 抽象方法, 在JDK8以后可以定义default修饰的非抽象方法