面向对象
1.1基本概念
和面向过程一样,都是一种语言设计的思想。
面向过程(procedure oriented programming 缩写POP):解决问题思路:一步一步实现。针对不同的功能创造相应的函数,并将它们串联起来互相调用。面向过程直接关注流程,核心就是一个个函数。(代表语言C语言)
现在多数语言都引入了面向对象(object oriented programming 缩写OOP)的思想 。 (java,c++,sql等都引入了面向对象):以分类的思想来解决问题
例:把大象装进冰箱
面向过程:1.打开冰箱门。2.把大象放进冰箱。3.关闭冰箱门。
面向对象:分为两类:冰箱和动物。类设计时有继承语法让大象类继承动物类。在各自类里面定义与其相关的所有功能。
也就是说,面向过程的语言更具有针对性,它的思想就是把提出的问题解决掉,但是想去扩展就比较麻烦。面向对象的语言更具有范围性,解决这个问题只是其中一部分,它会尽可能的去扩展去覆盖其他问题。根据问题只需要对相应的类进行相应的操作即可。
面向对象无法取代面向过程,它们相辅相成。面向对象关注于从宏观上把握事物之间的关系,实现某个具体细节仍然需要面向过程。
面向语言的三大特征:封装,继承,多态
1.2类
1.2.1概念
类是对某一类事物进行抽象的定义,是一种模板。不能直接使用模板。
比如我们发现小鸟都会飞且有翅膀,我们便将有翅膀会飞的都认为是鸟类,那么有翅膀会飞的概念就成了一个模板。
1.2.2创建类
发现类-->解决问题,发现这类问题中的共性类。-->定义类中的内容。
类的声明格式为:[访问权限修饰符] [修饰符] class Car{ }
访问修饰符有两种 public,无(默认)即default
修饰符:final,abstract,根据需要选择添加或不添加修饰符。
关键字:class用来定义一个类
Java类名的命名规范: 类名首字母大写
1.2.3类的结构:
1.成员变量:事物属性的描述; 比如汽车有名字,车牌等,名字,车牌这些就属于汽车的属性
2.方法:事物的行为;(可以做的事情) 比如汽车可以跑,我们定义一个方法来实现它可以跑的行为
3.构造方法:初始化对象;
4.内部类: 即在类体中声明的类。
5.块:一段没有名称的代码块
1.3对象
使用的是由类这个模板创建出来的具体存在的实例(对象)。
类就相当于是图纸,图纸是不能直接拿来使用的,对象就相当于一件实际存在的物品,这个物品是以类这个图纸作为模板创建出来的
例如:
Car x1 = new Car();
Car x1:声明一个Car类型的变量x1.
new Car():使用new + Car类构造方法创建对象.
= :将右边创建的对象地址 赋给 左边的x1.
创建对象时给计算机内存中开辟不同的内存空间,将类里面的成员变量复制过去,方法不会复制过去,它是引用类里面的方法的地址。
1.4类中定义变量
1.4.1成员变量
位置:成员变量在方法外,类体内。
数据类型:成员变量可以使用java的任意数据类型。
赋值:成员变量可以不用初始赋值,java会为其赋默认值。(因为有构造方法)
成员变量可以被成员方法,构造方法,代码块进行访问。
作用域:成员变量范围为整个类体
生命周期:对象被创建时被创造,对象被回收被销毁。
1.4.2局部变量
位置:在方法体内。(成员方法,构造方法,代码块) 方法里的参数也算作局部变量。
数据类型:局部变量可以使用java的任意数据类型。
赋值: 局部变量不会被默认赋值。
作用域:只能作用在所在的代码块内。
生命周期:方法被调用时被创造,方法结束被销毁。、
1.5类中定义方法
1.5.1成员方法
类中定义的方法。
格式: 修饰符 返回值类型 方法名( 参数列表) {
方法体语句;
[return 返回值]
}
加static 通过类名调用,不加通过对象调用
1.5.2构造方法
构造方法名字与类名相同,且无需返回值,也不需要void修饰;类中默认有一个无参的方法。一旦类中定义有参的构造方法,那么默认无参构造方法会消失;如果需要就需要显示定义出来。
作用:为新创建的对象成员变量进行初始化赋值。
一个类中可以有多个构造方法
我们在创建一个类时其实就调用了一次类的默认无参构造方法
为什么类中成员变量可以不用赋值?
就是因为这个无参构造方法给他赋了默认值。
为什么不直接给成员变量赋值?
因为类是一个模板,如果给其直接赋值,那么从这个模板里创建出来的对象的变量都会是这个值。比如给一个银行类赋值名字叫中国银行,那么创建出来的对象的名字都叫中国银行,但很明显我们不想让这种情况出现。 于是我们有了参构造方法,创建时利用有参构造方法给创建的对象的变量赋想要的值。 构造方法可以有多个,但构造方法的名字都只能叫这个类的名字,这时候我们就提出了方法重载的概念去分辨这些构造方法。
1.5.3方法重载
当一个类中出现了多个名称相同的方法。
可以用参数(参数的数量,类型,顺序)都可以来区分调用的具体是哪个方法。
方法重载和返回值类型没有关系。
例:哪个选项和show函数重载
class Demo{
void show(int a,int b,float c){ }
}
A.void show(int a,float c,int b){ }
B.void show(int a,int b,float c){ }
C.int show(int a,float c,int b){ return a; }
D.int show(int a,float c){ return a; }
首先方法重载和返回值类型没有关系,只需要看参数。A选项b,c的参数类型和原来不同,正确。C选项参数顺序和原来不同,正确,D选项参数数量和原来不同,正确。 B选项无变化,错误。
所以选择A,C,D
1.6对象与引用
Car bm= new Car();通常把这条语句的动作称之为创建一个对象,其实,它包含了三个动作。
1)右边的“new Car()”,是以Car类为模板,在堆空间里创建一个Car类对象。
2)左边的“Car bm”创建了一个Car类型引用变量。所谓Car类的引用,就是以后可以用来指向Car对象的对象引用。
3)”=”操作符使对象引用指向刚创建的那个Car对象。
我们可以把这条语句拆成两部分:Car bm; bm= new Car();这样写,就比较清楚了,有两个实体:一是对象引用变量,一是对象本身。
2.关键字this
this表示正在调用的当前对象
this.成员变量名 :来引用成员变量,来区分同名的成员变量与局部变量。
3.关键字static
静态,修饰类的 属性,代码块,内部类,方法。
3.1变量:
所有对象一样的成员变量,都可以用static来修饰,称为类变量。内存中只有一份,随着类的加载而加载初始化。
比如现在创建一个关于人的类,创建对象时的国家都想定义为中国,那么可以直接在类里面的成员变量中直接定义一个国家成员变量为中国。这样在创建每个新对象时可以直接访问类中的该成员变量,不需要复刻出来占用空间。
3.2方法:
static修饰的方法被称为类方法,也通过类名访问,随着类的加载而加载。 静态方法里面不能访问非静态,因为静态的先加载,非静态的需要创建对象再加载。
静态方法里访问静态变量的过程中没有创建对象,和面向过程一样。
创建类的对象,会先加载类(加载其中的静态成员),与静态位置无关。
类发生加载动作的两种情况:创建对象,调用类中的静态成员。
3.3代码块:
类中定义的代码块,没有名字,满足条件自动调用。
实例代码块:在创建类时会自动调用。实例代码块先于构造方法执行。
静态代码块:在类被加载时只调用一次。
4.访问权限修饰符
4.1包
像文件夹一样组织管理文件;包像是类的命名空间,组织管理类。
一个真正的类名=包名+包里面的类名。
作用:避免重复类名,按不同内容管理类,控制访问权限。
4.1.1包的命名:
名字全部小写。
第一级:com项目类型 org开源类型 gov政府 edu教育
第二级:公司类型
第三级:javaoop项目名称
第四级:按照不同功能管理命名
import 导入其他包的类
之前使用Scanner类时就需要用import导入java.util包的Scanner
java.lang包下的类使用时不需要导入。
4.2四个访问权限修饰符
1)public :公共权限 修饰类、属性、方法。可以被任意类访问
如果用public修饰类,类的名字和文件的名字需要一致。一个java文件中只有一个public修饰的类。
其实你会发现,每次创建一个class文件后,会自动产生一个与文件名相同的public修饰的类。
2)protected:受保护的权限 修饰属性、方法。可以被同包类访问,如果不是同包类,必须是该类的子类才可以访问。
3)default:同包权限 修饰类、属性、方法。只能被同包的类访问
4)private:私有权限 修饰属性、方法。 只能在本类中访问
封装
通过访问权限修饰符,使得类中的信息是否对外可见
设计模式
一系列解决问题方案
单例设计模式:解决只让一个类在一个程序中创建一个唯一的对象。
6.继承
主要就是为了代码重用和代码扩展。
代码重用:子继承父,继承后子可以使用父的功能,不需要重复定义。
代码扩展:子在自己类中扩展自己特有的功能。
基类(定义共有的属性和行为,让新类去继承)-->派生出新类
子类名 extends 父类名 可以多层继承,一个类可以被多个类继承,但不能一个类继承多个类。
当一个类没有继承其他类时,默认继承Object类。Object类是java中所有类的基类。
个人理解:其实就相当于模板的模板,比如人类相当于一个基类,各个不同国家的人可以看成人类的基类,中国各个不同地域的人可以看成不同国家的人的基类......
6.1继承中构造方法
子类构造方法会先调用父类的构造方法
使用super关键字调用父类任意一个构造方法,必须写在构造方法的第一行。确保父类成员进行初始化。 super访问父类的成员,this访问当前对象的成员
子类构造方法中,默认有调用,使用super()调用父亲的无参构造。
默认调用无参构造方法
7.方法重写
父类方法实现不能满足子类需求时,可以对方法进行重写。
在子类中将父类的方法不改变结构重新定义。不改变结构的意思是方法名相同,参数相同,返回值相同,访问权限不能小于父类权限。
构造方法,静态方法不能重写,成员变量不存在重写。
构造方法为什么不能重写?
因为构造方法要与类名相同,在子类中时构造方法就要与子类类名相同,在父类中亦如此。 但重写要求方法名要相同,很明显构造方法达不到该要求。
@override注解标签,表示此方法是从父类中重写而来,编译期间会在语法上进行校验
override可加可不加,加上必须使用方法重写。不加有可能表示方法重载。
例:
5.3.现有:
class Over{
int dolt (long x){ return 3; }
}
class Under extends Over{
7. }
和四个方法:
short dolt (int y) { return 4; }
int dolt(long x, long y) { return 4; }
private int dolt(short y) { return 4; }
protected int dolt (long x) { return 4; }
分别插入到第6行,有几个可以通过编译?
A. 1
B. 2
C. 3
D. 4
以上四个方法子类继承父类,子类加载的时候也加载了父类,同名方法之间构成了重载;如果加上了override ,会强制认为是方法重写,就会出现错误
8.抽象类
8.1抽象方法
即概念方法,没有方法体,不能使用。用来定义规范,功能。
关键字abstract修饰。
8.2抽象类
只要有一个抽象方法,abstract修饰的类就是抽象类。类中有抽象方法,该类就必须是一个抽象类。
越顶级的类一般都是抽象的,只定义功能不具体实现,让子类来继承实现
抽象类除了不能创建对象外,类的其他功能都有。
抽象类一般作为基类被其他类继承,在子类里将抽象方法重写
子类都不一样设计为抽象方法
子类都一样是非抽象
9.多态
多种状态
同一事物不同时刻表现不同状态
三个条件:1.有继承(包括接口实现)2.有重写 3.父类引用指向子类对象
因为继承,父类才能指向子类对象。(子类对象赋给父类变量,向上转型)
缺点:子类本身特有方法调用不到。父类有了才能调用,所以强调方法重写。
解决方法:必要时再变回去。(即父类对象赋给子类变量,向下转型)
就像是数据转换一样,假设父类和子类是两种数据类型,父类的内存的空间比子类更大,向上转型时,可以直接赋值,向下转型就需要强制转换。
即创建对象时引用类型是父类,对象是子类。执行的方法是子类中自己的方法。
非静态成员方法:编译看左边,运行看右边。
对于成员变量以及静态成员方法:编译运行都看左边。
非多态程序设计:每次扩展都需要做出改动。
多态增强代码的扩展性。
instanceof判断类型运行时所表示的对象是否为指定类型。
10.final关键字
用于声明属性,方法,类
属性:修饰局部变量(包含形参),一旦赋值就不可改变。修饰成员变量两种赋值方式:
1.直接赋值。且后面值无法改变。这种情况适合用static修饰。
2.必须在构造方法中进行赋值。便于对象赋值
方法:不能被子类重写。
类:不能被其他类继承。一般系统中的类有很多是final修饰的。
11.接口
接口像是规则,规范,用来定义功能,更彻底的抽象。不能被创建对象,不能有成员变量,构造方法。jdk8之后可以定义抽象方法,静态变量,默认方法,静态方法。
面向接口编程就像是面向抽象编程。
interface修饰的是接口,class修饰的是类
定义变量时默认存在public static final
定义方法时默认存在public abstract
接口和接口:接口可以继承多个接口
接口和类:接口也是抽象,设计接口也是为了让其他类继承实现。
即同类型之间是继承(类对类,接口对接口),不同之间是实现(类对接口)
类实现接口:implements。要么重写接口中所有的抽象方法。要么将此类也声明抽象类。
一个类可以实现多个接口。