面向对象三大特征之三:多态、内部类、常用API

目录

面向对象三大特征之三:多态

多态的概述、形式

多态的优势

多态下引用数据类型的类型转换

多态的案例

内部类

内部类的概述

内部类之一:静态内部类[了解]

内部类之二:成员内部类[了解]

内部类之三:局部内部类[了解]

内部类之四:匿名内部类概述[重点]

匿名内部类常见使用形式

匿名内部类真实使用场景演示

常用API

Object

StringBuilder

Math

System

BigDecimal


面向对象三大特征之三:多态

多态的概述、形式

什么是多态?
    同类型的对象,执行同一行为,会表现出不同的行为特征
多态的常见形式
    父类类型 对象名称 = new 子类构造器;
    接口 对象名称 = new 实现类构造器;
//抽象父类
public abstract class Animal {
    public abstract void run();
}
//狗类
public class Dog extends Animal {
    @Override
    public void run() {
        System.out.println("狗跑的贼快~~~");
    }
}
//乌龟类
public class Tortoise extends Animal {
    @Override
    public void run() {
        System.out.println("乌龟跑得很慢~~~");
    }
}
//测试类
//认识多态,理解多态的形式和概念
public class Test {
    public static void main(String[] args) {
        //1、多态的形式   父类类型 对象名称 = new 子类构造器;
        Animal a = new Dog();
        a.run();//狗跑的贼快~~~

        Animal a2 = new Tortoise();
        a2.run();//乌龟跑得很慢~~~
    }
}
多态成员访问特点
    方法调用:编译看左,运行看右
    变量调用:编译看左,运行也看左(多态侧重行为多态)
多态的前提
    有继承/实现关系;有父类引用指向子类对象;有方法重写。

多态的优势

优势
    在多态形式下,右边对象可以实现解耦合,便于扩展和维护
    定义方法的时候,使用父类型作为参数,该方法就可以接受这父类的一切子类对象,体现出多态的扩展性与便利

父类作为参数传递 

 

多态下会产生的一个问题
    多态下不能使用子类独有功能

多态下引用数据类型的类型转换

自动类型转换(从子到父):子类对象赋值给父类类型的变量指向
强制类型转换(从父到子)
    此时必须进行强制类型转换:子类 对象变量 = (子类)父类类型的变量
    作用:可以解决多态下的劣势,可以实现调用子类独有的功能

注意:如果转型后的数据和对象真实类型不是同一种类型,那么在转换的时候就会出现ClassCastException
Java建议强转转换前使用instanceof判断当前对象的真是类型,再进行强制转换
    变量名 instanceof 真实类型
    判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true,反之。
Animal t = new Tortoise();
Dog d = (Dog)t//出现异常ClassCastException
//学习多态形式下的类转换机制
public class Test {
    public static void main(String[] args) {
        //自动类型转换
        Animal a = new Dog();
        a.run();

        //强制类型转换:
        Animal a2 = new Tortoise();
        a2.run();

        //Dog d = (Dog)a2;//强制类型转换,编译阶段不报错(注意:有继承或实现关系编译阶段可以强制,运行时可能报错!
        if (a2 instanceof Tortoise) {
            Tortoise t = (Tortoise) a2;//从父类到子类的强制转换
            t.layEggs();
        } else if (a2 instanceof Dog) {
            Dog d = (Dog) a2;
            d.lookDoor();
        }
        System.out.println("-----------------");
        go(new Dog());
        go(new Tortoise());

    }

    public static void go(Animal a) {
        a.run();
        //a到底是乌龟还是狗?
        if (a instanceof Tortoise) {
            Tortoise t = (Tortoise) a;//从父类到子类的强制转换
            t.layEggs();
        } else if (a instanceof Dog) {
            Dog d = (Dog) a;
            d.lookDoor();
        }

    }
}

多态的案例

需求:
    使用面向对象编程模拟:设计一个电脑对象,可以安装2个USB设备
    鼠标:被安装是可以完成接入、调用点击功能、拔出功能
    键盘:被安装是可以完成接入、调用打字功能、拔出功能
分析:
    定义一个USB接口(申明USB接口设备的规范是必须是:可以接入和拔出)
    提供2个USB实现类代表鼠标和键盘,让其实现USB接口,并分别定义独有功能
    创建电脑对象,创建2个USB实现类对象,分别安装到电脑中并触发功能的执行
//USB接口 == 规范
public interface USB {
    //接入、拔出
    void connect();
    void unconnect();
}
//键盘实现类
public class KeyBoard implements USB {
    private String name;

    public KeyBoard(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void connect() {
        System.out.println(name + "成功连接了电脑~~~");
    }

    /**
     * 独有功能
     */
    public void keyDown(){
        System.out.println("敲击了:666~~~");
    }

    @Override
    public void unconnect() {
        System.out.println(name + "成功从电脑中拔出~~~");
    }
}
//键盘实现类
public class Mouse implements USB {
    private String name;

    public Mouse(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void connect() {
        System.out.println(name + "成功连接了电脑~~~");
    }

    /**
     * 独有功能
     */
    public void dbClick() {
        System.out.println(name + "点击了一键三连!");
    }

    @Override
    public void unconnect() {
        System.out.println(name + "成功从电脑中拔出~~~");
    }
}
//电脑类
public class Computer {
    private String name;

    public Computer(String name) {
        this.name = name;
    }

    public Computer() {
    }

    public void start() {
        System.out.println(name + "开机啦~~~");
    }

    /**
     * 提供安装USB设备的接口
     */
    public void installUSB(USB usb) {
        //多态:usb == 可能是鼠标,也可能是键盘
        usb.connect();//接入
        //独有功能
        if (usb instanceof KeyBoard) {
            //键盘
            KeyBoard k = (KeyBoard) usb;//强制类型转换
            k.keyDown();
        } else if (usb instanceof Mouse) {
            //鼠标
            Mouse m = (Mouse) usb;
            m.dbClick();
        }
        usb.unconnect();//拔出
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/**
 * 目标:USB设备模拟
 * 1、定义USB接口:接入、拔出
 * 2、定义2个USB实现类:鼠标、键盘
 * 3、创建一个电脑对象,创建USB设备对象,安装启动
 */
public class Test {
    public static void main(String[] args) {
        //创建电脑对象
        Computer c = new Computer("外星人");
        c.start();

        //创建鼠标、键盘对象
        USB usb = new KeyBoard("双飞燕");
        c.installUSB(usb);
        System.out.println("----------------");
        USB usb1 = new Mouse("罗技鼠标");
        c.installUSB(usb1);
    }
}

内部类

内部类的概述

内部类
    内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。
    public class People{
        //内部类
        public classHeart{
        }
    }
内部类的使用场景、作用
    1、当一个事物的内部,还有一个部分需要一个完整的结构进行描述,
    而这个内部的完整的结构又只为外部事物提供服务,
    那么整个内部的完整结构可以选择使用内部类来设计。
    2、内部类通常可以方便访问外部类的成员,包括私有的成员。
    3、内部类提供了更好的封装性,内部类本身就可以用private protectecd等修饰,
    封装性可以做更多控制。
内部类的分类
    静态内部类[了解]
    成员内部类(非静态内部类)[了解]
    局部内部类[了解]
    匿名内部类(重点)

内部类之一:静态内部类[了解]

什么是静态内部类?
    有static修饰,属于外部类本身
    它的特点和使用与普通类是完全一样的,类有的成分它都有,只是在别人里面而已
    public class Outer{
        //静态成员内部类
        public static class Inner{
        }
    }
静态内部类创建对象的格式:
格式:外部类.内部类名 对象名 = new 外部类名.内部类构造器;
范例:Outer.Inner in = new Outer.Inner();
静态内部类的访问拓展
1、静态内部类中是否可以直接访问外部类的静态成员?
    可以,外部类的静态成员只有一份可以被共享访问。
2、静态内部类中是否可以直接访问外部类的实例成员?
    不可以的,外部类的实例成员必须用外部类对象访问。

内部类之二:成员内部类[了解]

什么是成员内部类?
    无static修饰,属于外部类的对象
    JDK16之前,成员内部类中不能定义静态成员变量,JDK16开始可以定义静态成员变量
    public class Inner{
        //不用static修饰
        public class Inner{
        }
    }
成员内部类创建对象的格式:
格式:外部类.内部类名 对象名 = new 外部类构造器.new 内部类构造器();
范例:Outer.Inner in = new Outer().new Inner();
成员内部类的访问拓展:
1、成员内部类中是否可以直接访问外部类的静态成员?
    可以,外部类的静态成员只有一份可以被共享访问。
2、成员内部类的实例方法中是否可以直接访问外部类的实例成员?
    可以的,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员。

public class Test {
    public static void main(String[] args) {
        People.Heart heart = new People().new Heart();
        heart.show();
    }
}

class People {
    private int heartbeat = 150;

    /**
     * 成员内部类
     */
    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);//150
        }
    }
}

内部类之三:局部内部类[了解]

局部内部类(鸡肋语法,了解即可)
    局部内部类放在方法、代码块、构造器等执行体中。
    局部内部类的类文件名为:外部类$N内部类.class。

内部类之四:匿名内部类概述[重点]

匿名内部类:
本质上是一个没有名字的局部内部类,定义在方法中、代码块中、等。
作用:方便创建子类对象,最终目的为了简化代码编写。
特点总结:
    匿名内部类是一个没有名字的内部类
    匿名内部类写出来就会产生一个匿名内部类的对象
    匿名内部类的对象类型相当于是当前new的那个的类型的子类型

//学习匿名内部类的形式和特点
public class Test {
    public static void main(String[] args) {
        //Animal a = new Tiger();
        //a.run();
        //匿名内部类
        Animal a1 = new Animal() {
            @Override
            public void run() {
                System.out.println("老虎跑的很快~~~");
            }
        };
        a1.run();
    }
}

//老虎子类
//class Tiger extends Animal {
//    @Override
//    public void run() {
//        System.out.println("老虎跑的很快~~~");
//    }
//}

//动物抽象类
abstract class Animal {
    public abstract void run();
}

匿名内部类常见使用形式

//掌握匿名内部类的使用形式(语法)
public class Test {
    public static void main(String[] args) {
        Swimming s = new Swimming() {
            @Override
            public void swim() {
                System.out.println("学生在快乐地自由游~~~");
            }
        };
        go(s);
        System.out.println("------------------");
        Swimming s1 = new Swimming() {
            @Override
            public void swim() {
                System.out.println("老师游的贼快~~~");
            }
        };
        go(s1);

        System.out.println("-----------------");
        go(new Swimming() {
            @Override
            public void swim() {
                System.out.println("运动员游的贼快啊~~~");
            }
        });
    }

    /**
     * 老师 学生 远动员一起游泳
     */
    public static void go(Swimming s) {
        System.out.println("开始游泳~~~");
        s.swim();
        System.out.println("游泳结束~~~");
    }
}

/*学生实现类
class Student implements Swimming{
    @Override
    public void swim() {
        System.out.println("学生在快乐地自由游~~~");
    }
}*/

//游泳接口
interface Swimming {
    void swim();
}

匿名内部类真实使用场景演示

import javax.swing.*;
import java.awt.event.ActionEvent;

//通过GUI编程 理解匿名内部类的真实使用场景
public class Test {
    public static void main(String[] args) {
        //1、创建窗口
        JFrame win = new JFrame("登录界面");
        JPanel panel = new JPanel();//桌布
        win.add(panel);//添加桌布

        //2、创建一个按钮对象
        JButton btn = new JButton("登录");

        /*//注意:创建监听对象 匿名内部类的使用
        btn.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(win, "点我一下,说明爱我~~");//弹窗
            }
        });*/
        
        //简化写法
        btn.addActionListener(e -> JOptionPane.showMessageDialog(win, "点我一下,说明爱我~~"));

        //3、把按钮对象添加到窗口桌布显示
        panel.add(btn);

        //4、展示窗口
        win.setSize(400, 300);//窗口大小
        win.setLocationRelativeTo(null);//窗口居中显示
        win.setVisible(true);
    }
}

常用API

Object

Object类的作用:
    一个类要么默认继承了Object类,要么间接继承了Object类,Object类是Java中的祖宗类。
    Object类的方法是一切子类都可以直接使用的,所以我们要学习Object类的方法。

Object类的常用方法:

方法名说明
public String toString()默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址
public Boolean equals(Object o)默认是比较当前对象与另一个对象的地址是否相同,相同返回true,不同返回false
1. Object的toString方法的作用是什么?
    默认是打印当前对象的地址。
    让子类重写,以便返回子类对象的内容。
public class Student {
    private String name;
    private char sex;
    private int age;

    public Student() {
    }

    public Student(String name, char sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //方法重构toString()
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", age=" + age +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Student s = new Student("阿珍", '女', 20);
//        String rs = s.toString();
//        System.out.println(rs);
//
//        System.out.println(s.toString());
        System.out.println(s);
    }
}

Object的equals方法
存在的意义:父类equals方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则

//isNull()方法的使用
import java.util.Objects;

public class Test {
    public static void main(String[] args) {
        String s1 = new String("Java");
        String s2 = null;

        System.out.println(Objects.isNull(s1));//false
        System.out.println(s1 == null);//false

        System.out.println(Objects.isNull(s2));//true
        System.out.println(s2 == null);//true

    }
}
对象进行内容比较的时候建议使用什么?为什么?
    建议使用Objects提供的equals方法
    比较结果是一样的,但是更安全

StringBuilder

StringBuilder概述
    StringBuilder是一个可变的字符串类,我们可以把它看成是一个对象容器。
    作用:提高字符串的操作效率,如拼接、修改等。

StringBuilder 构造器

名称说明
public StringBuilder()创建一个空白的可变的字符串对象,不包含任何内容
 
public StringBuilder(String str)创建一个指定字符串内容的可变字符串对象

 String Builder常用方法

方法名称说明
public StringBuilder append(任意类型)添加数据并返回StringBuilder对象本身
public StringBuilder reverse()将对象的内容反转
public int length()返回对象内容长度
public String toString()通过toString()就可以实现把StringBuilder转换为String
//学会StringBuilder的操作字符

public class Test {
    public static void main(String[] args) {
        //1、public StringBuilder append(任意类型)  添加数据并返回StringBuilder对象本身
        StringBuilder sb1 = new StringBuilder();
        sb1.append("a");
        sb1.append('b');
        sb1.append("ab");
        sb1.append(1);
        sb1.append(1.5);
        sb1.append(false);
        System.out.println(sb1);//abab11.5false

        StringBuilder sb2 = new StringBuilder();
        //支持链式编程
        sb2.append("abc").append(3).append(5.2).append("Java");
        System.out.println(sb2);//abc35.2Java

        //2、public StringBuilder reverse()	将对象的内容反转
        sb1.reverse().append("我爱你~");
        System.out.println(sb1);//eslaf5.11baba我爱你~

        //3、public int length()	返回对象内容长度
        System.out.println(sb2.length());//11

        //注意:StringBuilder只是拼接字符串的手段:效率高
        //最终的结果还是要恢复成String类型
        StringBuilder sb = new StringBuilder();
        sb.append("123").append("456");
        //check(sb);//sb是StringBuiler类型不是String类型,不能进行传递
        //恢复成String
        String rs = sb.toString();
        check(rs);
    }

    public static void check(String data) {

    }
}

 

1、为什么拼接、反转字符串建议使用StringBuilder?
    String:内容是不可变的、拼接字符串性能差。
    String Builder:内容是可变的、拼接字符串性能好、代码优雅。
    定义字符串使用String
    拼接、修改等操作字符串使用StringBuilder
案例:打印整型数组内容
需求:
    设计一个方法用于输出任意整型数组的内容,要求输出以下格式:
    "[11, 22, 12]"
分析:
    定义一个方法,要求该方法能够接收数组,并输出数组内容(需要参数和返回值类型)
//学会StringBuilder的操作字符

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        int[] arr = null;
        int[] arr1 = {};
        int[] arr2 = {11, 22, 12};

        System.out.println(toString(arr));//null
        System.out.println(toString(arr1));//[]
        System.out.println(toString(arr2));//[11, 22, 12]
    }

    public static String toString(int[] arr) {
        if (arr != null) {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < arr.length; i++) {
                sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", ");
            }
            sb.append("]");
            return sb.toString();
        } else {
            return null;
        }
    }
}

Math

Math类
    包含执行基本数字运算的方法,Math类没有提供公开的构造器。
    如何使用类中的成员呢?看类的成员是否都是静态的,如果是,通过类名就可以直接调用

Math类的常用方法

方法名说明
public static int abs(int a)获取参数绝对值
public static double ceil (double a)向上取整
public static double floor(double a)向下取整
public static int round (float a)四舍五入
public static int max(int a,int b)获取两个int值中的较大值
public static double pow(double a,double b)返回a的b次幂的值
public static double random()返回值为double的随机值,范围[0.0,1.0)
public class Test {
    public static void main(String[] args) {
        //1、public static int abs(int a)	获取参数绝对值
        System.out.println(Math.abs(10));//10
        System.out.println(Math.abs(-10.5));//10.5

        //2、public static double ceil (double a)	向上取整
        System.out.println(Math.ceil(4.00000001));//5
        System.out.println(Math.ceil(4.99999999));//5

        //3、public static double floor(double a)	向下取整
        System.out.println(Math.floor(6.9999999999));//6
        System.out.println(Math.floor(6.00000001));//6

        //4、求指数次方
        System.out.println(Math.pow(2, 3));//2^3=8.0

        //5、四舍五入
        System.out.println(Math.round(4.46));//4
        System.out.println(Math.round(4.54));//5

        //6、public static double random()	返回值为double的随机值,范围[0.0,1.0)
        System.out.println(Math.random());
    }
}

System

System 类概述
System的功能是通用的,都是直接用类名调用即可,所以System不能被实例化。

System 类的常用方法 

方法说明
public static void exit(int status)终止当前运行的Java虚拟机,非零表示异常终止
public static long currentTimeMillis()返回当前系统的时间毫秒值形式
public static void arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数)数组拷贝

BigDecimal

BigDecimal作用
    用于解决浮点型运算精度失真的问题
使用步骤
    创建对象BigDecimal封装浮点型数据(最好的方式是调用方法)
public static BigDecimal valueOf(double val):  包装浮点数成为BigDecimal对象。

  

 BigDecima常用API

方法名说明
public BigDecimal add(BigDecimal b)加法
public BigDecimal subtract(BigDecimal b)减法
public BigDecimal multiply(BigDecimal b)乘法
public BigDecimal divide(BigDecimal b)除法
public Big Decimal divide(另一个BigDecimal对象,精确几位,舍入模式)除法
import java.math.BigDecimal;
import java.math.RoundingMode;

public class Test {
    public static void main(String[] args) {
        System.out.println(0.3+0.4);//0.7
        System.out.println(0.3*0.2);//0.06
        System.out.println("-------------------");
        double a = 0.1;
        double b = 0.2;
        double c = a + b;
        System.out.println(c);//0.30000000000000004

        System.out.println("-------------------");
        //包装浮点数据成为大数据对象BigDecimal
        BigDecimal a1 = BigDecimal.valueOf(a);
        BigDecimal b1 = BigDecimal.valueOf(b);
        BigDecimal c1 = a1.add(b1);
        System.out.println(c1);//0.3

        //目的:double
        double rs  = c1.doubleValue();
        System.out.println(rs);//0.3

        System.out.println("-------------------");

        /*BigDecimal a11 = BigDecimal.valueOf(10.0);
        BigDecimal b11 = BigDecimal.valueOf(3.0);
        BigDecimal c11 = a11.divide(b11);//报错,3.333333
        System.out.println(c11);*/

        //注意事项:BigDecimal是一定要精度运算的
        BigDecimal a11 = BigDecimal.valueOf(10.0);
        BigDecimal b11 = BigDecimal.valueOf(3.0);
       //参数一:除数 参数二:保留小数位数 参数三:舍入模式
        BigDecimal c11 = a11.divide(b11,2, RoundingMode.HALF_UP);
        System.out.println(c11);//3.33
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值