一、多态
1.多态概述
1.1什么是多态
同类型对象,执行同一行为,表现出不同的行为特征;
1.2多态常见形式
-
父类类型 对象名称 = new 子类构造器;
-
接口 对象名称 = new 实现类构造器;
1.3 多态中成员访问特点
-
方法调用:编译看左边,运行看右边(多态侧重行为多态)
-
编译,查看父类中是否有对应方法
-
运行,执行子类方法结果
-
-
变量调用:编译看左边,运行看左边;
1.4 多态前提
-
有继承/实现关系;
-
有父类引用指向子类对象;
-
有方法重写
public abstract class Animal {
public String name = "动物原型";
public abstract void run();
}
public class Dog extends Animal{
public String name = "Dog原型";
@Override
public void run() {
System.out.println("Dog is run");
}
}
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();
//编译看左,运行看右
//Dog is run
dog.run();
System.out.println(dog.name);
Animal cat = new Cat();
cat.run();
//动物原型,变量采用父类
System.out.println(cat.name);
}
}
2.多态优势和问题
-
多态形态下,右边对象实现解耦合,便于扩展维护;
-
右侧的子类对象可以调换,不影响其他代码
-
-
定义方法,采用父类对象,兼容性强,接收一切子类对象,体现多态扩展性;
-
存在问题:
-
以父类为主,使用子类独有方法,报错
-
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();
go(dog);
Cat cat = new Cat();
go(cat);
//dog and cat 在go()中效果一致
}
/**
* 要求所有动物都可用
* @param animal
*/
public static void go(Animal animal){
System.out.println("Start Up");
animal.run();
System.out.println("Time Out");
}
}
3.多态下引用数据类型的数据转换
-
自动类型转换(从子到父,范围小到大):
-
子类对象赋值给父类类型的变量转换;
-
-
强制类型转换(从父到子):
-
子类 对象变量 = (子类)父类类型变量;
-
作用:解决多态下劣势,实现调用子类多有功能
-
//自动类型转换 Animal a = new Dog(); a.run(); //强制类型转换 Animal b = new Cat(); b.run(); //b由父类型强制转换为子类型 Cat cat = (Cat) b; //转为子类型,可以使用独有方法 cat.eatFish();
-
-
转型后类型和对象真实类型不是同一种,类型异常ClassCastException
-
//强制类型转换,编译阶段不报错(有继承或者实现关系可以强转),运行时可能出错;类型异常ClassCastException
//Dog dog = (Dog) b;
-
-
Java建议强制转换前 使用instanceof判断
-
/** * 要求所有动物都可用 * 不清楚传进来的动物类型 * @param animal */ public static void go(Animal animal){ if (animal instanceof Dog){ Dog dog = (Dog) animal; dog.lookDoor(); }else if (animal instanceof Cat){ Cat cat = (Cat) animal; cat.eatFish(); } }
-
-
4.多态综合
public interface USB {
void connect();
void unConnect();
}
public class KeyBoard implements USB{
private String name;
public KeyBoard(String name) {
this.name = name;
}
@Override
public void connect() {
System.out.println(name+"成功连接");
}
/**
* 独有功能
*/
public void keyDown(){
System.out.println(name+"键入字符");
}
@Override
public void unConnect() {
System.out.println(name+"成功拔出");
}
}
public class Mouse implements USB{
其他同上
/**
* 独有功能
*/
public void dbClick(){
System.out.println(name+"单击图标");
}
}
public class Computer {
其他同上
/**
* 提供USB设备安装接口
*/
public void installUSB(USB usb){
usb.connect();
//判断子类类型,强转实现功能
if (usb instanceof KeyBoard){
KeyBoard keyBoard = (KeyBoard) usb;
keyBoard.keyDown();
}else if (usb instanceof Mouse){
Mouse mouse = (Mouse) usb;
mouse.dbClick();
}
usb.unConnect();
}
}
public class Test {
public static void main(String[] args) {
Computer computer = new Computer("机械师T58");
computer.start();
KeyBoard keyBoard = new KeyBoard("PHILIPS");
//插入键盘
computer.installUSB(keyBoard);
Mouse mouse = new Mouse("罗技");
computer.installUSB(mouse);
}
}
二、内部类
1.概述
定义在一个类内的类,里面类可以理解为寄生,外面是宿主;
public class People {
public class Heart {
}
}
2.使用场景
-
一个事务内部,还有一个部分需要完整的结构描述,并且这个内部结构只为外部事务服务,可以用内部类设计
-
(人和各人体器官)(汽车和发动机)与现实对接
-
-
内部类通常可以方便访问外部类成员,包括私有
-
内部类提供更好的封装性,内部类本身可以用private protected修饰,封装做更多控制
-
外部类只能用public修饰
-
3.内部类分类
3.1静态内部类
-
和内部类无区别
-
Outer.inner inner = new Outer.inner();
-
静态内部类可以直接访问外部类静态成员;共享
-
静态内部类不可以直接访问外部类实例成员;需要外部类对象
3.2成员内部类(非静态)
-
JDK16后运行成员内部静态
-
Outer.inner inner = new Outer().new inner();
-
成员内部类可以直接访问外部类静态成员;共享
-
成员内部类的实例方法可以直接访问外部类实例成员;先有外部,才有内部;
/**
* 面试试题:
* 输出对应值
*/
public class People {
private int heartbeat = 158;
public class Heart{
private int heartbeat = 110;
public void show(){
int heartbeat = 78;
System.out.println(heartbeat);//78
System.out.println(this.heartbeat);//110
System.out.println(People.this.heartbeat);//158
}
}
}
3.3 局部内部类
-
放在方法,代码块,构造器等执行体中;
-
局部 内部类产生class文件:外部类$内部类
3.4匿名内部类(重点)
-
本质:没有名字的局部内部类,放在方法,代码块等执行体中;
-
作用:方便创建子类对象,为了简化代码编写
-
特点总结:
-
匿名内部类写出来就会产生一个匿名对象
-
匿名对象类型是当前new的类的子类
-
public class Test {
public static void main(String[] args) {
Animal tiger = new Tiger();
tiger.run();
//匿名内部类
Animal rabbit = new Animal() {
@Override
public void run() {
System.out.println("兔子跑");
}
};
rabbit.run();
}
}
class Tiger extends Animal{
@Override
public void run() {
System.out.println("老虎跑");
}
}
abstract class Animal{
public abstract void run();
}
3.4.1匿名内部类常见使用形式
匿名内部类可以作为方法的实际参数进行传输;
public class Test2 {
public static void main(String[] args) {
Swimming student = new Swimming() {
@Override
public void swim() {
System.out.println("学生游泳");
}
};
goSwim(student);
goSwim(new Swimming() {
@Override
public void swim() {
System.out.println("teacher游泳");
}
});
}
public static void goSwim(Swimming swimming){
System.out.println("开始");
swimming.swim();
System.out.println("结束");
}
}
interface Swimming{
void swim();
}
3.4.2 常用使用场景
-
开发中不是主动去定义匿名内部类代码,别人需要我们写才会用
-
匿名内部类代码实现代码进一步简化
public class Test3 {
public static void main(String[] args) {
//窗口
JFrame win = new JFrame("清理垃圾界面");
//画布创建
JPanel jPanel = new JPanel();
win.add(jPanel);
JButton btn1 = new JButton("清理");
JButton btn2 = new JButton("二次清理");
//匿名内部类
btn1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(win,"垃圾清理开始!");
}
});
//匿名内部类:最终目的简化代码
btn2.addActionListener(e -> JOptionPane.showMessageDialog(win,"二次垃圾清理开始!") );
jPanel.add(btn1);
jPanel.add(btn2);
//窗口宽高,居中,显示
win.setSize(400,300);
win.setLocationRelativeTo(null);
win.setVisible(true);
}
}