1、面向对象
- 对象:用来描述客观事物的一个实体,由一组属性和方法构成。
- 面向对象:
人关注对象
人关注事物信息 - 类
确定对象将会拥有的属性和方法
类的特点:
类是对象的类型
具有相同属性和方法的一组对象的集合。 - 类和对象的关系
类是抽象的概念
对象是一个能看到的具体实体
类是对象的类型
对象是特定类型的数据
具体开发中,先定义类再实例化对象。- 对象实例化
Cat cat = new Cat();
实例化过程分两部分:
声明对象 Cat cat
实例化对象 new Cat()
注意:
1.每次new对象都会产生新的实例化对象。
2.多个对象可以指向同一块实例化空间。
3.对象必须被实例化之后才能使用。
4.对象间的引用,实际上传递的是堆内存的引用。
- 构造方法
1、构造方法与类同名,没有返回值。
2、只能在对象实例化的时候调用。
3、没有指定构造方法时,系统会自动添加无参的构造方法。
4、当指定构造方法时,无论是有参、无参的构造方法,都不会自动添加无参的构造方法。
5、一个类中可以有多个构造方法。
单一职责原则
单一职责原则(SRP:single responsibility principle),又称单一功能原则。
面向对象的五个基本原则之一(SOLID:SRP、OCP开放封闭原则、LSP里氏替换原则、DIP依赖倒置原则、ISP接口分离原则)。
它规定一个类应该只有一个发生变化的原因。
所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责就是一个类或模块应该有且只有一个改变的原因。
在软件系统中,一个类承担的职责越多,它被复用的可能性越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中。如果多个职责总是同时发生改变则可将他们封装在同一类中。
2、面向对象的特性
2.1 封装
- 将类的某些信息隐藏在类内部,不允许外部程序直接访问。
- 通过该类提供的方法来实现对隐藏信息的操作和访问。
- 隐藏对象的信息
- 流出访问的接口
特点:
1、只能通过规定的方法访问数据。
2、隐藏类的实例细节,方便修改和实现。
操作:
1、修改属性的可见性。设为private。
2、创建getter/setter方法。设为public,用于属性的读写。
3、在getter/setter方法中添加属性的控制值语句。
包
-
作用:
1、管理java文件。
2、解决同名文件冲突。 -
定义包 :
package 包名
例如:package com.xxxx.xxx;
注意:
1、必须放在java源文件的第一行
2、一个java源文件中只能有一个package语句
3、包名全小写
4、推荐命名方式:域名倒序+模块名+功能 -
导入包
语法: import 包名.类名;
例如:import com.xxx.*;
static
1、static+属性 ------ 静态属性
2、static+方法 ------ 静态方法
3、static+类 ------ 不存在
4、static+方法内局部变量 ------ 不存在
静态成员随类的加载产生,直至类销毁才回收。
静态方法
可以直接调用同类中的静态成员。
不可以直接调用同类中的非静态成员。
可以通过实例化对象后,对象调用的方式完成非静态成员调用。
代码块
通过{}可以形成代码块。
方法内的代码块称为:普通代码块。
类内的代码块称为:构造代码块。
构造代码块前+static:静态代码块。
- 代码块执行顺序
无论实例产生多少对象,静态代码块只执行一次。
构造代码块随实例化过程调用。
普通代码块随方法调用执行。
2.2 继承
概念
一种类与类之间的关系,使用已存在的类的定义作为基础建立新类。新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但是不能选择性的继承父类。满足‘A is a B’的关系。
特点
利于复用代码
缩短开发周期
继承的关系
满足‘A is a B’的关系就可以形成继承关系
如:
猫、狗是动物 —>猫狗继承自动物。
继承的实现
使用extends实现封装
单一继承,只能有一个父类
方法重写
语法规则:返回值类型、方法名、参数类型顺序个数都要与父类继承的方法相同。
方法重写vs方法重载
方法重写 | 方法重载 |
---|---|
在满足继承关系的子类中 | 在同一个类中 |
方法名、参数个数、顺序、类型与父类、返回值相同 | 方法名相同 参数个数、顺序、类型不同,返回值类型任意 |
访问修饰符的限定范围大于等于父类方法 | 访问修饰符任意 |
super关键字
访问父类成员方法 super.test()
访问父类属性 super.name;
访问父类构造方法 super()
- 子类的构造的过程中必须调用其父类的构造方法
- 如果子类的构造方法中没有显示调用父类的构造方法,则系统默认调用父类无参的构造方法
- 如果子类构造方法中既没有显示调用父类的构造方法,而父类又没有无参的构造方法,则编译出错。
- 使用super调用父类指定构造方法,必须在子类的构造方法的第一行。
super VS this
构造方法调用时,super和this不能同时出现。
this 当前类对象的引用 | super 父类对象的应用 |
---|---|
访问当前类的成员方法 | 访问父类的成员方法 |
访问当前类的成员属性 | 访问父类的成员属性 |
访问当前类的构造方法 | 访问父类的构造方法 |
不能在静态方法中使用 | 不能在静态方法中使用 |
实例化顺序
- 父类静态成员
- 子类静态成员
- 父类对象构造(属性赋值、构造代码块、构造方法)
- 子类对象构造(属性赋值、构造代码块、构造方法)
Object类
Object类是所有类的父类。
一个类没有使用extends关键字明确标识继承关系,则默认继承Object类(包括数组)
java中每个类都可以使用Object中定义的方法。
Object类的常用方法
方法 | 说明 |
---|---|
toString() | 返回当前对象本身的有关信息,按字符串对象返回 |
equals() | 比较两个对象是否是同一个对象,是则返回true |
hashCode() | 返回该对象的哈希代码值 |
getClass() | 获得当前对象所属的类信息,返回Class对象 |
final关键字
1、修饰类表示不允许被继承。
2、修饰方法表示不允许被子类重写。
不能修饰构造方法
3、修饰变量表示不允许修改。
- 方法内部的局部变量 ---- 在使用之间被初始化赋值即可
- 类中成员变量 ---- 只能在定义时或者构造代码块、构造方法中进行初始化赋值
- 基本数据类型的变量 ---- 初始化后不能更改
- 引用类型的变量 — 初始化之后不能再指向另一个对象,但指向的对象的内容是可变的。
4、可配合static使用。
5、使用final修饰可以提高性能,但会降低可扩展性。
注解
JDK1.5版本引入的特型
可以声明在包、类、属性、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、注释。
注解的分类:
按运行机制 | 按来源 |
---|---|
源码注解 | JDK的注解 |
编译时注解 | 第三方的注解 |
运行时注解 | 自定义的注解 |
元注解
2.3 多态
多态(Polymorphism)按字面量意思就是“多种状态”,是面向对象程序设计语言最核心的特征。
从一定角度来看,封装和继承几乎都是为多态而准备的。
概念
一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在程序运行期间才能决定。
多态的分类
1、编译时多态:方法重载。
2、运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定调用哪个方法则被称为运行时多态。
平时说的多态,多指运行时多态。
必要条件
- 满足继承关系
- 父类引用指向子类对象
向上转型 & 向下转型
向上转型(Upcast): 将子类型转为父类型。
- 隐式/自动类型转换,是小类型到大类型的转换。
- 对于向上的类型转换,不需要显示指定,即不需要加上前面的小括号和父类型名。
向下类型转换(Downcast):将父类型转换为子类。
- 将一个指向子类对象的父类引用赋值给一个子类的引用。
- 强制类型转换,是大类新型到小类型。
- 父类型的引用必须指向转型的子类的对象,即指向谁才能转换成谁。不然会编译出错。
通过instanceof运算符,来解决引用对象的类型,避免类型转换的安全性问题,提高代码的强壮性。
注意:
- 父类引用指向子类实例时,可以调用子类重写父类的方法以及直接继承父类的方法,无法调用子类特有的方法。
- 静态static方法属于特殊情况,静态方法只能继承,不能重写。调用的时候用谁的引用,则调用谁的版本。
3、抽象类
应用场景:
某个父类只是知道其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法。
public abstract class Person {
}
抽象方法
abstract 也可以用于方法
- 抽象方法没有方法体
- 抽象方法必须在抽象类里
- 抽象方法必须在子类中被实现,除非子类是抽象类。
public abstract void eat();
抽象类&抽象方法
- abstract 定义抽象类
- 抽象类不能直接实例化,只能被继承,可以通过向上转型完成对象实例。
- abstract 定义抽象方法,不需要具体实现。
- 包含抽象方法的类就是抽象类。
- 抽象类中可以没有抽象方法。
- 子类如果没有重写父类所有的抽象方法,则也要定义为抽象类。
- abstract 不能与static、final、private共存。
- 抽象方法在子类实现时访问权限必须大于等于父类方法。
4、接口
接口定义了某一批类所需要遵守的规范。
接口不关心这些类的内部数据,也不关心这些类里方法的实现细节,它只规定这些类里必须提供某些方法。
语法
[修饰符] interface 接口名 [extends 父接口1,父接口2 …]{
0到多个常量定义
0到多个抽象方法定义
0到多个默认方法的定义
0到多个静态方法的定义
}
接口的语法规则
- 接口及接口成员默认的访问权限为:public或默认
- 常量默认添加static final 关键字
- 抽象方法默认添加abstract关键字
- 只有default方法及static方法可以添加方法体
- 实现接口的类如果不能实现所有接口中待重写的方法,则必须设置为抽象类。
- 接口可以实现多继承,即一个子接口可以同时继承多个父接口。
- 一个类可以继承自一个父类,同时实现多个接口
- 当一个类同时实现多接口,且其中同时具有相同的方法时,实现类需要重写该方法,否则编译报错。
接口VS抽象类
相同点:
- 都可以包含抽象方法
- 都不能被实例化
- 都是引用数据类型,抽象类的子类或接口的实现 都可以向上转型
不同点:
抽象类 | 接口 |
---|---|
一个只能继承一个抽象类,即单继承 | 一个类可以实现多个接口 |
抽象类可以包含抽象方法、静态方法、构造方法等,且抽象方法前必须加abstract关键字 | 接口中可以有抽象方法,默认方法、静态方法。接口中的抽象方法默认public abstract,可省略。接口中的默认方法和静态方法可以包含方法体。 |
抽象类中可以定义实例属性,也可以定义静态常量属性 | 接口中只能定义静态常量属性,且定义时就初始化 |
5、内部类
在java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
与之对应,包含内部类的类称为外部类。
//外部类
public class Person {
int age;
public Heart getHeart(){
return new Heart();
}
// 内部类
class Heart{
public String beat(){
return "心脏在跳动";
}
}
}
内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类,更好的实现了信息隐藏。
内部类的分类
1、成员内部类
- 内部类中最常见的就是成员内部类,也称普通内部类。
- 内部类相当于外部类的一个成员变量,可以使用任意访问修饰符。
- 内部类中定义的方法可以直接访问外部类中的数据,而不受访问控制符的影响。
- 外部类不能直接使用内部类的成员和方法,需要借由内部类对象完成。
- 需要通过外部类对象来创建内部类实例。
- 如果外部类和内部类具有相同的成员,内部类默认访问自己的成员;可以通过“外部类.this.对象成员”以及“外部类.静态成员”的方式访问外部类成员。
- 编译后产生:外部类$内部类.class
2、静态内部类
- 静态内部类对象可以不依赖于外部类对象,直接创建。
- 静态内部类不能直接访问外部类的非静态成员,但可以通过“外部类对象.成员”的方式访问。
- 外部类中可以通过“类名.成员名”的方式直接访问内部类中静态成员。
3、方法内部类
- 定义在外部类方法中的内部类,也称局部内部类。
- 方法内部类只在其定义所在的方法的内部可见,即只在该方法内可以使用。
- 方法内部类不能使用访问控制符和static修饰符,但可以使用final和abstract修饰。
- 编译后产生:外部类$数字.class
4、匿名内部类
- 如果某个类的实例只是用一次,则可以将类的定义与类的创建放到一起完成,或者说在定义类的同时就创建一个类。以这种方法定义的没有名字的类称为匿名内部类。
- 适用场景
- 只用到类的一个实例
- 类再定义后马上用到
- 给类命名并不会导致代码更容易被理解 - 使用原则
不能有构造方法,可以通过构造代码块实现数据初始化。
不能定义任何静态成员、静态方法。
不能使用public、protected、private、static、abstract、final修饰。
因匿名内部类也是局部内部类,所以局部内部类的所有限制都对其生效。
一个匿名内部类一定在new的后面,用其隐含实现一个接口或继承一个类,但两者不可兼得。
只能创建匿名内部类的一个实例。
匿名内部类在编译时有系统自动起名为Outer$1.class
一般来说,匿名内部类用于继承其他类或实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
通过匿名内部类返回的是一个对象的引用,所以可以直接使用或将其赋值给一个对象变量。