Java面向对象编程
IDEA中快速生成构造方法
- 按
Alt
+insert
- 选择
Constructor
3. 选择构造函数及其参数(以矩形类Rectangle为例)
同理快速重写方法时按 Alt
+ insert
后,选择 Override Methods
从 Maven远程仓库 中添加插件依赖
- 打开 Maven远程仓库,网址:https://mvnrepository.com
- 在搜索框中查找依赖项目
- 选择对应版本的依赖,并添加
查看类的源码
1. 选择一个类,以 JDK日期与时间处理类 中用的 ·Calender· 类为例 :
2. 按下 Ctrl
+ h
打开结构图
3. 双击该类进入源码
实验要求
一、创建矩形类Rectangle(含关键字this的使用)
(1)在项目文件夹java里,创建名为 unit03
的包。
(2)在包 unit03
里新建名为 Rectangle
的类,并创建 main()
方法体。
(3)定义2个私有属性 length
和 width
;在IDEA里自动生成有公有、有参构造方法;分别定义显示矩形尺寸和面积的公有方法;在 main()
里实例化 Rectangle
对象并调用业务方法。
二、创建员工类及管理者类(含关键字super、访问权限和方法重写的使用)
(1)新建员工类 Staff
,定义包访问权限、String
类型的字段 name
和 int
类型的 salary
。
(2)定义类的公有构造方法,以 name
和 salary
作为参数。
(3)定义返回 name
和 salary
详细信息的公有实例方法 getDetails()
。
(4)新建管理者类 Manager
并继承类 Staff
,增加一个表示管理部门、String
类型的字段 department
。
(5)定义 Manager
类的公有构造方法,以 name
,salary
和 department
作为参数,使用 super(name,salary)
调用基类的构造方法。
(6)使用快捷菜单,自动产生重写 getDetails()
方法的方法体,编写代码输出管理者的详细信息(包含name
、salary
和 department
)。
(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个子类 Sms
和 QQ
,根据提示重写父类的抽象方法 getMessage()
,分别返回”短信”和“QQ消息”。
(4)定义主类 Student
,包括 String
类型的字段 name
。
(5)定义类 Student
的公有构造方法,以 name
作为参数。
(6)定义发送消息的方法 sendMessage(String msg)
,输出表达式: name+"在发【"+msg+"】"
。
(7)定义 main()
方法,实例化一个 Student
对象,并调用方法 sendMessage(String msg)
。其中,msg
的值分别为 Sms
和 QQ
实例化后调用 getMessage()
方法的结果。
要求:总结抽象类的使用。
(8)新建抽象类 Animal
,定义返回值类型为 void
的抽象方法 cry()
。
(9)分别定义抽象类 Animal
的两个子类 Cat
和 Dog
,并重写抽象方法 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
还原为抽象类、Cat
和 Dog
还原为继承抽象类。
(15)新建两个接口 Bird
和 Fish
,分别定义 void
类型的抽象方法 flying()
和 swimming()
。
(16)定义类 LittleMonkey
,继承抽象类 Animal
,并同时实现接口 Bird
和 Fish
。
(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个私有属性 length
和 width
;在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
类型的字段 name
和 int
类型的 salary
。
public class Staff {
// 新建员工类 Staff,定义包访问权限、String 类型的字段 name 和 int 类型的 salary 。
String name;
int salary;
}
2. 定义类的公有构造方法,以 name
和 salary
作为参数。
// 定义类的公有构造方法,以 name 和 salary 作为参数。
public Staff(String name, int salary) {
this.name = name;
this.salary = salary;
}
3. 定义返回 name
和 salary
详细信息的公有实例方法 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
类的公有构造方法,以 name
,salary
和 department
作为参数,使用 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()
方法的方法体,编写代码输出管理者的详细信息(包含name
、salary
和 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();
}
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
的源码
- 选择一个类,以 JDK日期与时间处理类 中用的 ·Calender· 类为例 :
- 按下
Ctrl
+h
打开结构图
- 双击该类进入源码
查验本类是使用关键字abstract修饰的抽象类
验证使用 new
实例化时,提示需要重写该类的若干抽象方法。
Calendar calendar = new Calendar();
提示 Calendar
是抽象类,不可以被实例化
2. 使用关键字 abstract
,新建抽象类 MessageKind
,声明返回值类型为 String
的抽象方法 getMessage()
。
抽象类 MessageKind
:
public abstract class MessageKind {
public abstract String getMessage();
}
3. 分别定义 MessageKind
类的2个子类 Sms
和 QQ
,根据提示重写父类的抽象方法 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
的值分别为 Sms
和 QQ
实例化后调用 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
的两个子类 Cat
和 Dog
,并重写抽象方法 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
还原为抽象类、Cat
和 Dog
还原为继承抽象类。
抽象类 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. 新建两个接口 Bird
和 Fish
,分别定义 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
,并同时实现接口 Bird
和 Fish
。
类 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();
}
运行截图: