目录
6. 抽象类为什么不能创建对象?自己干什么, 创建对象毫无意义
一、抽象类
1. 简介
抽象类:就是用abstract关键字修饰的类
2. 什么时候定义抽象类?
当一个类中的某个方法的具体实现不能确定就可以声明成abstract修饰的抽象方法(不能写方法体)
含有抽象方法的类, 必须定义为抽象类, 即这个类必须用abstract修饰,抽象类不一定一定含有抽象方法,
3. 什么是抽象方法?
抽象方法就是用abstract 修饰的方法,只有方法签名, 没有方法体!
4. 抽象类的作用是什么?
抽象类就是用来被子类继承、充当模板的、同时也可以提高代码复用
5. 继承抽象类需要做什么?
一个类如果继承了抽象类, 那么这个类必须重写完抽象类的全部抽象方法,或者这个类也是抽象类
6. 抽象类为什么不能创建对象?自己干什么, 创建对象毫无意义
类有的成员(成员变量、方法、构造器), 抽象类都具备
抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类
一个类继承了抽象类必须重写完抽象类的全部抽象方法, 否则这个类也必须定义成抽象类
不能用abstract修饰变量、代码块、构造器等,只能用于方法!
7. final和abstract是什么关系?
互斥关系
abstract定义的抽象类作为模板让子类继承, final定义的类不能被继承
抽象方法定义通用功能让子类重写, final定义的方法子类不能重写
二、类
1. 简介
类(class)是构造对象的模板或蓝图。
构造类是对象共同特征的抽象描述,也就是一类具有共同属性和行为的事物的抽象。
对象就是真实存在的具体实例,在Java中,必须先设计类,才能获得对象。
一个对象的状态(state,也称为特征(property)或属性(attribute)是由具有当前值的数据域来表示的。
—个对象的行为(behavior,也称为动作(action))是由方法定义的。调用对象的一个方法就是要求对象完成一
个动作。
Java类使用变量定义数据域,使用方法定义动作。
我们把对象中的数据称为实例字段(instance field),操作数据的过程称为方法(method)。
2. 表示类关系的UML符号
3. 类的组成
类由属性和行为组成
属性:在类中通过成员变量来体现(类中方法外的变量)
行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)
4. 如何定义类
类名首字母大写(满足大驼峰模式)
一个Java文件中可以定义多个class类, 但只能一个类是public修饰(称为主类)
public修饰的类名必须成为代码文件名
5. 成员变量完整定义格式
修饰符 数据类型 变量名称 = 初始化值;(一般无需指定初始化值,存在默认值)
三、对象
1. 如何得到类的对象
Java是使用使用构造方法构造对象的,如下所示:
2. 初始化对象格式
类名 对象名 = new 类名(形参列表);
3. 如何使用对象访问成员
访问属性:对象名.成员变量
访问行为:对象名.方法名(...)
4. 对象存放在哪
对象存放在堆内存
对象变量存放在栈内存, 存储的是对象在堆内存中的地址
成员变量的数据存储在对象中, 存储在堆内存中
5. 对象成员变量默认赋值规则
① 基本数据类型
byte、short、char、int、long(默认值 0)
float、double(默认值 0.0)
boolean (默认值 false)
② 引用类型
类、接口、数组、String 、对象类等(默认值 null)
6. 对象没有任何变量引用时,会怎么样?
当堆内存中的类对象或数组对象, 没有被任何变量引用(指向)时,
就会被判定为内存中的“垃圾”,同时Java存在自动垃圾回收器,会定期进行清理
7. 基本类型变量和引用类型变量的区别
我们知道对象类型就是引用数据类型,而基本数据类型我们也知道有八种,我们也知道每个变量都代表一个存储
值的内存位置。声明一个变量时,就是在告诉编译器这个变量可以存放什么类型的值。
对基本类型变量来说,对应内存所存储的值是基本类型值。
对引用类型变量来说,对应内存所存储的值是一个引用,是对象的存储地址。
8. 不可变对象和类
我们可以定义不可变类来产生不可变对象。不可变对象的内容不能被改变。
当我们创建一个对象后,它的内容是允许之后改变的。
有时候也需要创建一个一旦创建其内容就不能再改变的对象。
例如:String类就是不可变的。
如果一个类是不可变的,那么它的所有数据域必须都是私有的,而且没有对任何一个数据域提供公共的set方法。
一个类的所有数据都是私有的且没有修改器并不意味着它一定是不可变类。
要使一个类成为不可变的,它必须满足下面的要求:
① 所有数据域都是私有的。
② 没有修改器方法。
③ 没有一个返回指向可变数据域的引用的访问器方
9. 对象转换和instanceof运算符
对象的引用可以类型转换为对另外一种对象的引用,这称为对象转换,但是,转换之前需要先验证是否能够转
换,否则,直接转换可能导致类型转换异常,这种对象转换通常应用于多态,也就是父转子的时候!
10. 对象初始化流程
① new对象,先找到class文件加载到内存中
② 执行该类的static代码, 如果有的话, 静态代码块对该类进行初始化
③ 在堆内存中开辟空间, 分配内存地址
④ 在堆内存中建立对象的特有属性, 并进行默认初始化
⑤ 对对象进行显示初始化
⑥ 对对象进行构造代码块初始化
⑦ 对对象进行对应的构造函数初始化
⑧ 将对象的内存地址赋值给栈内存中的变量
四、构造器
1. 简介
构造方法在使用new操作符创建对象的时候被调用。
构造方法就是一种特殊的方法。构造方法有以下三个特殊性:
① 构造方法必须具备和所在类相同的名字
② 构造方法没有返回值类型,甚至连void也没有
③ 构造方法是在创建一个对象使用new操作符时调用的
构造方法的作用是初始化对象。
构造方法具有和定义它的类完全相同的名字。
和所有其他方法一样,构造方法也可以重载(也就是说,可以有多个同名的构造方法,但它们要有不同的签
名),这样更易于用不同的初始数据值来构造对象。
同时,构造方法又称为构造器。
2. 构造器分类
① 无参构造器
无参数构造器(默认存在):初始化对象时,成员变量的数据均采用默认值初始化
② 有参构造器
有参数构造器:初始化对象时,同时可以为对象进行赋值
3. 构造器使用细节
任何类定义出来, 默认都自带无参数构造器
一旦定义有参数构造器, 无参数构造器就不再提供
五、接口
1. 简介
接口就是用interface关键字来定义
JDK8之前接口中只能是抽象方法和常量, 没有其他成分,接口不能实例化
接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化
2. 定义格式
public interface 接口名 {
// 常量
// 抽象方法
}
3. 接口实现类
接口是用来被类实现(implements)的, 实现接口的类称为实现类(可以理解成所谓的子类)
接口可以被类单实现,也可以被类多实现
一个类实现接口, 必须重写完全部接口的全部抽象方法, 否则这个类需要定义成抽象类
4. 使用格式
修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... {
}
5. 接口与接口的关系
接口与接口的关系:多继承, 一个接口可以同时继承多个接口
类和类的关系:单继承, 一个类只能继承一个类
接口和接口的关系:多实现, 一个类可以实现多个接口
接口多继承的作用:规范合并, 整合多个接口为同一个接口, 便于子类实现
6. JDK版本升级后接口规范的变化
JDK8版本开始后, Java只对接口的成员方法进行了新增
7. 为什么新增接口规范
如何能在丰富接口功能的同时又不对子类代码进行更改呢?
允许接口中直接定义带有方法体的方法
8. JDK8新增默认实例方法
必须用default修饰, 而不是缺省修饰
需要用接口的实现类的对象来调用
default void run(){
System.out.println("--开始跑--");
}
9. JDK8新增静态方法
必须static修饰
接口的静态方法必须用本身的接口名来调用
10. JDK9新增私有实例方法
必须使用private修饰,
只能在本类中被其他的默认方法或者私有方法访问
11. 使用接口的要求
接口不能创建对象
一个类实现多个接口, 多个接口中有同样的静态方法不冲突
一个类继承了父类, 同时又实现了接口,父类中和接口中有同名方法, 默认用父类的
一个类实现了多个接口, 多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可
一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承
12. 接口特点
接口中的所有方法都是抽象方法,不能包含方法的实现
接口中的所有方法的访问修饰权限都是public,不写并不是默认访问权限,而是public
接口不能被实例化
接口的子类必须要实现接口中的所有方法,跟抽象类有所不同,抽象类中的抽象方法必须要被子类实现,普通方
法可以不重写
子类可以实现多个接口
接口中的变量都是静态常量,如果没有使用static关键字修饰,它默认也表示静态常量,不用final关键字修饰,
默认也是常量,不能修改
接口中的方法和常量无论是否添加public修饰,默认的权限有且仅有一个,就是public
13. 抽象类和接口的区别
抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。
抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象
一个类可以实现多个接口,但是只能继承一个父类。
Java只允许为类的扩展做单一继承,但是允许使用做多重扩展。
14. 抽象类和接口的应用场景
如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧
如果你想实现多重继承,那么你必须使用接口。
由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它
如果基本功能在不断改变,那么就需要使用抽象类。
如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
六、四种内部类
1. 简介
内部类就是定义在一个类里面的类,里面的类可以理解成(寄生), 外部类可以理解成(宿主
2. 格式
public class People{
// 内部类
public class Heart{
}
}
3. 内部类的使用场景与作用
当一个事物的内部, 还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务
内部类通常可以方便访问外部类的成员, 包括私有的成员
内部类提供了更好的封装性, 内部类本身就可以用private protectecd等修饰符修饰 封装性可以做更多控制!
我们外部类只能是缺省,public修饰,文件名以public修饰的类名为准
4. 内部类的分类
4.1 静态内部类
1. 简介
静态内部类就是有static修饰的内部类, 属于外部类本身
静态内部类的特点和使用与普通类是完全一样,类有的成分它都有, 只是位置在别人里面而已
2. 格式
public class Outer{
// 静态成员内部类
public static class Inner{
}
}
3. 静态内部类创建对象的格式
格式:外部类名.内部类名 对象名 = new 外部类名.内部类构造器;
例如:Outer.Inner in = new Outer.Inner();
静态内部类中是否可以直接访问外部类的静态成员?
可以, 外部类的静态成员只有一份可以被共享访问
静态内部类中是否可以直接访问外部类的实例成员?
不可以的, 外部类的实例成员必须用外部类对象访问
4.2 成员内部类
1. 简介
成员内部类就是无static修饰的内部类, 属于外部类的对象
JDK16之前,成员内部类中不能定义静态成员,JDK 16开始可以定义静态成员
public class Outer {
// 成员内部类
public class Inner {
}
}
2. 成员内部类创建对象的格式
格式:外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器();
例如:Outer.Inner in = new Outer().new Inner();
成员内部类中可以直接访问外部类的静态成员,外部类的静态成员只有一份可以被共享访问
成员内部类的实例方法中可以直接访问外部类的实例成员,
因为必须先有外部类对象,才能有成员内部类对象, 所以可以直接访问外部类对象的实例成员
4.3 局部内部类
1. 定义位置
在一个类的成员方法中。或者说,定义在一个成员方法的中的类就是局部内部类。
2. 文件名
外部类$N内部类.class
3. 特点
1、不能使用任何的访问修饰符。
2、会生成两个.class文件,一个是Outer.class ,另一个是Outer$LocalInner.class。
3、局部内部类只能访问方法中声明的final类型的变量。
4. 案例
4.4 匿名内部类
1. 简介
本质上是一个没有名字的局部内部类, 定义在方法中、代码块、构造器等执行体中
2. 作用
方便创建子类对象,目的为了简化代码编写
3. 格式
new 类|抽象类名|或者接口名() {
重写方法;
};
4. 特点
匿名内部类是一个没有名字的内部类
匿名内部类写出来就会产生一个匿名内部类的对象
匿名内部类的对象类型相当于是当前new的那个的类型的子类类型
5. 形式
匿名内部类可以作为方法的实际参数进行传输