Java语言面向对象
- (一)面向对象
- (二)Scanner类
- (三)Random类
- (四)ArrayList类
- (五)String类
- (六)static关键字
- (七)Arrays类
- (八)Math类
- (九)继承
- (十)super与this关键字
- (十一)Java继承的三个特点
- (十二)抽象
- (十三)接口
- (十四)多态
- (十五)对象的向上和向下转型
- (十六)final关键字
- (十七)权限
- (十八)内部类
(一)面向对象
一、面向对象:
1、概念:是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
2、面向对象与面向过程的区别:
1)面向过程:强调步骤;
2)面向对象:强调对象;
3、三大特征:封装、继承、多态;
4、类与对象的关系:
1)类 :是一组相关属性和行为的集合。(可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。)
2)类的组成部分:属性、行为。
注:属性:是什么;(在类中为姓名、年龄)
行为:能做什么;(在例中为睡觉、学习、吃饭)
对应到Java的类当中:
成员变量(属性):
String name; // 姓名
int age; // 年龄
成员方法(行为):
public void eat() {} // 吃饭
public void sleep() {} // 睡觉
public void study() {} // 学习、
注意事项:
(1) 成员变量是直接定义在类中的,在方法外边。
(2) 成员方法不要写static关键字。
注:通常类不能直接使用,需要根据类创建对象,才能使用。
3)导包:支出需要使用的类在什么位置;
格式:import 包名称.类名称;
eg:improt.day06.Demo01.Student;
对与当前的类属于同一个包时,可以省略语句不写。
4)创建:
格式:类名称 对象名=new 类名称();
Student stu = new Student();
5)使用(分为两种情况):
(1)使用成员变量:对象名.成员变量名
(2)使用成员方法:对象名.成员方法名(参数)
(想用谁,就用对象名点儿谁。)
注意事项:
如果成员变量没有进行赋值,将会有一个默认值(规则和数组一样)。
6)关系:
类是对一类事物的描述,是抽象的。
对象是一类事物的实例,是具体的。
类是对象的模板,对象是类的实体 。
5、一个对象的内存图:
6、两个对象使用通过一个方法的内存图:
7、两个引用指向同一个对象的内存图:
8、使用对象类型作为方法的参数:
9、使用对象类型作为方法的返回值:
10、成员变量和局部变量的区别:
1)定义的位置不同【重点】
局部变量:在方法的内部
成员变量:在方法的外部,直接写在类中
2)作用范围不同【重点】
局部变量:只能在方法中使用
成员变量:整个类全都可以使用
3)默认值不同【重点】
局部变量:没有默认值,想要使用必须手动赋值
成员变量:如果没有赋值,会有默认值(规则和数组一样)
4)内存的位置不同
局部变量:位于栈内存
成员变量:位于堆内存
5)生命周期不同
局部变量:随着方法进栈而诞生,随着方法出栈而消失
成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失
11、面向对象三大特征值封装性:
1)封装性在Java当中的体现:
方法就是一种封装
关键字private也是一种封装
2)含义:将一些细节信息隐藏起来,对于外界不可见。
3)原则:将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。
12、Private关键字的作用与使用:
1)private的含义:
(1) private是一个权限修饰符,代表最小权限。
(2) 可以修饰成员变量和成员方法。
(3)被private修饰后的成员变量和成员方法,只在本类中才能访问。
2)步骤:step1. 使用 private 关键字来修饰成员变量。
step2. 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。
3)问题描述:定义Person的年龄时,无法阻止不合理的数值被设置进来。
解决方案:用private关键字将需要保护的成员变量进行修饰。
一旦使用了private进行修饰,那么本类当中仍然可以随意访问;
但是,超出了本类范围之外就不能再直接访问。
4)间接访问private成员变量,就是定义一对Getter/Setter方法
必须叫setXxx或者是getXxx命名规则。
(1)Getter:不能有参数,返回值类型和成员变量对应;
(2)Setter:不能有返回值,参数类型和成员变量对应。
注:对于基本类型当中的boolean值,Getter方法一定要写成isXxx的形式,而setXxx规则不变。【重点】
13、This关键字的作用:
1)含义:this代表所在类的当前对象的引用(地址值),即对象自己的引用。
备注:方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。(“通过谁调用的方法,谁就是this。”)
2)作用:在重名的情况下起到区分的作用。
3)注意:当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,优先使用局部变量。
4)如果需要访问本类当中的成员变量,需要使用格式:
this.成员变量名
14、构造方法:当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
1)含义:构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法。
2)格式:
public 类名称(参数类型 参数名称) {
方法体
}
3)注意事项:
(1)构造方法的名称必须和所在类名称完全一样(连大小写都要一样)
(2)构造方法不要写返回值类型(连void都不写)
(3) 构造方法不能return一个具体的返回值
(4)如果没有编写任何构造方法,那么编译器将会默认赠送一个构造方法,没有参数、方法体什么事情都不做。
public Student() {}
(5)一旦编写了至少一个构造方法,那么编译器将不再赠送。
(6)构造方法也是可以进行重载的。
重载:方法名称相同,参数列表不同。
15、定义一个标准的类—JavaBean:
1)一个标准的类的四个组成部分:
(1) 所有的成员变量都要使用private关键字修饰
(2) 为每一个成员变量编写一对儿Getter/Setter方法
(3) 编写一个无参数的构造方法
(4)编写一个全参数的构造方法
(二)Scanner类
1、含义:一个可以解析基本类型和字符串的简单文本扫描器。
2、功能:可以实现键盘输入数据,到程序当中。
3、引用类型的一般使用步骤:
step1. 导包:
import 包路径.类名称;
如果需要使用的目标类,和当前类位于同一个包下,则可以省略导包语句不写。
只有java.lang包下的内容不需要导包,其他的包都需要import语句。
step2. 创建:
类名称 对象名 = new 类名称();
step3. 使用:
对象名.成员方法名()
获取键盘输入的一个int数字:int num = sc.nextInt();
// 备注:System.in代表从键盘进行输入
Scanner sc=new Scanner(System.in);
4、匿名对象:
1)创建对象的标准格式:
类名称 对象名 = new 类名称();
2) 含义:就是只有右边的对象,没有左边的名字和赋值运算符。
注意事项:匿名对象只能使用唯一的一次,下次再用不得不再创建一个新对象。
使用建议:如果确定有一个对象只需要使用唯一的一次,就可以用匿名对象。
(三)Random类
1、功能:用来生成随机数字。
2、步骤:
step1. 导包
import java.util.Random;
step2. 创建
Random r = new Random(); // 小括号当中留空即可
step3. 使用
获取一个随机的int数字(范围是int所有范围,有正负两种):int num = r.nextInt()
获取一个随机的int数字(参数代表了范围,左闭右开区间):int num = r.nextInt(3)
实际上代表的含义是:[0,3),也就是0~2
3、限定随机数范围与个数:
Random r = new Random();
for (int i = 0; i < 100; i++) {
int num = r.nextInt(10);
System.out.println(num);
}
(四)ArrayList类
1、对象数组:
1)缺点:一旦创建,程序运行期间长度不可以发生改变。
2)题目:定义一个数组,用来存储3个Person对象。
2、ArrayList集合概述和基本使用:
数组的长度不可以发生改变。
但是ArrayList集合的长度是可以随意变化的。
ArryList中有一个尖括号代表泛型。
泛型:装在集合当中的所有元素,全都是统一的什么类型。
注意:泛型只能是引用类型,不能是基本类型。
注意事项:
1)对于ArrayList集合来说,直接打印得到的不是地址值,而是内容。
2)如果内容是空,得到的是空的中括号:[]
ArrayList<String> list =new ArrayList<>();
System.out.println(list);
list.add("赵桥");
System.out.println(list);
3、ArrayList集合的常用方法和遍历:
public boolean add(E e):向集合当中添加元素,参数的类型和泛型一致。返回值代表添加是否成功。
备注:对于ArrayList集合,add添加动作一定是成功的,所以返回值可用可不用;但是对于其他集合来说,add添加动作不一定成功。
public E get(int index):从集合当中获取元素,参数是索引编号,返回值就是对应位置的元素。
public E remove(int index):从集合当中删除元素,参数是索引编号,返回值就是被删除掉的元素。
public int size():获取集合的尺寸长度,返回值是集合中包含的元素个数。
4、ArrayList集合存储基本数据:
如果向集合ArrayList当中存储基本类型数据,必须使用基本类型对应的“包装类”。
基本类型 包装类(引用类型,包装类都位于java.lang包下)
byte Byte
short Short
int Integer 【特殊】
long Long
float Float
double Double
char Character 【特殊】
boolean Boolean
(从JDK 1.5+开始,支持自动装箱、自动拆箱。)
1)自动装箱:基本类型 --> 包装类型
2)自动拆箱:包装类型 --> 基本类型
(五)String类
1、概念:程序中所有的双引号字符串都是String类的对象(无需考虑new)。
2、特点:
1)字符串的内容永远不可改变。【重点】
2)因为字符串不可改变,所以字符串可以共享使用。
3)字符串效果相当于char[]字符数组,但底层的原理是byte[]字节数组。
3、创建字符串常见的3+1种方式:
三种构造方法:
public String():创建一个空白字符串,不含有任何内容;
public String(char[] array):根据字符数组的内容创建对应的字符串;
public String(byte[] array):根据字节数组的内容创建对应字符串;
一种直接创建:
String str =“Hello”; //右边直接使用双引号
注意:直接写上双引号就是字符串对象;
4、常量池:程序中直接写的双引号字符串,在字符串常量池中。
1)对于基本类型,==是进行数值比较。
2)对于引用类型,==是进行【地址值】比较。
5、比较方法:==是进行对象的地址值比较,如果需要字符串的内容比较,可以使用两个方法:
1)public boolean equals(Object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同才会给true;否则返回false。
注意事项:
- 任何对象都能用Object进行接收。
- equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。
- 如果比较双方一个常量一个变量,推荐把常量字符串写在前面。
推荐:“abc”.equals(str) 不推荐:str.equals(“abc”)
2)public boolean equalsIgnoreCase(String str):忽略大小写,进行内容比较。
6、获取的相关方法:
public int length():获取字符串当中含有的字符个数,拿到字符串长度。
public String concat(String str):将当前字符串和参数字符串拼接成为返回值新的字符串。
public char charAt(int index):获取指定索引位置的单个字符。(索引从0开始。)
public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。
7、截取的相关方法:
public String substring(int index):截取从参数位置一直到字符串末尾,返回新字符串。
public String substring(int begin, int end):截取从begin开始,一直到end结束,中间的字符串。
备注:[begin,end),包含左边,不包含右边。
8、转换的相关方法:
public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值。
public byte[] getBytes():获得当前字符串底层的字节数组。
public String replace(CharSequence oldString, CharSequence newString):
将所有出现的老字符串替换成为新的字符串,返回替换之后的结果为新字符串。
备注:CharSequenc(意思就是说可以接受字符串类型。)
9、分割的相关方法:
public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。
注意事项:
split方法的参数其实是一个“正则表达式”。
注意:如果按照英文句点“.”进行切分,必须写"."(两个反斜杠)
(六)static关键字
2)一个成员变量使用了static关键字,这个变量不再属于对象自己,而是属于所在的类。多个对象共享同一份数据。
2、static的修饰成员方法:
1)说明:一旦使用了static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类。
2)没有static关键字时,必须首先创建对象,然后通过对象才能使用它。
3)有了static关键字时,不需要创建对象,直接就能通过类名称来使用它。
4)注:无论是成员变量,还是成员方法。如果有了static,都推荐使用类名称进行调用。
(1)静态变量:类名称.静态变量
(2)静态方法:类名称.静态方法()
注意事项:
- 静态不能直接访问非静态。
原因:在内存当中是【先】有静态内容,【后】有非静态内容。 - 静态方法当中不能用this。
原因:this代表当前对象,通过谁调用的方法,谁就是当前对象。
3、静态static关键字的内存图:
4、静态代码块:
1)定义在成员位置,使用static修饰的代码块{ }。
2)位置:类中方法外。
3)执行:随着类的加载而执行且执行一次,优先于 main方法和构造方法的执行。
4)格式:
public class 类名称 {
static {
// 静态代码块的内容
}
}
5)特点:当第一次用到本类时,静态代码块执行唯一的一次。
静态内容总是优先于非静态,所以静态代码块比构造方法先执行。
6)静态代码块的典型用途:用于一次性地对静态成员变量进行赋值。
(七)Arrays类
1)java.util.Arrays是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作。
2)方法:
public static String toString(数组):将参数数组变成字符串(按照默认格式:[元素1, 元素2, 元素3…])
public static void sort(数组):按照默认升序(从小到大)对数组的元素进行排序。
备注:
- 如果是数值,sort默认按照升序从小到大
- 如果是字符串,sort默认按照字母升序
- 如果是自定义类型,那么这个自定义类需要有Comparable或Comparator接口的支持。
1)概述:用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。类似这样的工具类,其所有方法均为静态方法,并且不会创建对象,调用起来非常简单。
2)方法:
public static double abs(double num):获取绝对值。有多种重载。
public static double ceil(double num):向上取整。
public static double floor(double num):向下取整。
public static long round(double num):四舍五入。
Math.PI代表近似的圆周率常量(double)。
附加 :
1)循环中的从小到大排序的快捷方式为:chars.forr
2)在字符串的比较方法中 ,Ignore Case有忽略大小写的作用。
1、概述:子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
2、格式:在继承的关系中,“子类就是一个父类”。子类可以被当做父类看待。
例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a。
定义父类的格式:(一个普通的类定义)
public class 父类名称 {
// …
}
定义子类的格式:
public class 子类名称 extends 父类名称 {
// …
}
3、成员变量的访问特点:
在父子类的继承关系中,若成员变量重名,则创建子类对象时,访问有两种方式:
1)直接通过子类对象访问成员变量:
等号左边是谁,就优先用谁,没有则向上找。
2)间接通过成员方法访问成员变量:
该方法属于谁,就优先用谁,没有则向上找。
4、区分子类方法中的重名:
局部变量: 直接写成员变量名
本类的成员变量: this.成员变量名
父类的成员变量: super.成员变量名
5、继承中成员变量的访问特点 :
在父子类的继承关系中,创建子类对象,访问成员方法的规则: 创建的对象是谁,就优先用谁,若没有则向上找。
注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类。
6、继承中方法的覆盖重写:
1)重写(Override):在继承关系中,方法的名称一样,参数列表也一样。
重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
重载(Overload):方法的名称一样,参数列表【不一样】。
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
2)方法覆盖重写的注意事项:
- 必须保证父子类之间方法的名称相同,参数列表也相同。
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。
这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。
2.子类方法的返回值必须【小于等于】父类方法的返回值范围。
小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。
3.子类方法的权限必须【大于等于】父类方法的权限修饰符。
小扩展提示:public > protected > (default) > private
备注:(default)不是关键字default,而是什么都不写,留空。
3)方法覆盖重写的应用场景:
7、继承中构造方法的访问特点:
- 子类构造方法中有一个默认隐含的“super()”调用,所以是先调用父类构造,后执行子类构造。
- 子类构造可以通过super关键字来调用父类重载构造。
- super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。
1、super关键字的三种用法:
1.在子类的成员方法中,访问父类的成员变量。
2.在子类的成员方法中,访问父类的成员方法。
3.在子类的构造方法中,访问父类的构造方法。
2、this关键字的三种用法:
- 在本类的成员方法中,访问本类的成员变量。
- 在本类的成员方法中,访问本类的另一个成员方法。
- 在本类的构造方法中,访问本类的另一个构造方法。
第三种用法中需注意:
A. this(…)调用也必须是构造方法的第一个语句,唯一一个。
B. super和this两种构造调用,不能同时使用。
3、super关键字与this关键字的区别:
super关键字用来访问父类内容,而this关键字用来访问本类内容。
1、抽象的概念
2、抽象方法和抽象类的格式:
1)抽象方法:加上abstract关键字,然后去掉大括号,直接分号结束。
2)抽象类:抽象方法所在的类,必须是抽象类才行。在class前写abstract。
如何使用抽象类和抽象方法:
- 不能直接创建new抽象类对象。
- 必须用一个子类来继承抽象父类。
- 子类必须覆盖重写抽象父类当中所有的抽象方法。
覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。 - 创建子类对象进行使用。
3、使用:
1)一个抽象类不一定含有抽象方法,
2)只要保证抽象方法所在的类是抽象类,即可。
3)没有抽象方法的抽象类,不能直接创建对象,在一些特殊场景下有用途。
4、注意事项:
1 . 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
2 . 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
4 . 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
1、概述:是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。
(接口就是多个类的公共规范。
接口是一种引用数据类型,最重要的内容就是其中的:抽象方法。)
2、定义:与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。
3、引用数据类型:数组,类,接口。
4、接口的使用:不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
5、定义一个接口的基本格式:
public interface 接口名称 {
// 接口内容
}
备注:换成关键字interface后,编译生成的字节码文件仍然是:.java --> .class
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
6、接口的抽象方法的定义:
在任何版本的Java中,接口都能定义抽象方法。
格式:
public abstract 返回值类型 方法名称(参数列表);
注意事项:
- 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
- 这两个关键字修饰符,可以选择性地省略。(今天刚学,所以不推荐。)
- 方法的三要素,可以随意定义。
7、接口使用步骤:
5. 接口不能直接使用,必须有一个“实现类”来“实现”该接口。
格式:
public class 实现类名称 implements 接口名称 {
// …
}
6. 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。
实现:去掉abstract关键字,加上方法体大括号。
7. 创建实现类的对象,进行使用。
8、默认方法的定义:
从Java 8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表) {
方法体
}
备注:接口当中的默认方法,可以解决接口升级的问题。
9、默认方法的使用:
- 接口的默认方法,可以通过接口实现类对象,直接调用。
- 接口的默认方法,也可以被接口实现类进行覆盖重写。
10、静态方法的定义:
从Java 8开始,接口中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表) {
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体。
11、静态方法的使用:
注意事项:不能通过接口实现类的对象来调用接口中的静态方法。
正确用法:通过接口名称,直接调用其中的静态方法。
格式:
接口名称.静态方法名(参数);
12、私有方法的定义:
问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有化的。
解决方案:
从Java 9开始,接口中允许定义私有方法。
普通私有方法,解决多个默认方法之间重复代码问题
格式:
private 返回值类型 方法名称(参数列表) {
方法体
}
静态私有方法,解决多个静态方法之间重复代码问题
格式:
private static 返回值类型 方法名称(参数列表) {
方法体
}
13、常量定义和使用:
接口中可以定义“成员变量”,但必须使用public static final三个关键字进行修饰。
从效果上看,这其实就是接口的【常量】。
格式:
public static final 数据类型 常量名称 = 数据值;
备注:
一旦使用final关键字进行修饰,说明不可改变。
注意事项:
接口当中的常量,可以省略public static final,注意:不写也是一样。
接口当中的常量,必须进行赋值;不能不赋值。
接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)
15、内容小结:
在Java 9+版本中,接口的内容可以有:成员变量其实是常量,格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:
常量必须进行赋值,而且一旦赋值不能改变。
常量名称完全大写,用下划线进行分隔。接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。从Java 8开始,接口里允许定义默认方法,格式:
[public] default 返回值类型 方法名称(参数列表) { 方法体 }
注意:默认方法也可以被覆盖重写从Java 8开始,接口里允许定义静态方法,格式:
[public] static 返回值类型 方法名称(参数列表) { 方法体 }
注意:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法从Java 9开始,接口里允许定义私有很乏,格式:
普通私有方法:private 返回值类型 方法名称(参数列表) { 方法体 }
静态私有方法:private static 返回值类型 方法名称(参数列表) { 方法体 }
注意:private的方法只有接口自己才能调用,不能被实现类或别人使用。
15、继承父类并实现多个接口使用接口的时候,需要注意:
接口是没有静态代码块或者构造方法的
一个类的直接父类是唯一的,当时一个类可以同时实现多个接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA,InterfaceB{
//覆盖重写所有抽象方法
}如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
一个类如果没有直接父类当中的方法和接口当中国的默认值发生冲突时,优先使用父类当中的方法。
16、接口的多个继承类与类之间是单继承的。直接父类只有一个。
类与接口之间是多实现的。一个类可以实现那多个接口。
接口与接口之间是多继承的。
注意事项:
- 多个父接口当中的抽象方法如果重复,没关系。
- 多个父接口当中默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,【而且带着default关键字】。
1、概述:
代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
2、格式和使用:
格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();
3、多态中成员变量的使用特点:
访问成员变量的两种方式:
- 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找。
- 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。
4、多态中成员方法的使用特点:
在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找。
口诀:编译看左边,运行看右边。
对比:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边。
5、使用多态的好处:
1、向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:
对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
解决方案:用对象的向下转型【还原】。
2、如何才能知道一个父类引用的对象,本来是什么子类?
格式:
对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。
2、用instanceof关键字进行类型判断
public class Demo02Instanceof {
public static void main(String[] args) {
Animal animal = new Dog();
animal.eat();
// 如果希望调用子类特有方法,需要向下转型
// 判断一下父类引用animal本来是不是Dog
if (animal instanceof Dog) {
Dog dog =(Dog)animal;
dog.watchHouse();
}
//判断animal 本来是不是Cat
if (animal instanceof Cat) {
Cat cat = (Cat)animal;
cat.catchMouse();
}
}
}
1、概念:不可改变。可以用于修饰类、方法和变量。
2、常见四种用法:
可以用来修饰一个类
可以用来修饰一个方法
还可以用来修饰一个局部变量
还可以用来修饰一个成员变量
3、用来修饰一个类:
当final关键字用来修饰一个类的时候,格式:
public final class 类名称 {
// …
}
1)含义:当前这个类不能有任何的子类。(太监类)
2)注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写。
4、用来修饰一个方法:
当final关键字用来修饰一个方法的时候,这个方法就是最终方法,即不能被覆盖重写。
1)格式:
修饰符 final 返回值类型 方法名称(参数列表) {
// 方法体
}
2)注意事项:
对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。
5、用来修饰一个局部变量:
public class Demo01Final {
public static void main(String[] args) {
int num1 =10;
System.out.println(num1);
num1 = 25;
System.out.println(num1);
//一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。
//"一次赋值,终生不变"
final int num2 =230;
System.out.println(num2);
// num2 = 250; //错误写法!不能改变!
// num2 = 200; //错误写法!
//正确写法!只要保证有唯一一次赋值即可
final int num3;
num3 = 30;
//对于基本类型来说,不可变说的是变量当中的数据不可改变
//对于引用类型来说,不可变说的是变量当中的地址值不可改变
Student stu1 = new Student("锅巴侠");
System.out.println(stu1);
System.out.println(stu1.getName());
stu1 = new Student("烧饼侠");
System.out.println(stu1);
System.out.println(stu1.getName());
System.out.println("===========");
final Student stu2 = new Student("高晓松");
// 错误写法!final的引用类型变量,其中的地址不可改变
// stu2 = new Student("韩庚");
System.out.println(stu2.getName());
stu2.setName("晓松");
System.out.println(stu2.getName());
}
}
public class Student {
private String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
6、用来修饰一个成员变量:
对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变。
- 因为成员变量具有默认值,所以用了final后必须手动赋值,不会再给默认值。
- 对于final的成员变量,使用直接赋值,或者通过构造方法赋值。二者选其一。
- 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。
四种权限修饰符:
public > protected > (default) > private
同一个类(我自己) YES YES YES YES
同一个包(我邻居) YES YES YES NO
不同包子类(我儿子) YES YES NO NO
不同包非子类(陌生人) YES NO NO NO
注意事项:(default)并不是关键字“default”,而是根本不写。
编写代码时,如果没有特殊的考虑,建议这样使用权限:
成员变量使用private,隐藏细节。
构造方法使用public,方便创建对象。
成员方法使用public,方便调用方法。
备注:不加权限修饰符,其访问能力与default修饰符相同。
1、概念:如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。(例如:身体和心脏的关系。又如:汽车和发动机的关系。)
2、分类:
成员内部类
局部内部类(包含匿名内部类)
3、成员内部类的定义格式:
修饰符 class 外部类名称 {
修饰符 class 内部类名称 {
// …
}
// …
}
注意:内用外,随意访问;外用内,需要内部类对象。
4、使用:
如何使用成员内部类?有两种方式:
间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
直接方式,公式:
类名称 对象名 = new 类名称();
【外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();】
5、内部类的同名变量访问:
// 如果出现了重名现象,那么格式是:外部类名称.this.外部类成员变量名
public class Outer {
int num = 10; //外部类的成员变量
public class Inner /*extends Object*/ {
int num = 20; //内部类的成员变量
public void methodInner() {
int num = 30 ; //内部类方法的局部变量
System.out.println(num); //局部变量,就近原则
System.out.println("this.num"); //内部类的成员变量
System.out.println(Outer.this.num); //外部类的成员变量
}
}
}
public class Demo02InnerClass {
public static void main(String[] args) {
//外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
Outer.Inner obj = new Outer().new Inner();
obj.methodInner();
}
}
6、局部内部类定义:
如果一个类定义在一个方法内部,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
2)定义格式:
修饰符 class 外部类名称 {
修饰符 返回值类型 外部类方法名称(参数列表) {
class 局部内部类名称 {
// …
}
}
}
3)小节一下类的权限修饰符:
public > protected > (default) > private
定义一个类的时候,权限修饰符规则:
- 外部类:public / (default)
- 成员内部类:public / protected / (default) / private
- 局部内部类:什么都不能写
7、局部内部类的final问题:
局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。
备注:从Java 8+开始,只要局部变量事实不变,那么final关键字可以省略。
原因:
new出来的对象在堆内存当中。
局部变量是跟着方法走的,在栈内存当中。
方法运行结束之后,立刻出栈,局部变量就会立刻消失。
但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
8、匿名内部类:
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,则可以省略掉该类的定义,而改为使用【匿名内部类】。
2)匿名内部类的定义格式:
接口名称 对象名 = new 接口名称() {
// 覆盖重写所有抽象方法
};
3)注意事项:
- 匿名内部类,在【创建对象】的时候,只能使用唯一一次。
如果希望多次创建对象,而且类的内容一样的话,那么就需要使用单独定义的实现类了。 - 匿名对象,在【调用方法】的时候,只能调用唯一一次。
如果希望同一个对象,调用多次方法,那么必须给对象起个名字。 - 匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】
强调:匿名内部类和匿名对象不是一回事!!!