第四章、类和接口
一、类
1.什么是类
-
类 : 是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类
事物。- 现实中,描述一类事物
- 属性 : 就是该事物的状态信息。
- 行为 : 就是该事物能够做什么。
- 现实中,描述一类事物
-
内部类:如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。
- 例如 : 身体和心·脏的关系。又如 : 汽车和发动机的关系。
分类 :
- 1.成员内部类
成员内部类的定义格式:
修饰符class外部类名称{
修饰符class内部类名称{
//...
}
// ...
}
如何使用成员内部类 ? 有两种方式:
1.间接方式 : 在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
2.直接方式, 公式 : 外部类名称.内部类名称对象名= new 外部类名称( ).new内部类名称( )
;
注意: 内用外,随意访问 ; 外用内,需要内部类对象。
内部类使用外部类成员变量
如果出现了重名现象,那么格式是 : 外部类名称.this.外部类成员变量名
如 :
public class Outer {
int num = 10;//外部类的成员变量
public class Inner /*extends 0bject*/ {
int num = 20; //内部类的成员变量
public void methodInner() {
int num = 30;//内部类方法的局部变量
System.out.println(num); //局部变量,就近原则
System.out.println(this.num); //内部类的成员变量
System.out.print1n(outer.this.num);//外部类的成员变量
}
}
}
- 2.局部内部类(包含匿名内部类) : 如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
//“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
//定义格式:
修饰符 class 外部类名称{
修饰符 返回值类型 外部类方法名称(参数列表){
class 局部内部类名称{
//....
}
}
局部内部类中,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效 final 的】。
备注:从Java 8+开始,只要局部变量事实不变,那么final关键字可以省略。
原因 :
1.new出来的对象在堆内存当中。
2.局部变量是跟着方法走的,在栈内存当中。
3.方法运行结束之后,立刻出栈,局部变量就会立刻消失。
4.但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
-
匿名内部类
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,
那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。
//匿名内部类的定义格式:
接口名称对象名 = new 接口名称(){
//覆盖重写所有抽象方法
};
对格式 “new 接口名称( ){…}” 进行解析;
1. new代表创建对象的动作
2. 接口名称就是匿名内部类需要实现哪个接口
3. {…} 这才是匿名内部类的内容
另外还要注意几点问题:
1.匿名内部类,在【创建对象】的时候,只能使用唯一—次。
如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了。
2.匿名对象,在【调用方法】的时候,只能调用唯一—次。
如果希望同一个对象,调用多次方法,那么必须给对象起个名字。
3.匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】
4.强调: 匿名内部类和匿名对象不是一回事! ! !
2.什么是对象
- 对象 : 是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。
3.类的定义格式
public class className {
//成员变量
//成员方法
}
- 定义类 : 就是定义类的成员,包括成员变量和成员方法。
- 成员变量 : 和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外。
- 成员方法 : 和以前定义方法几乎是一样的。
4.修饰符
> | public | protected | (default) | private |
---|---|---|---|---|
同一个类(我自己) | YES | YES | YES | YES |
同一个包(我邻居) | YES | YES | YES | NO |
石同包子类(我儿子) | YES | YES | NO | NO |
不同包非子类(陌生人) | YES | NO | NO | NO |
注意事项 : (default)并不是关键字"default",而是根本不写。
1.外部类 : public / (default)
2.成员内部类 : public / protected / (defqult) / private
3.局部内部类 : 什么都不能写
6.对象的创建及使用
通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用。
-
导包 : 也就是指出需要使用的类,在什么位置。
import 包名称.类名称;
import cn.itcast.daye6.demoe1. Student;
对于和当前类属于同一个包的情况,可以省略导包语句不写。 -
创建
//类名称 对象名= new 类名称(); 例如: Student stu = new Student();
-
使用
- 分为两种情况:
- 使用成员变量 : 对象名.成员变量名
- 用成员方法 : 对象名.成员方法名(参数)
- 分为两种情况:
二、总结
1.继承关系中,父子类构造函数的调用关系
- 子类构造方法当中有一个默认隐含的 super() 调用,所以一定是先调用的父类构造,后执行的子类构造。
- 子类构造可以通过super关键字来调用父类(重载)构造。
- super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
- 总结 :
- 子类必须调用父类构造方法,不写则赠送 super() ;
- 写了则用写的指定的super调用,super只能有一个,还必须是第一行。
2.static关键字的使用要点
- static 修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。
- static 修饰成员变量,这个变量也称作静态静态成员变量。如果加上final关键字,就会不可改变。
- 静态变量属于类,它当且仅当在类初次加载时会被初始化。
- 静态变量定义时必须初始化。
- 存放于 方法区内存的 静态区中。
- static 和 final的异同
- 共同点:static和final在编译时直接分配内存。
- 区别:
- (赋值)静态成员变量的值在运行时可以更改赋值,而常量的值是不可改变的,运行一开始已经固定,之后修改会报错。
- (内存)静态成员变量存放在方法区内存 的 静态区中。final 常量算是一个普通的只读变量,随函数结束而结束。
- static代码块,static块可以置于类中的任何地方,类中可以有多个static块。
- 在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
- 很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行
- 如果没有 static关键字,那么必须首先创建对象,然后通过对象才能使用它。
- 如果有 static关键字,那么不需要创建对象,直接就能通过类名称来使用它。
- 无论是成员变量,还是成员方法。如果有了static,都推荐使用类名称进行调用。
- 静态变量 : 类名称.静态变量
静态方法 : 类名称.静态方法( )
- 静态变量 : 类名称.静态变量
- 注意事项:
- 静态不能直接访问非静态。
- 因为在内存当中是【先】有的静态内容,【后】有的非静态内容。“先人不知道后人,但是后人知道先人。
- 静态方法当中不能用this。
- 因为this代表当前对象,通过谁调用的方法,谁就是当前对象。
- 静态不能直接访问非静态。
3.this关键字总结
- super关键字用来访问父类内容,而this关键字用来访问本类内容。
- 用法也有三种:
- 在本类的成员方法中,访问本类的成员变量。
- 在本类的成员方法中,访问本类的另一个成员方法。
- 在本类的构造方法中,访问本类的另一个构造方法。
- 在第三种用法当中要注意:
- this ( …) 调用也必须是构造方法的第一个句,唯一一个。
- super和this两种构造调用,不能同时使用。
4.supper关键字总结
- super关键字的用法有三种:
- 在子类的成员方法中,访问父类的成员变量。
- 在子类的成员方法中,访问父类的成员方法。
- 在子类的构造方法中,访问父类的构造方法。
5.this、supper关键字内存变化图
6.final关键字总结
此关键字代表最终、不可改变的。常见四种用法:
- 1.可以用来修饰一个类
//含义:当前这个类不能有任何的子类。
//注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写
public final class类名称{
}
- 2.可以用来修饰一个方法
//当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。
//注意事项:对于类、方法来说, abstract关键字和final关键字不能同时使用,因为矛盾。
修饰符 final 返回值类型 方法名称(参数列表){
//方法体
}
- 3.还可以用来修饰一个局部变量
//一旦使用finaL用来修饰局部变量,那么这个变量就不能进行更改。[“一次赋值,终生不变”]
//对于基本类型来说,不可变说的是变量当中的 数据 不可改变
//对于引用类型来说,不可变说的是变量当中的 地址值 不可改变
例如:final int num2 = 200;
或者:final int num3;
num3 = 30;
-
4.还可以用来修饰一个成员变量
- 对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变。
- 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
- 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
- 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。
- 对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变。
二、接口
一、基础知识
二、接口总结:[在Java 9+版本中,接口的内容可以有]
1.成员变量其实是常量
[public] [static] [final] 数据类型常量名称 数据值;
注意 : 常量必须进行赋值,而且一旦赋值不能改变。常量名称完全大写,驼峰命名法+下划线。
2.接口中最重要的就是抽象方法
[public] [abstract] 返回值类型 方法名称(参数列表);
注意 : 实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。
3.从Java 8开始,接口里允许定义默认方法
[public] default 返回值类型 方法名称(参数列表){ 方法体 }
注意 : 默认方法也可以被覆盖重写
4.从Java 8开始,接口里允许定义静态方法
[public] static 返回值类型 方法名称(参数列表){方法体}
注意 : 应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法
5.从Java 9开始,接口里允许定义私有方法
//普通私有方法
private 返回值类型 方法名称(参数列表){方法体}
//静态私有方法
private static 返回值类型 方法名称(参数列表){方法体}
注意: private的方法只有接口自己才能调用,不能被实现类或别人使用。
三、接口使用注意事项 :
1. 接口是没有静态代码块或者构造方法的。
2. 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
public class MyInterfaceImpl implements MyInterfaceA,MyInterfaceB {
//覆盖重写所有抽象方法
}
3.如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
4.如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
5.如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
6.一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
四、封装、继承、多态性解析
一、封装性 :
- 修饰符 属性、方法
二、继承性
-
extends
-
继承主要解决的问题就是 : 共性抽取。
-
子类可以拥有父类的“内容”
-
子类还可以拥有自己专有的内容。
-
三、多态性
- 代码当中多态性的体现 : 父类引用指向子类对象。
格式 :- 父类名称 对象名 = new 子类名称 ( );
- 或 :接口名称 对象名 = new 实现类名称( );