Java面向对象编程

Java面向对象编程

IDEA中快速生成构造方法

  1. Alt + insert
  2. 选择 Constructor

 IDEA中快速生成构造方法
3. 选择构造函数及其参数(以矩形类Rectangle为例)
选择构造函数及其参数(以矩形类Rectangle为例)

同理快速重写方法时按 Alt + insert后,选择 Override Methods

Maven远程仓库 中添加插件依赖

  1. 打开 Maven远程仓库,网址:https://mvnrepository.com
  2. 在搜索框中查找依赖项目
  3. 选择对应版本的依赖,并添加

查看类的源码

1. 选择一个类,以 JDK日期与时间处理类 中用的 ·Calender· 类为例 :
JDK日期与时间处理类中用的 ·Calender
2. 按下 Ctrl + h 打开结构图
结构图
3. 双击该类进入源码
双击该类进入源码

实验要求

一、创建矩形类Rectangle(含关键字this的使用)

(1)在项目文件夹java里,创建名为 unit03 的包。
(2)在包 unit03 里新建名为 Rectangle 的类,并创建 main() 方法体。
(3)定义2个私有属性 lengthwidth ;在IDEA里自动生成有公有、有参构造方法;分别定义显示矩形尺寸和面积的公有方法;在 main() 里实例化 Rectangle 对象并调用业务方法。

二、创建员工类及管理者类(含关键字super、访问权限和方法重写的使用)

(1)新建员工类 Staff,定义包访问权限、String 类型的字段 nameint 类型的 salary
(2)定义类的公有构造方法,以 namesalary 作为参数。
(3)定义返回 namesalary 详细信息的公有实例方法 getDetails()
(4)新建管理者类 Manager 并继承类 Staff ,增加一个表示管理部门、String 类型的字段 department
(5)定义 Manager 类的公有构造方法,以 namesalarydepartment 作为参数,使用 super(name,salary) 调用基类的构造方法。
(6)使用快捷菜单,自动产生重写 getDetails() 方法的方法体,编写代码输出管理者的详细信息(包含namesalarydepartment )。
(7)定义 main() 方法,在其内实例化一个 Staff 对象和一个 Manager 对象,并分别调用实例方法getDetails() ,输出2个对象的相应信息。
(8)对类 Staff 的2个字段使用访问修饰符 protected ,验证程序不需要做任何修改就能正确地运行。
(9)对类 Staff 的2个字段使用访问修饰符 private 。此时,在类 Manager 重写的方法里,出现字段不可访问的错误。
(10)使用快捷菜单,对类Staff产生2个字段的 getter 方法。在类 Manager 重写的方法错误处,使用相应的getter 方法代替后,错误消失,程序能正确运行。
(11)注释类 Staff 产生2个字段的 getter 方法。
(12)确认IDEA已经安装Lombok插件。如果没有,就安装。
(13)在项目里,添加Lombok依赖
(14)对类Staff依次添加注解@Data、@NoArgsConstructor和@AllArgsConstructor后,程序能正常运行。

三、抽象类、接口与多态

(1)查看类 Calendar 的源码,查验本类是使用关键字abstract修饰的抽象类,验证使用 new 实例化时,提示需要重写该类的若干抽象方法。
(2)使用关键字 abstract ,新建抽象类 MessageKind ,声明返回值类型为 String 的抽象方法 getMessage()
(3)分别定义 MessageKind 类的2个子类 SmsQQ ,根据提示重写父类的抽象方法 getMessage() ,分别返回”短信”和“QQ消息”。
(4)定义主类 Student ,包括 String 类型的字段 name
(5)定义类 Student 的公有构造方法,以 name 作为参数。
(6)定义发送消息的方法 sendMessage(String msg) ,输出表达式: name+"在发【"+msg+"】"
(7)定义 main() 方法,实例化一个 Student 对象,并调用方法 sendMessage(String msg) 。其中,msg 的值分别为 SmsQQ 实例化后调用 getMessage() 方法的结果。
要求:总结抽象类的使用。
(8)新建抽象类 Animal ,定义返回值类型为 void 的抽象方法 cry()
(9)分别定义抽象类 Animal 的两个子类 CatDog ,并重写抽象方法 cry() ,分别输出“喵喵叫…“和"汪汪叫…”。
(10)新建多态测试类 PolymorphismDemo1 及其 main() 方法,输入如下代码:

Animal animal=new Cat();  //向上转型
animal.cry();   //动态绑定“猫”
animal=new Dog();
animal.cry();  //动态绑定“狗”

要求:总结抽象类实现多态的使用。
(11)使用关键字 interface ,将上面的抽象类 Animal 改写成接口 Animal
(12)分别使用关键字 implements ,将类 Cat Dog 改写为接口的实现类。
(13)新建多态测试类 PolymorphismDemo2 及其 main() 方法,测试代码同上。
要求:总结接口也能实现多态。
(14)将上面的 Animal 还原为抽象类、CatDog 还原为继承抽象类。
(15)新建两个接口 BirdFish ,分别定义 void 类型的抽象方法 flying()swimming()
(16)定义类 LittleMonkey ,继承抽象类 Animal ,并同时实现接口 BirdFish
(17)按照提示,需要重写抽象方法cry(),输出:“吱吱声…”;实现接口方法 flying() ,输出:“我像鸟儿,会飞”;重写接口方法swimming(),输出:“我像鱼儿,会游”。
(18)新建多态测试类 PolymorphismDemo3 及其 main() 方法,输入如下测试代码:

LittleMonkey aMonkey=new LittleMonkey();  
aMonkey.cry();  
aMonkey.flying();   //动态绑定“小鸟”
aMonkey.swimming();  //动态绑定“鱼”
//如果定义变量aMonkey时,若使用类型 Animal或Bird或Fish,将会出现什么编译错误? 请仔细分析。

四、Java面向对象的高级特性(内部类、匿名对象、反射、Lambda表达式)

(1)新建类名 OuterCWithInnerClassDemo,定义私有int类型的变量 num ,初值为 2 ,定义私有 void 类型的方法 addOneNum() ,功能是将 num 加一并输出现在的数字。
(2)定义私有内部类 InnerClass ,新增方法 getOneNum() ,功能是将 num 减1并输出现在的数字,新增方法 putOneNum() ,功能是调用方法 addOneNum()
(3)为外部类 OuterCWithInnerClassDemo 新增方法 visitPrivateMembersByInnerClass() ,功能是先输出变量 num 的值,再新建一个内部类对象,并调用方法 getOneNum() 和方法 putOneNum()
(4)新建主类 testOuterInnerClassDemo 和添加 main() 方法,实例化一个外部类对象,并调用方法visitPrivateMembersByInnerClass() ,观察程序输出的结果。
要求:有代码截图,总结内部类的使用
(5)新建接口 ISay,声明一个 void 类型的抽象方法 sayHello()
(6)新建主类 testAnnoyInnerDemo()main() 方法,定义一个 ISay 类型的变量(对象)mySay,指向实现此接口的匿名类(无名内部类),在类体中重写方法 sayHello() ,输出 “Hello Java!”
(7)通过对象 mySay 调用方法 sayHello() ,观察程序的输出结果。
要求:有代码截图,总结匿名内部类的使用
(8)定义类类型为 Class<OuterC> 的对象 clazz ,其值为 OuterCWithInnerClassDemo.class , 并通过 clazz 对象调用泛型类 Class<?> 的实例方法newInstance() 并强转类型,间接创建类 OuterCWithInnerClassDemo 的实例对象 aObj
(9)通过对象 clazz 调用方法 getDeclaredMethod(String methodName, Calss<?> parameterTypes) ,指出参数1为私有方法名 "addOneNum" ,获得此方法的 Method 对象 aMethod
(10)设置在类外允许访问私有方法,语句是:aMethod.setAccessible(true);
(11)通过 Java 反射机制,在类的外部调用该类的私有方法,语句是:aMethod.invoke(aObj) ,观察程序的输出结果。
要求:有代码截图,总结Java反射的使用
(12)定义一个 iSay 类型的变量 lamSay ,并赋值为: ()->System.out.println("Hello Java!");
(13)执行语句: lamSay.sayHello(); 观察程序的输出结果。
要求:有代码截图,总结使用Lambda表达式,简化接口类型对象的创建

代码参考

创建矩形类Rectangle(含关键字this的使用)

1. 在项目文件夹 java 里,创建名为 unit03 的包。
// 在包 unit03 里新建名为 Rectangle 的类,并创建 main() 方法体。
public class Rectangle {
    public static void main(String[] args) {
        
    }
}
2. 定义2个私有属性 lengthwidth ;在IDEA里自动生成有公有、有参构造方法;分别定义显示矩形尺寸和面积的公有方法
// 在包 unit03 里新建名为 Rectangle 的类,并创建 main() 方法体。
public class Rectangle {
    // 定义2个私有属性length和width
    private double length, width;

    //公有的构造方法
    public Rectangle(double length, double width) {
        this.length = 1;
        this.width = width;
        //函数参数可以与类属性同名。此时,需要使用关键字this
    }

    public double getPerimeter() {  //公有的成员方法
        return 2 * (length + width);
    }

    public double getArea() {
        return length * width;
    }

    public void showSize() {
        System.out.println("length=" + length + ", width=" + width);
    }

    public static void main(String[] args) {

    }


}
3. 在 main() 里实例化 Rectangle 对象并调用业务方法。
    // 在 main() 里实例化 Rectangle 对象并调用业务方法。
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(3.5, 4); //创建类的实例对象
        rectangle.showSize();
        System.out.println("此矩阵的面积是:"+rectangle.getArea());
    }
4. 矩形类 Rectangle 完整代码
package unit03;

// 在包 unit03 里新建名为 Rectangle 的类,并创建 main() 方法体。
public class Rectangle {
    // 定义2个私有属性length和width
    private double length, width;

    //公有的构造方法
    public Rectangle(double length, double width) {
        this.length = 1;
        this.width = width;
        //函数参数可以与类属性同名。此时,需要使用关键字this
    }

    public double getPerimeter() {  //公有的成员方法
        return 2 * (length + width);
    }

    public double getArea() {
        return length * width;
    }

    public void showSize() {
        System.out.println("length=" + length + ", width=" + width);
    }

    // 在 main() 里实例化 Rectangle 对象并调用业务方法。
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(3.5, 4); //创建类的实例对象
        rectangle.showSize();
        System.out.println("此矩阵的面积是:"+rectangle.getArea());
    }
}

运行截图

运行截图

二、创建员工类及管理者类(含关键字super、访问权限和方法重写的使用)

1. 新建员工类 Staff,定义包访问权限、String 类型的字段 nameint 类型的 salary
public class Staff {
    // 新建员工类 Staff,定义包访问权限、String 类型的字段 name 和 int 类型的 salary 。
    String name;
    int salary;
}
2. 定义类的公有构造方法,以 namesalary 作为参数。
    // 定义类的公有构造方法,以 name 和 salary 作为参数。
    public Staff(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
3. 定义返回 namesalary 详细信息的公有实例方法 getDetails()
    // 定义返回name和salary详细信息的公有实例方法getDetails()。
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n", this.name, this.salary);
    }
4. 新建管理者类 Manager 并继承类 Staff ,增加一个表示管理部门、String 类型的字段 department
// 新建管理者类 Manager 并继承类 Staff ,增加一个表示管理部门、 String 类型的字段 department。
public class Manager extends Staff {
    String department;
}
5. 定义 Manager 类的公有构造方法,以 namesalarydepartment 作为参数,使用 super(name,salary) 调用基类的构造方法。
    // 定义 Manager 类的公有构造方法,以 name ,salary 和 department 作为参数,使用 super(name,salary) 调用基类的构造方法。
    public Manager(String name, int salary, String department) {
        super(name, salary);
        this.department = department;
    }
6. 使用快捷菜单,自动产生重写 getDetails() 方法的方法体,编写代码输出管理者的详细信息(包含namesalarydepartment )。
    // 使用快捷菜单,自动产生重写 getDetails() 方法的方法体,编写代码输出管理者的详细信息(包含 name 、 salary 和 department )。
    @Override
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n部门:%s\n", this.name, this.salary, this.department);
        System.out.println();
    }
7. 定义 main() 方法,在其内实例化一个 Staff 对象和一个 Manager 对象,并分别调用实例方法getDetails() ,输出2个对象的相应信息。
    // 定义 main() 方法,在其内实例化一个 Staff 对象和一个 Manager 对象,并分别调用实例方法 getDetails() ,输出2个对象的相应信息。
    public static void main(String[] args) {
        Staff staff = new Staff("张翼德",50000);
        staff.getDetails();

        System.out.println();

        Manager manager = new Manager("刘玄德", 50000, "主公");
        manager.getDetails();
    }
Staff 类中
package unit03;

public class Staff {
    // 新建员工类 Staff,定义包访问权限、String 类型的字段 name 和 int 类型的 salary 。
    String name;
    int salary;

    // 定义类的公有构造方法,以 name 和 salary 作为参数。
    public Staff(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    // 定义返回name和salary详细信息的公有实例方法getDetails()。
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n", this.name, this.salary);
    }
}

Manger类中
package unit03;

// 新建管理者类 Manager 并继承类 Staff ,增加一个表示管理部门、 String 类型的字段 department。
public class Manager extends Staff {

    // 定义 Manager 类的公有构造方法,以 name ,salary 和 department 作为参数,使用 super(name,salary) 调用基类的构造方法。
    String department;

    public Manager(String name, int salary, String department) {
        super(name, salary);
        this.department = department;
    }

    // 使用快捷菜单,自动产生重写 getDetails() 方法的方法体,编写代码输出管理者的详细信息(包含 name 、 salary 和 department )。
    @Override
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n部门:%s\n", this.name, this.salary, this.department);
        System.out.println();
    }

    // 定义 main() 方法,在其内实例化一个 Staff 对象和一个 Manager 对象,并分别调用实例方法 getDetails() ,输出2个对象的相应信息。
    public static void main(String[] args) {
        Staff staff = new Staff("张翼德", 50000);
        staff.getDetails();

        System.out.println();

        Manager manager = new Manager("刘玄德", 50000, "主公");
        manager.getDetails();
    }
}


运行截图

8. 对类 Staff 的2个字段使用访问修饰符 protected ,验证程序不需要做任何修改就能正确地运行。
Staff 类中
package unit03;

public class Staff {
    // 新建员工类 Staff,定义包访问权限、String 类型的字段 name 和 int 类型的 salary 。
    protected String name;
    protected int salary;

    // 定义类的公有构造方法,以 name 和 salary 作为参数。
    public Staff(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    // 定义返回name和salary详细信息的公有实例方法getDetails()。
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n", this.name, this.salary);
    }
}

运行截图

9. 对类 Staff 的2个字段使用访问修饰符 private 。此时,在类 Manager 重写的方法里,出现字段不可访问的错误。
package unit03;

public class Staff {
    // 新建员工类 Staff,定义包访问权限、String 类型的字段 name 和 int 类型的 salary 。
    private String name;
    private int salary;

    // 定义类的公有构造方法,以 name 和 salary 作为参数。
    public Staff(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    // 定义返回name和salary详细信息的公有实例方法getDetails()。
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n", this.name, this.salary);
    }
}

在这里插入图片描述

10. 使用快捷菜单,对类Staff产生2个字段的 getter 方法。在类 Manager 重写的方法错误处,使用相应的getter 方法代替后,错误消失,程序能正确运行。
package unit03;

// 新建管理者类 Manager 并继承类 Staff ,增加一个表示管理部门、 String 类型的字段 department。
public class Manager extends Staff {

    // 定义 Manager 类的公有构造方法,以 name ,salary 和 department 作为参数,使用 super(name,salary) 调用基类的构造方法。
    String department;

    public Manager(String name, int salary, String department) {
        super(name, salary);
        this.department = department;
    }

    // 使用快捷菜单,自动产生重写 getDetails() 方法的方法体,编写代码输出管理者的详细信息(包含 name 、 salary 和 department )。
    // 在类Manager重写的方法错误处,使用相应的getter方法代替后,错误消失,程序能正确运行。
    @Override
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n部门:%s\n", this.getName(), this.getSalary(), this.department);
        System.out.println();
    }

    // 定义 main() 方法,在其内实例化一个 Staff 对象和一个 Manager 对象,并分别调用实例方法 getDetails() ,输出2个对象的相应信息。
    public static void main(String[] args) {
        Staff staff = new Staff("张翼德", 50000);
        staff.getDetails();

        System.out.println();

        Manager manager = new Manager("刘玄德", 50000, "主公");
        manager.getDetails();
    }
}

在这里插入图片描述

11. 注释类 Staff 产生2个字段的 getter 方法。
确认IDEA已经安装Lombok插件。如果没有,就安装。此为安装演示:

1, 找到IDEA的 settings —— plugin选项 —— 搜索Lombok —— OK
在这里插入图片描述

在这里插入图片描述
2. 在 Maven远程仓库 中查找插件的依赖
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
3. 在 pom.xml 中添加该插件的依赖
在这里插入图片描述
4. 点击 · Reload· 图标重新加载
在这里插入图片描述
5. 添加注释

package unit03;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Staff {
    // 新建员工类 Staff,定义包访问权限、String 类型的字段 name 和 int 类型的 salary 。
    private String name;
    private int salary;

    // 对类 Staff 产生2个字段的 getter 方法。
    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

    // 定义返回name和salary详细信息的公有实例方法getDetails()。
    public void getDetails() {
        System.out.printf("姓名:%s\n工资:%d\n", this.name, this.salary);
    }
}

注意:添加 @AllArgsConstructor 注释时删除了原有构造函数
在这里插入图片描述

三、抽象类、接口与多态

1. 查看类 Calendar 的源码,查验本类是使用关键字abstract修饰的抽象类,验证使用 new 实例化时,提示需要重写该类的若干抽象方法。
查看类 Calendar 的源码
  1. 选择一个类,以 JDK日期与时间处理类 中用的 ·Calender· 类为例 :
    JDK日期与时间处理类中用的 ·Calender
  2. 按下 Ctrl + h 打开结构图
    结构图
  3. 双击该类进入源码
    双击该类进入源码
查验本类是使用关键字abstract修饰的抽象类

查验本类是使用关键字abstract修饰的抽象类

验证使用 new 实例化时,提示需要重写该类的若干抽象方法。
Calendar calendar = new Calendar();

提示 Calendar 是抽象类,不可以被实例化
在这里插入图片描述

2. 使用关键字 abstract ,新建抽象类 MessageKind ,声明返回值类型为 String 的抽象方法 getMessage()

抽象类 MessageKind

public abstract class MessageKind {
    public abstract String getMessage();
}
3. 分别定义 MessageKind 类的2个子类 SmsQQ ,根据提示重写父类的抽象方法 getMessage() ,分别返回”短信”和“QQ消息”。

子类 Sms

public class Sms extends MessageKind {

    @Override
    public String getMessage() {
        return "短信";
    }
}

子类 QQ

public class QQ extends MessageKind{
    @Override
    public String getMessage() {
        return "QQ消息";
    }
}
4. 定义主类 Student ,包括 String 类型的字段 name

主类 Student

public class Student {
    String name;
}

5. 定义类 Student 的公有构造方法,以 name 作为参数。
public class Student {
    String name;

    public Student(String name) {
        this.name = name;
    }
}
6. 定义发送消息的方法 sendMessage(String msg) ,输出表达式: name+"在发【"+msg+"】"
    // 定义发送消息的方法 sendMessage(String msg) ,输出表达式: name + " 在发【"+msg+"】"
    public void sendMessage(String msg) {
        System.out.println(name + "在发【" + msg + "】");
    }
7. 定义 main() 方法,实例化一个 Student 对象,并调用方法 sendMessage(String msg) 。其中,msg 的值分别为 SmsQQ 实例化后调用 getMessage() 方法的结果。
    public static void main(String[] args) {
        Student student = new Student("诸葛亮");
        Sms sms = new Sms();
        QQ qq = new QQ();
        student.sendMessage(sms.getMessage());
        student.sendMessage(qq.getMessage());
    }

完整代码:
主类 Student

package unit03;

// 定义主类 Student ,包括 String 类型的字段 name
public class Student {

    String name;

    //  定义类 Student 的公有构造方法,以 name 作为参数
    public Student(String name) {
        this.name = name;
    }

    // 定义发送消息的方法 sendMessage(String msg) ,输出表达式: name + " 在发【"+msg+"】"
    public void sendMessage(String msg) {
        System.out.println(name + "在发【" + msg + "】");
    }

    public static void main(String[] args) {
        Student student = new Student("诸葛亮");
        Sms sms = new Sms();
        QQ qq = new QQ();
        student.sendMessage(sms.getMessage());
        student.sendMessage(qq.getMessage());
    }
}

抽象类 MessageKind

package unit03;

// 使用关键字 abstract ,新建抽象类 MessageKind ,声明返回值类型为 String 的抽象方法 getMessage()
public abstract class MessageKind {
    public abstract String getMessage();
}

子类 Sms

package unit03;

public class Sms extends MessageKind {

    @Override
    public String getMessage() {
        return "短信";
    }
}

子类 QQ

package unit03;

public class QQ extends MessageKind{
    @Override
    public String getMessage() {
        return "QQ消息";
    }
}

运行截图
在这里插入图片描述
要求:总结抽象类的使用。

8. 新建抽象类 Animal ,定义返回值类型为 void 的抽象方法 cry()
// 新建抽象类Animal,定义返回值类型为void的抽象方法cry()。
public abstract class Animal {
    public abstract void cry();
}

9. 分别定义抽象类 Animal 的两个子类 CatDog ,并重写抽象方法 cry() ,分别输出“喵喵叫…“和"汪汪叫…”。

子类 Cat

package unit03;

// 定义抽象类 Animal 的两个子类 Cat ,并重写抽象方法 cry() ,输出“喵喵叫…“。
public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("喵喵叫…");
    }
}

子类 Dog

package unit03;

// 定义抽象类 Animal 的子类 Dog ,并重写抽象方法 cry() ,输出"汪汪叫…”
public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println("汪汪叫…");
    }
}

(10)新建多态测试类 PolymorphismDemo1 及其 main() 方法,输入如下代码:

Animal animal=new Cat();  //向上转型
animal.cry();   //动态绑定“猫”
animal=new Dog();
animal.cry();  //动态绑定“狗”

完整代码:
抽象类 Animal

package unit03;

// 抽象类包含抽象方法,都要使用关键字abstract修饰
// 抽象类可以定义属性、构造方法和普通方法等成员,但至少应包含一个抽象方法
// 抽象方法不能使用private、final和static等修饰符
// 抽象类不能直接被 new来创建其实例

// 新建抽象类Animal,定义返回值类型为void的抽象方法cry()。
public abstract class Animal {
    public abstract void cry();
}

子类 Cat

package unit03;

// 定义抽象类 Animal 的子类 Cat ,并重写抽象方法 cry() ,输出“喵喵叫…“。
public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("喵喵叫…");
    }
}

子类 Dog

package unit03;

// 定义抽象类 Animal 的子类 Dog ,并重写抽象方法 cry() ,输出"汪汪叫…”
public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println("汪汪叫…");
    }
}

多态测试类 PolymorphismDemo1

package unit03;

// 新建多态测试类 PolymorphismDemo1 及其 main() 方法
public class PolymorphismDemo1 {
    public static void main(String[] args) {
        Animal animal=new Cat();  //向上转型
        animal.cry();   //动态绑定“猫”
        animal=new Dog();
        animal.cry();  //动态绑定“狗”
    }
}

运行截图:
在这里插入图片描述

11. 使用关键字 interface ,将上面的抽象类 Animal 改写成接口 Animal

抽象类 Animal

// 使用关键字interface,将上面的抽象类Animal改写成接口Animal
interface Animal {
    void cry(); // 等效于使用 public 修改
}
12. 分别使用关键字 implements ,将类 Cat Dog 改写为接口的实现类。

Cat

public class Cat implements Animal{
    @Override
    public void cry() {
        System.out.println("喵喵叫…");
    }
}

Dog

public class Dog implements Animal{
    @Override
    public void cry() {
        System.out.println("汪汪叫…");
    }
}
13. 新建多态测试类 PolymorphismDemo2 及其 main() 方法,测试代码同上。

完整代码:
多态测试类 PolymorphismDemo2

public class PolymorphismDemo2 {
    public static void main(String[] args) {
        Animal animal=new Cat();  //向上转型
        animal.cry();   //动态绑定“猫”
        animal=new Dog();
        animal.cry();  //动态绑定“狗”
    }
}
14. 将上面的 Animal 还原为抽象类、CatDog 还原为继承抽象类。

抽象类 Animal

package unit03;

// 抽象类包含抽象方法,都要使用关键字abstract修饰
// 抽象类可以定义属性、构造方法和普通方法等成员,但至少应包含一个抽象方法
// 抽象方法不能使用private、final和static等修饰符
// 抽象类不能直接被 new来创建其实例

// 新建抽象类Animal,定义返回值类型为void的抽象方法cry()。
public abstract class Animal {
    public abstract void cry();
}

子类 Cat

package unit03;

// 定义抽象类 Animal 的子类 Cat ,并重写抽象方法 cry() ,输出“喵喵叫…“。
public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("喵喵叫…");
    }
}

子类 Dog

package unit03;

// 定义抽象类 Animal 的子类 Dog ,并重写抽象方法 cry() ,输出"汪汪叫…”
public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println("汪汪叫…");
    }
}

多态测试类 PolymorphismDemo1

package unit03;

// 新建多态测试类 PolymorphismDemo1 及其 main() 方法
public class PolymorphismDemo1 {
    public static void main(String[] args) {
        Animal animal=new Cat();  //向上转型
        animal.cry();   //动态绑定“猫”
        animal=new Dog();
        animal.cry();  //动态绑定“狗”
    }
}
15. 新建两个接口 BirdFish ,分别定义 void 类型的抽象方法 flying()swimming()

接口 Bird

// 新建两个接口Bird,定义void类型的抽象方法flying()
public interface Bird {
    abstract void flying();
}

接口 Fish

// 新建两个接口Fish,定义void类型的抽象方法swimming()
public interface Fish {
    abstract void swimming();
}
16. 定义类 LittleMonkey ,继承抽象类 Animal ,并同时实现接口 BirdFish

LittleMonkey

// 定义类 LittleMonkey ,继承抽象类 Animal ,并同时实现接口 Bird和Fish 
public class LittleMonkey extends Animal implements Bird,Fish{
    @Override
    public void cry() {

    }

    @Override
    public void flying() {

    }

    @Override
    public void swimming() {

    }
}

17. 按照提示,需要重写抽象方法cry(),输出:“吱吱声…”;实现接口方法 flying() ,输出:“我像鸟儿,会飞”;重写接口方法swimming(),输出:“我像鱼儿,会游”。

LittleMonkey

// 定义类 LittleMonkey ,继承抽象类 Animal ,并同时实现接口 Bird和Fish
public class LittleMonkey extends Animal implements Bird,Fish{
    
    // 重写抽象方法cry(),输出:“吱吱声...”;
    // 实现接口方法flying(),输出:“我像鸟儿,会飞”
    // 实现接口方法swimming(),输出:“我像鱼儿,会游”。
    @Override
    public void cry() {
        System.out.println("吱吱声...”");
    }

    @Override
    public void flying() {
        System.out.println("我像鸟儿,会飞");
    }

    @Override
    public void swimming() {
        System.out.println("我像鱼儿,会游");
    }
}
18. 新建多态测试类 PolymorphismDemo3 及其 main() 方法,输入如下测试代码:
LittleMonkey aMonkey=new LittleMonkey();  
aMonkey.cry();  
aMonkey.flying();   //动态绑定“小鸟”
aMonkey.swimming();  //动态绑定“鱼”

完整代码:

多态测试类 PolymorphismDemo3

// 新建多态测试类PolymorphismDemo3及其main()方法
public class PolymorphismDemo3 {
    public static void main(String[] args) {
        LittleMonkey aMonkey=new LittleMonkey();
        aMonkey.cry();
        aMonkey.flying();   //动态绑定“小鸟”
        aMonkey.swimming();  //动态绑定“鱼”
    }
}

接口 Bird

// 新建两个接口Bird,定义void类型的抽象方法flying()
public interface Bird {
    abstract void flying();
}

接口 Fish

// 新建两个接口Fish,定义void类型的抽象方法swimming()
public interface Fish {
    abstract void swimming();
}

LittleMonkey

// 定义类 LittleMonkey ,继承抽象类 Animal ,并同时实现接口 Bird和Fish
public class LittleMonkey extends Animal implements Bird,Fish{
    
    // 重写抽象方法cry(),输出:“吱吱声...”;
    // 实现接口方法flying(),输出:“我像鸟儿,会飞”
    // 实现接口方法swimming(),输出:“我像鱼儿,会游”。
    @Override
    public void cry() {
        System.out.println("吱吱声...”");
    }

    @Override
    public void flying() {
        System.out.println("我像鸟儿,会飞");
    }

    @Override
    public void swimming() {
        System.out.println("我像鱼儿,会游");
    }
}

抽象类 Animal

package unit03;

// 抽象类包含抽象方法,都要使用关键字abstract修饰
// 抽象类可以定义属性、构造方法和普通方法等成员,但至少应包含一个抽象方法
// 抽象方法不能使用private、final和static等修饰符
// 抽象类不能直接被 new来创建其实例

// 新建抽象类Animal,定义返回值类型为void的抽象方法cry()。
public abstract class Animal {
    public abstract void cry();
}

子类 Cat

package unit03;

// 定义抽象类 Animal 的子类 Cat ,并重写抽象方法 cry() ,输出“喵喵叫…“。
public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("喵喵叫…");
    }
}

子类 Dog

package unit03;

// 定义抽象类 Animal 的子类 Dog ,并重写抽象方法 cry() ,输出"汪汪叫…”
public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println("汪汪叫…");
    }
}

运行截图:
在这里插入图片描述

使用接口能克服Java单继承的不足,接口间接实现多继承

四、Java面向对象的高级特性(内部类、匿名对象、反射、Lambda表达式)

1. 新建类名 OuterCWithInnerClassDemo,定义私有int类型的变量 num ,初值为 2 ,定义私有 void 类型的方法 addOneNum() ,功能是将 num 加一并输出现在的数字。

外部类 OuterCWithInnerClassDemo

// 新建类名OuterCWithInnerClassDemo,定义私有int类型的变量num,初值为2,定义私有void类型的方法addOneNum()
// 功能是将num加一并输出现在的数字
public class OuterCWithInnerClassDemo {
    private int num = 2;
    private void addOneNum(){  //私有方法;加 1并输出
        num++;
        System.out.println("num="+num);
    }
}
2. 定义私有内部类 InnerClass ,新增方法 getOneNum() ,功能是将 num 减1并输出现在的数字,新增方法 putOneNum() ,功能是调用方法 addOneNum()

外部类 OuterCWithInnerClassDemo

// 新建类名OuterCWithInnerClassDemo,定义私有int类型的变量num,初值为2,定义私有void类型的方法addOneNum()
// 功能是将num加一并输出现在的数字
public class OuterCWithInnerClassDemo {
    private int num = 2;

    private void addOneNum() {  //私有方法;加 1并输出
        num++;
        System.out.println("num=" + num);
    }

    // 定义私有内部类InnerC,新增方法getOneNum(),功能是将num减1并输出现在的数字,新增方法putOneNum(),功能是调用方法addOneNum()
    private class InnerClass {  //私有内部类
        void getOneNum() {  //减 1并输出
            num--;
            System.out.println(num);
        }

        void putOneNum() {
            addOneNum();  //调用外部类的私有方法
        }
    }
}

3. 为外部类 OuterCWithInnerClassDemo 新增方法 visitPrivateMembersByInnerClass() ,功能是先输出变量 num 的值,再新建一个内部类对象,并调用方法 getOneNum() 和方法 putOneNum()

外部类 OuterCWithInnerClassDemo

    // 为外部类OuterC新增方法visitPrivateMembersByInnerClass(),功能是先输出变量num的值
    // 再新建一个内部类对象,并调用方法getOneNum()和方法putOneNum()。
    public void visitPrivateMembersByInnerClass() {
        System.out.println(num);  //输出:2
        InnerClass innerClass = new InnerClass();  //创建内部类对象
        innerClass.getOneNum();  //输出:1
        innerClass.putOneNum();  //输出:num=2
    }
4. 新建主类 testOuterInnerClassDemo 和添加 main() 方法,实例化一个外部类对象,并调用方法visitPrivateMembersByInnerClass() ,观察程序输出的结果。

完整代码:
主类 testOuterInnerClassDemo

package unit03;

// 新建主类testOuterInnerClassDemo和添加main()方法
// 实例化一个外部类对象,并调用方法visitPrivateMembersByInnerClass(),观察程序输出的结果。
public class testOuterInnerClassDemo {
    public static void main(String[] args) {
        OuterCWithInnerClassDemo outerCWithInnerClassDemo = new OuterCWithInnerClassDemo();
        outerCWithInnerClassDemo.visitPrivateMembersByInnerClass();
    }
}

外部类 OuterCWithInnerClassDemo

    // 为外部类OuterC新增方法visitPrivateMembersByInnerClass(),功能是先输出变量num的值
    // 再新建一个内部类对象,并调用方法getOneNum()和方法putOneNum()。
    public void visitPrivateMembersByInnerClass() {
        System.out.println(num);  //输出:2
        InnerClass innerClass = new InnerClass();  //创建内部类对象
        innerClass.getOneNum();  //输出:1
        innerClass.putOneNum();  //输出:num=2
    }

运行截图:
在这里插入图片描述

5. 新建接口 ISay,声明一个 void 类型的抽象方法 sayHello()

接口 ISay

// 新建接口 ISay,声明一个 void 类型的抽象方法 sayHello()
public interface iSay {
    abstract void sayHello();
}

6. 新建主类 testAnnoyInnerDemo()main() 方法,定义一个 ISay 类型的变量(对象)mySay,指向实现此接口的匿名类(无名内部类),在类体中重写方法 sayHello() ,输出 “Hello Java!”

主类 testAnnoyInnerDemo()

// 新建主类testAnnoyInnerDemo()和main()方法
// 定义一个ISay类型的变量(对象)mySay,指向实现此接口的匿名类(无名内部类),在类体中重写方法sayHello(),输出“Hello Java!”
public class testAnnoyInnerDemo {
    public static void main(String[] args) {
        iSay maSay = new iSay() {
            @Override
            public void sayHello() {
                System.out.println("Hello Java!");
            }
        };
    }
}
7. 通过对象 mySay 调用方法 sayHello() ,观察程序的输出结果。

主类 testAnnoyInnerDemo()

package unit03;

// 新建主类testAnnoyInnerDemo()和main()方法
// 定义一个ISay类型的变量(对象)mySay,指向实现此接口的匿名类(无名内部类),在类体中重写方法sayHello(),输出“Hello Java!”
public class testAnnoyInnerDemo {
    public static void main(String[] args) {
        iSay maSay = new iSay() {
            @Override
            public void sayHello() {
                System.out.println("Hello Java!");
            }
        };

        // 通过对象 mySay 调用方法 sayHello() ,观察程序的输出结果。
        maSay.sayHello();
    }
}

接口 ISay

// 新建接口 ISay,声明一个 void 类型的抽象方法 sayHello()
public interface iSay {
    abstract void sayHello();
}

在这里插入图片描述

8. 定义类类型为 Class<OuterC> 的对象 clazz ,其值为 OuterCWithInnerClassDemo.class , 并通过 clazz 对象调用泛型类 Class<?> 的实例方法newInstance() 并强转类型,间接创建类 OuterCWithInnerClassDemo 的实例对象 aObj

主类 testAnnoyInnerDemo()

package unit03;

// 新建主类testAnnoyInnerDemo()和main()方法
// 定义一个ISay类型的变量(对象)mySay,指向实现此接口的匿名类(无名内部类),在类体中重写方法sayHello(),输出“Hello Java!”
public class testAnnoyInnerDemo {
    public static void main(String[] args) throws Exception {
        iSay maSay = new iSay() {
            @Override
            public void sayHello() {
                System.out.println("Hello Java!");
            }
        };

        // 通过对象 mySay 调用方法 sayHello() ,观察程序的输出结果。
        maSay.sayHello();

        // 定义类类型为 Class<OuterC> 的对象 clazz ,其值为 OuterCWithInnerClassDemo.class
        // 并通过 clazz 对象调用泛型类 Class<?> 的实例方法 newInstance() 并强转类型
        // 间接创建类 OuterCWithInnerClassDemo 的实例对象aObj
        Class<?> clazz = OuterCWithInnerClassDemo.class;  //类型(类或接口)信息,此方式更加通用
        OuterCWithInnerClassDemo aObj = (OuterCWithInnerClassDemo) clazz.newInstance();
    }
}

9. 通过对象 clazz 调用方法 getDeclaredMethod(String methodName, Calss<?> parameterTypes) ,指出参数1为私有方法名 "addOneNum" ,获得此方法的 Method 对象 aMethod

主类 testAnnoyInnerDemo()

        // 通过对象 clazz 调用方法 getDeclaredMethod(String methodName, Class<?> parameterTypes)
        // 指出 参数1 为私有方法名"addOneNum",获得此方法的Method对象aMethod。
        Method aMethod = clazz.getDeclaredMethod("addOneNum",null);
10. 设置在类外允许访问私有方法,语句是:aMethod.setAccessible(true);

主类 testAnnoyInnerDemo()

        // 通过对象 clazz 调用方法 getDeclaredMethod(String methodName, Class<?> parameterTypes)
        // 指出 参数1 为私有方法名"addOneNum",获得此方法的Method对象aMethod。
        Method aMethod = clazz.getDeclaredMethod("addOneNum",null);
        // 设置在类外允许访问私有方法,语句是:aMethod.setAccessible(true);
        aMethod.setAccessible(true);
11. 通过 Java 反射机制,在类的外部调用该类的私有方法,语句是:aMethod.invoke(aObj) ,观察程序的输出结果。
        // 通过对象 clazz 调用方法 getDeclaredMethod(String methodName, Class<?> parameterTypes)
        // 指出 参数1 为私有方法名"addOneNum",获得此方法的Method对象aMethod。
        Method aMethod = clazz.getDeclaredMethod("addOneNum",null);
        // 设置在类外允许访问私有方法,语句是:aMethod.setAccessible(true);
        aMethod.setAccessible(true);
        // 通过Java反射机制,在类的外部调用该类的私有方法,语句是:aMethod.invoke(aObj)
        aMethod.invoke(aObj);

完整代码:
主类 testAnnoyInnerDemo()

package unit03;

import java.lang.reflect.Method;

// 新建主类testAnnoyInnerDemo()和main()方法
// 定义一个ISay类型的变量(对象)mySay,指向实现此接口的匿名类(无名内部类),在类体中重写方法sayHello(),输出“Hello Java!”
public class testAnnoyInnerDemo {
    public static void main(String[] args) throws Exception {
        iSay maSay = new iSay() {
            @Override
            public void sayHello() {
                System.out.println("Hello Java!");
            }
        };

        // 通过对象 mySay 调用方法 sayHello() ,观察程序的输出结果。
        maSay.sayHello();

        // 定义类类型为 Class<OuterC> 的对象 clazz ,其值为 OuterCWithInnerClassDemo.class
        // 并通过 clazz 对象调用泛型类 Class<?> 的实例方法 newInstance() 并强转类型
        // 间接创建类 OuterCWithInnerClassDemo 的实例对象aObj
        Class<?> clazz = OuterCWithInnerClassDemo.class;  //类型(类或接口)信息,此方式更加通用
        OuterCWithInnerClassDemo aObj = (OuterCWithInnerClassDemo) clazz.newInstance();

        // 通过对象 clazz 调用方法 getDeclaredMethod(String methodName, Class<?> parameterTypes)
        // 指出 参数1 为私有方法名"addOneNum",获得此方法的Method对象aMethod。
        Method aMethod = clazz.getDeclaredMethod("addOneNum",null);
        // 设置在类外允许访问私有方法,语句是:aMethod.setAccessible(true);
        aMethod.setAccessible(true);
        // 通过Java反射机制,在类的外部调用该类的私有方法,语句是:aMethod.invoke(aObj)
        aMethod.invoke(aObj);
    }
}

接口 ISay

// 新建接口 ISay,声明一个 void 类型的抽象方法 sayHello()
public interface iSay {
    abstract void sayHello();
}

运行截图:
在这里插入图片描述

12. 定义一个 iSay 类型的变量 lamSay ,并赋值为: ()->System.out.println("Hello Java!");

主类 testAnnoyInnerDemo()

    // 定义一个iSay类型的变量lamSay,并赋值为: ()->System.out.println("Hello Java!")
    iSay lamSay = () -> System.out.println("Hello Java!");

(13)执行语句: lamSay.sayHello(); 观察程序的输出结果。
主类 testAnnoyInnerDemo()

        // 定义一个iSay类型的变量lamSay,并赋值为: ()->System.out.println("Hello Java!")
        iSay lamSay = () -> System.out.println("Hello Java!");
        // 执行语句: lamSay.sayHello(); 观察程序的输出结果。
        lamSay.sayHello();

完整代码:
主类 testAnnoyInnerDemo()

package unit03;

import java.lang.reflect.Method;

// 新建主类testAnnoyInnerDemo()和main()方法
// 定义一个ISay类型的变量(对象)mySay,指向实现此接口的匿名类(无名内部类),在类体中重写方法sayHello(),输出“Hello Java!”
public class testAnnoyInnerDemo {
    public static void main(String[] args) throws Exception {
        iSay maSay = new iSay() {
            @Override
            public void sayHello() {
                System.out.println("Hello Java!");
            }
        };

        // 通过对象 mySay 调用方法 sayHello() ,观察程序的输出结果。
        maSay.sayHello();

        // 定义类类型为 Class<OuterC> 的对象 clazz ,其值为 OuterCWithInnerClassDemo.class
        // 并通过 clazz 对象调用泛型类 Class<?> 的实例方法 newInstance() 并强转类型
        // 间接创建类 OuterCWithInnerClassDemo 的实例对象aObj
        Class<?> clazz = OuterCWithInnerClassDemo.class;  //类型(类或接口)信息,此方式更加通用
        OuterCWithInnerClassDemo aObj = (OuterCWithInnerClassDemo) clazz.newInstance();

        // 通过对象 clazz 调用方法 getDeclaredMethod(String methodName, Class<?> parameterTypes)
        // 指出 参数1 为私有方法名"addOneNum",获得此方法的Method对象aMethod。
        Method aMethod = clazz.getDeclaredMethod("addOneNum", null);
        // 设置在类外允许访问私有方法,语句是:aMethod.setAccessible(true);
        aMethod.setAccessible(true);
        // 通过Java反射机制,在类的外部调用该类的私有方法,语句是:aMethod.invoke(aObj)
        aMethod.invoke(aObj);
        // 定义一个iSay类型的变量lamSay,并赋值为: ()->System.out.println("Hello Java!")
        iSay lamSay = () -> System.out.println("Hello Java!");
        // 执行语句: lamSay.sayHello(); 观察程序的输出结果。
        lamSay.sayHello();
    }
}

接口 ISay

// 新建接口 ISay,声明一个 void 类型的抽象方法 sayHello()
public interface iSay {
    abstract void sayHello();
}

运行截图:
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值