今日内容
零、 复习昨日
一、作业
二、抽象
三、接口
零、 复习昨日
final的作用
- 最终的,修饰的类,属性,方法不能改变
- 类不能继承,属性不能改变(常量),方法不能重写
static修饰方法的特点
- 修饰的属性方法在内存只有一份
- 随着类加载而初始化
- 不要new,可以通过类名直接调用
- 被该类的所有对象共享(类属性,方法)
- 静态不能调用非静态
多态效果形成的前提
- 继承(子父类关系)
- 重写
- 向上转型(父类指向子类对象)
多态使用的场景
- 方法的参数列表是父类,传入子类,方法执行时出现的各种子类效果
- 数组是父类型数组,存储子类对象
- ps: 多态是解决共性问题方便使用的
什么叫向下转型?如何才能转型成功?
- 父对象变子对象(子类引用指向父类对象)
- 先有向上,才能 向下
- Animal a = new Dog();s
- Dog dog = (Dog)a;
- 什么时候需要? 当需要执行子类特有的方法时
一、作业
见代码
二、抽象
2.1 解释
生活抽象: 抽象画,抽象的故事 , 意思就是指看不明白,不懂…与具象化是反义词
代码的抽象: 主要是指抽象类和抽象方法
2.2 语法特点
类和方法如何变成抽象?有何特点?代码如何写?
- 在class前面加
abstract 修饰,类就变成抽象类
- 抽象类中可以有正常属性,且不能抽象
- 抽象类中
可以有正常方法
- 抽象类中
可以有被abstract修饰的抽象方法,没有方法体!
抽象方法必须 放在抽象类中
- 抽象类中可以
有构造方法,且不抽象!但是不能直接new创建对象
!
那么抽象类存在的目的意义是什么?
- 抽象类是用来被继承的
- 子类继承抽象类要求:
- 要么子类定义成抽象类
要么就必须重写(实现implement)全部抽象方法
// 抽象父类
package com.qf.abstract_;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @date 2024/1/31
* @desc 演示抽象语法
*/
public abstract class Animal {
// 属性没有抽象性
int age;
// 正常方法
public void eat(){
System.out.println("动物觅食" );
}
// 抽象方法
public abstract void play();
// 构造方法
public Animal(){
System.out.println("Animal()" );
}
}
// 子类
public /*abstract*/ class Dog extends Animal{
public Dog(){
System.out.println("Dog()" );
}
@Override
public void play() {
System.out.println("小狗玩球" );
}
}
// 测试
public class TestAbstract {
public static void main(String[] args) {
// 抽象类有构造方法,但是不能直接new创建对象!!
// new Animal();
// new Dog()还会调用Animal()构造方法
Dog dog = new Dog( );
System.out.println(dog.age );// 使用抽象父类的属性
dog.eat();// 父抽象类方法
// 抽象类可以当做父类引用指向子类对象
Animal animal = new Dog();
animal.eat();// animal自己的正常,执行
animal.play();// 调用子类重写的执行,即多态效果
}
}
2.3 什么用?
抽象类不能直接主动new创建对象,但是被继承后,
创建子类对象时,还是会父类构造方法
,因为子类还需要父类的非私有的属性和方法
抽象类虽然不能直接new,但是可以当做父类引用,指向子类对象 —> 多态
总结什么时候需要抽象类抽象方法?
- 抽象差异化,具体共同点
- 将很多类都有的共同方法抽取到父类中,大家共用
- 很多类有共同的行为但是具体表现不一样,将这些方法定义成抽象,让子类自己实现
平时自己用,敲代码时,抽象有什么经验?
- 1)用别人的抽象类时,一般要继承它,重写抽象方法即可
- 2)做为设计者,设计抽象类,将共同能直接用的方法直接定义,子类都需要单独实现的定义成抽象
- 现在抽象的用法与之前写代码几乎是一样用法,只不过
多了一层限制
,即必须重写抽象方法
2.4 练习
抽象类的使用,将之前做的所有练习将父类改成抽象类即可
- 形状类变抽象
- 员工类变抽象
- 动物类变抽象
其他用法基本一样(继承,重写,向上转型)…
三、接口
java的引用数据类型: 数组,类,接口
接口是比抽象类还抽象的java文件
3.1 语法介绍
接口不是类
,需要使用interface修饰- 接口中没有属性变量,
都是常量
,默认都被public static final
修饰- 接口中没有正常方法,
全都是抽象方法
,默认都被public abstract
修饰- 接口中不能有构造方法,肯定
不能创建对象
接口用来干什么呢? 用来被子类实现
- 接口是用来被
子类实现implements
- 子类实现父接口,
- 要么子类定义成抽象类
- 要么子类重写(实现)全部抽象方法
- 子类允许实现
多个接口
(多实现)- 子类还可以再
继承的同时实现接口
,注意先继承后实现
// 父接口
public interface USB {
// 属性都是常量,默认被 public static final修饰
public static final double length = 1;
// 方法都是抽象,默认被public abstract修饰
public abstract void send();
// 没有构造
// public USB(){}
}
// 子实现类
// 继承同时实现接口
// 且是多实现
public class UDisk extends Shape implements USB,Disk{
@Override
public void send() {
System.out.println("U盘发送数据" );
}
@Override
public void input() {
System.out.println("U盘输入数据" );
}
@Override
public void output() {
System.out.println("U盘输出数据" );
}
}
3.2 作用
接口虽然不创建创建对象,但是可以当做父引用去使用! 其实就是利用多态的特性,即
- 提供扩展性
- 减少耦合性
练习题:
今天以及以前那些多态题,抽象类的题其实都可以改造成接口去演示,基本上一致
3.3 和抽象的区别
代码语法上来说,区别
抽象 | 接口 | |
---|---|---|
类 | 是类(class) | 不是类(interface) |
属性 | 有属性 | 没有,全是常量 |
方法 | 有正常方法,也有抽象 | 全是抽象方法 |
构造方法 | 构造方法 | 没有 |
创建对象 | 不能创建对象 | 不能创建对象 |
应用 | 当做父引用指向 子类 | 当做父引用指向 子类 |
从应用角度来说,感觉用法很相似,都是当做父引用指向子类对象,即多态场景下使用!
既然差不多,为何需要接口?
- 如果只有抽象,一个类继承完抽象类还能再扩展吗? 不能!类是单继承
- 接口 是一种对接的思想,可以让类和类产生关系
- 抽象类至少还是类!类是描述一类物体! 接口是不是类,都是常量和抽象方法,所以接口是一种规范(约束,定义)
- 编程时,如何设计抽象还是接口呢?
- 能代表一类物体(物种),有共性可复用,又有特性的,那就设计成抽象类
- 能代表一类能力,行为,规范的这些定义成接口
编程经验
- 后续写项目,会把接口的命名定义成IXxxx , IUsb
- 实现类定义成 XxxImpl
3.4 练习
pdf8
五、内部类[了解]
内部类的概念:
在⼀个类中定义的类,称之为内部类(InnerClass),外⾯的类的称之为外部类(OutClass)
内部类的分类:
- 1、成员内部类
- 2、静态内部类
- 3、局部内部类
- 4、匿名内部类
内部类的特点:
- 1、内部类可以访问到外部类的私有成员,且不破坏封装性
- 2、内部类也会生成.class⽂件。名为:外部类名$内部类名.class
外部类的特点:
- 一个java 文件中可以编写多个类,但是只能有一个类能使用public修饰,称之为主类。主类名必 须与文件名⼀致
- 建议:以后开发中,一个java文件就编写⼀个类
5.1 成员内部类
成员内部类
- 1、成员内部类中只能定义非静态属性和方法
- 2、成员内部类中可以访问外部类的成员,私有的可以,静态的也可以
- 3、成员内部类如何创建对象
- 语法: 内部类 对象名 = new 外部类().new 内部类();
public class Outer {
private int outer = 1;
void testOuter(){
// 外部不能用内部
// System.out.println(inner );
}
// 成员内部类
public class Inner {
int inner = 2;
void testInner(){
// 内部可以用外部
System.out.println(outer );
}
}
}
5.2 匿名内部类 [熟悉]
匿名内部类:本⾝就是⼀个对象
语法:
new ⽗类(){ 重写⽗类的⽅法 }
特点:
- 1、匿名内部类本⾝就是⼀个对象
- 2、⼀般在匿名内部类中不会定义属性和⽅法,因为没有意义
- 3、匿名内部类的⽗类⼀般都是抽象类或者是接口
匿名内部类的应用场景
- 如果一个方法的参数是接口,且这个接口只需要实现一次,那么就可以使用匿名内部类
// 接口
public interface USB {
void chuanshu();
}
// 测试
package com.qf.oop3;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
*/
public class TestInnerClass {
public static void main(String[] args) {
/**
* 按以前,需要新建一个类实现USB接口,创建子实现类对象
* 但是如果该接口的方法只需要实现一次,那么这么做就浪费时间
*
* 可以使用匿名内部类来简写
* 匿名内部类
* new 接口(){
* 重写方法()
* }
* 相对于是,实现了接口并重写了方法且创建了子类对象
*/
new USB() {
@Override
public void chuanshu() {
System.out.println("U盘传输" );
}
}.chuanshu();
System.out.println("---------" );
// 匿名内部类相当于创建了子类对象,所有也可以使用父类类型接收
USB usb = new USB() {
@Override
public void chuanshu() {
System.out.println("U盘传输" );
}
};
usb.chuanshu();
System.out.println("-----------" );
// 当方法的参数列表是接口的时候,可以传入匿名内部类对象
// 跟以前传入子实现类对象一个意思,只是简化了
addUSB(new USB( ) {
@Override
public void chuanshu() {
System.out.println("U盘传输" );
}
});
addUSB(new USB( ) {
@Override
public void chuanshu() {
System.out.println("U盘传输" );
}
});
}
public static void addUSB(USB usb) {
usb.chuanshu();
}
}
四、补充知识
成员内部类,静态 内部类,匿名内部类
构造代码块,局部代码块,静态代码块