面向对象
接口
接口的关系
类和类之间是继承关系,不支持多继承,可以多层继承.
类和接口之间是实现关系,支持多实现,类可以多实现接口.
接口和接口之间的关系是继承,接口之间支持多继承关系.
interface B{}
interface C{}
interface A extends B,C{}
/*
* D类,实现接口A
* A接口,继承了B和C
* D类重写A,B,C 三个接口的全部抽象方法
*/
public class D implements A {
@Override
public void interB() {
// TODO Auto-generated method stub
}
@Override
public void interC() {
// TODO Auto-generated method stub
}
@Override
public void interA() {
// TODO Auto-generated method stub
}
}
接口的实现类还是抽象类
定义实现类实现了接口, 但是只重写了一部分的抽象方法,这个实现类还是抽象类.
interface A{
public abstract void function1();
public abstract void function2();
}
abstract class B implements A{
public void function1(){
}
}
抽象类和接口的区别
- 从定义上看
- 接口定义关键字 interface
- 抽象类定义关键字 abstract class
- 从成员上看
- 接口成员固定形式,成员变量,成员方法
- 抽象类可以有抽象方法,非抽象方法,成员变量
- 使用上看
- 接口需要实现类实现,支持多实现
- 抽象类要子类继承,单继承
- 设计思想
- 抽象类,是这个继承体现中所有事务的共性内容
- 接口,是这个继承体现中事务的部分额外功能
多态
多态 : 一个事务具备的不同形态,叫做多态
-
实例 :
-
你: 现在教室里面,你的形态是学习 (学生形态)
出去逛商场,你的形态是顾客
发现一个孩子落水,施救,英雄形态
-
狗: 当宠物
攻击外人, 看家的
疯狗
-
对象的多态性
-
对象多态性前提 :
- 要有继承或者接口实现
- 方法的重写
- 父类或者接口的引用变量,指向自己的子类或者实现类对象 (定义)
-
子类父类多态实现
public class Person { public void eat() { System.out.println("人在吃饭"); } } public class Student extends Person{ public void eat() { System.out.println("学生在吃饭"); } }
public static void main(String[] args) { //实现子类继承父类的 多态程序 //学生是一个人 //父类或者接口的引用变量,指向自己的子类或者实现类对象 /* * Person 父类类型 * p 是父类类型的引用变量 * new Student() 对象,是Person的子类对象 */ Person p = new Student(); p.eat(); // 执行子类的方法重写 }
-
抽象类和子类
public abstract class Animal { public abstract void eat(); }
public class Cat extends Animal { public void eat() { System.out.println("猫吃猫粮"); } }
public static void main(String[] args) { //抽象类和子类的多态形式 //父类类型 变量名 = new 子类对象(); Animal a = new Cat(); a.eat(); }
-
接口和实现类
public interface MyInterface { public abstract void inter(); }
public class MyInterfaceImpl implements MyInterface{ public void inter() { System.out.println("实现类重写方法"); } }
public static void main(String[] args) { //接口和实现类的多态程序 //接口类型 变量名 = new 实现类对象() MyInterface my = new MyInterfaceImpl(); my.inter(); }
多态的实现细节
- 多态的程序中,子类父类中成员变量特点
- 编译期 : 看父类中是否有这个变量,如果有编译成功,没有编译失败.
- 运行期 : 运行的是父类中的成员变量
- 多态的程序中,子类父类中成员方法特点
- 编译期 : 看父类中是否有这个方法,如果有编译成功,没有编译失败.
- 运行期 : 运行子类的方法重写
- 小总结:
Fu f = new Zi();
- 成员变量 : 编译看左边,运行看左边
- 成员方法 : 编译看左边,运行看右边
为什么编译是父类,运行是子类 (成员方法)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jP8GMiHH-1594817802098)(images/编译和运行的区别.jpg)]
多态转型
public static void main(String[] args) {
/*
* 多态创建对象
* Cat和Dog都继承Animal
* 调用子类父类的共性内容 eat()
* 调用不了,子类的特有内容 catchMouse() lookHome()
*/
Animal a = new Cat();
a.eat();
//类型强制转换, 向下转型
//已经提升为Animal类型的Cat对象,强制转换Cat类型
Cat c = (Cat)a;
//对象c 调用Cat类的特有成员,共有成员
c.catchMouse();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GDxIdDFQ-1594817802109)(images/类的转换.jpg)]
- 多态的好处和弊端:
- 好处 : 运行子类的重写方法,多态程序中可以随时扩展子类对象
- 弊端 : 多态中,能调用子类父类的共有成员,不能调用子类的特有成员
类型转换时候出现的异常问题
类型转换异常 : ClassCastException
/*
* Animal a = new Cat();
* Animal抽象的类,可以有多个子类产生
*
* Animal a = new 任何子类();
*/
public class PolymorphismTest {
public static void main(String[] args) {
Animal a = new Dog();
a.eat();
Cat c = (Cat)a;
c.catchMouse();
}
}
Exception in thread "main" java.lang.ClassCastException: polymorphism06.Dog cannot be cast to polymorphism06.Cat
at polymorphism06.PolymorphismTest.main(PolymorphismTest.java:13)
解决异常的出现 : 关键是在要转换的对象 a
上, 判断出这个a这个引用,是Dog对象还是Cat对象.
-
运算符 instanceof 做比较
-
比较的结果是布尔类型
-
instanceof 比较出, a到底是哪个类的对象
-
语法 :
引用类型变量 instanceof 类名 例子 : a instanceof Cat 含义 : a是不是Cat对象呢
public static void main(String[] args) { Animal a = new Cat(); a.eat(); //判断a,如果是Cat对象,强制转换 if(a instanceof Cat) { Cat c = (Cat)a; c.catchMouse(); } //判断a,如果是Dog对象,强制转换 else if(a instanceof Dog) { Dog d = (Dog)a; d.lookHome(); } }
多态案例
需求 : 有一台笔记本电脑,笔记本上面有接口存在 USB, USB是真实存在的接口,使用笔记本的人可以向接口上连接一些外接设备, 鼠标,键盘,手机,打印机 …
笔记本的厂家,不会预先想到USB接口上,会连接哪些设备
-
设计一台笔记本电脑,出现USB接口,可以连接任意的外接设备
核心的技术点 : 方法的参数是接口类型,调用方法传递实现类对象,多态调用,执行实现类的重写方法
/*
* 接口USB : 就是一个规则
* 规则的具体的体现 : 接口中的抽象方法
*/
public interface USB {
//设备开机
public abstract void open();
//设备关键
public abstract void close();
}
/*
* 鼠标类 : 连接到USB接口,必须实现接口的规则
*/
public class Mouse implements USB{
@Override
public void open() {
System.out.println("鼠标开机");
}
@Override
public void close() {
System.out.println("鼠标关机");
}
}
/*
* 键盘类 : 连接到USB接口,必须实现接口的规则
*/
public class Keyboard implements USB{
@Override
public void open() {
System.out.println("键盘开机");
}
@Override
public void close() {
System.out.println("键盘关机");
}
}
/*
* 定义笔记本类
*/
public class Computer {
/*
* 定义方法: 笔记本使用USB接口上的设备
* 方法的计算结果,返回值类
* 方法的参数,是未知的数据, USB接口上的外接设备 (鼠标,键盘)
* 方法的参数,不能写某一个设备(程序写死了)
* 但是 : 无论鼠标或者是键盘,还是其他设备... 必须满足USB接口规则!!
* 参数 : 写的是接口
*
* USB u = new Mouse()
*/
public void useUSB(USB u) {
//接口引用变量 u 调用方法
u.open();
u.close();
}
}
public static void main(String[] args) {
//创建笔记本的对象,调用笔记本的功能
Computer computer = new Computer();
/*
* 调用笔记本的功能, 使用USB接口设备功能
* 方法的参数是USB的接口类型
* 接口没有对象, 能传递的参数只有接口实现类的对象
*/
computer.useUSB( new Mouse() );
computer.useUSB( new Keyboard() );
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DUbN624w-1594817802111)(images/方法的参数是接口.jpg)]
static 静态
static修饰符 : 成员修饰符,只能修饰类的成员 (变量和方法), 方法里面不能使用static修饰
被static修饰的成员,称为静态成员.
静态成员的内存图
/*
* 定义一些人的属性和行为
* 指定一个属性 : 国籍
*/
public class Person {
String name;
int age;
static String country;
public void eat() {
System.out.println("人在吃饭");
}
}
public static void main(String[] args) {
//创建Person对象
Person p1 = new Person();
p1.name = "张三";
p1.age = 20;
p1.country = "中国";
Person p2 = new Person();
p2.name = "李四";
p2.age = 21;
//p2.country = "中国";
System.out.println(p2.country);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qTEvek9Z-1594817802113)(images/静态内存图.jpg)]
静态的调用规则
内存图进行分析,静态的成员在内存中有自己的所属,属于自己的类.
因此 : 静态的调用方式 : 类名.静态成员
System.out.println(Person.country);
Person.eat();
静态使用的注意事项
- 不能在静态上下文中引用非静态变量
- 静态不能直接使用非静态
- 原因 : 生命周期,静态成员优先于非静态的成员出现在内存中
- 先人(静态)不能调用后人(非静态)
- 静态方法中,进制使用this和super
- this 和 super都和对象有关联
- 静态优先于对象存在
静态和对象无关性
多态 : 对象的多态性
静态成员 : 属于自己的类,和对象无关!!
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.s); //s 静态变量,编译运行全是父类
f.show(); // 方法show()静态方法,编译运行全那是父类
}
成员的调用方式
- 静态成员
- 类名调用
- 可以被对象调用 X javac 编译器,直接编译为类名!
- 非静态成员
- 只能被对象调用
main方法解释
- public : 被JVM调用,权限必须足够大
- static : JVM通过类名调用方法main
- void : 返回值,返回调用者, JVM获得返回值没有意义
- main : 名字固定
- String[] args : 存储字符串数组, 以后会添加JVM的启动参数
静态成员和非静态成员的区别
- 内存上看区别
- 静态成员变量,跟随类进入到静态区
- 非静态成员变量,跟随对象进入到堆内存
- 所属上看区别
- 静态成员变量,属于自己的类
- 非静态成员变量,属于对象
- 从生命周期上看区别
- 静态成员优先于非静态进入内存,在静态区里,程序结束才释放,最长
- 非静态成员进入堆,对象成为垃圾后,JVM进行回收,相对较短
- 调用方式上看
- 静态类名调用
- 非静态对象调用
- 数据使用上看
- 静态的成员,是所有对象的共享数据
- 非静态的成员,是对象自己的特有数据
什么时候使用静态修饰
具体事务具体分析了,根据分析的结果,决定是否使用静态修饰
分析方法 : 分析这些事务之间是否存在着共享数据,出现共享数据,static修饰
以上说的是静态的成员变量
什么时候使用静态方法 : 如果方法中的功能使用了静态的成员变量,这个方法就应该static修饰
final修饰符
final翻译为最终的,不可改变的
-
可以修饰类
public final class A{} 最终类 最终类不被子类继承, A类没有孩子 (太监类) 以前学过最终类 : String,Scanner,System
-
可以修饰方法
public final 返回值类型 方法名(参数列表){} 最终方法 最终方法,不能被子类重写 有些类,定义的方法,一部分很完美,另一些方法不是很完善
-
可以修饰局部变量
final 数据类型 变量名 = 值 ; 最终变量 被final修饰的变量,一次赋值,终身不变,可以看成是常量 final修饰的是引用类型,引用类固定的是内存地址