抽象类、接口、内部类
1:抽象类
- 理解抽象的设计思想
- abstract关键字的使用
/**
* 举例1:
* abstract class Account{
* double balance;
*
* //存钱、取钱的方法
* }
*
* class SavingAccount extends Account{
*
* }
* class CheckAccount extends Account{
*
* }
*
* class Customer{
* Account acct;
* public void setAccount(Account acct){ //Account acct = new SavingAccount();
* this.acct = acct;
* }
*
* }
*
* 1. abstract:抽象的
* 2. 可以用来修饰:类、方法
*
* 3. abstract 来修饰类:抽象类
* > 此类就不可以实例化(不能创建对象) ---> 凡是类,内部都有构造器。
* -->此时抽象类提供构造器的意义:为了子类对象实例化进行对抽象父类中构造器的调用
* > 在开发中,针对于抽象类,我们一定会提供其子类。在实现过程中,创建子类的对象。
*
* 4. abstract 来修饰方法:抽象方法
* > 特点:抽象方法,没有方法体结构。
* > 抽象类中可以没有抽象方法;但是,抽象方法所在的类,一定是抽象类。
* > 如果抽象类的子类重写了父类中的所有的抽象方法,则此子类可以实例化。
* 如果抽象类的子类没有重写父类中所有的抽象方法,则此子类也必须声明为abstract的。
*
*
*
* @author Begonia_sea
* @create 2020-07-10
*/
- 代码举例
public class AbstractTest {
public static void main(String[] args) {
// Person p1 = new Person();
// p1.eat();
Student s1 = new Student();
s1.eat();
// Worker w1 = new Worker();
// w1.eat();
//提供抽象类的匿名子类的对象
Person p2 = new Person(){
@Override
public void eat() {
System.out.println("人:吃饭");
}
@Override
public void walk() {
System.out.println("人:走路");
}
@Override
public void breath() {
System.out.println("人:呼吸");
}
};
p2.eat();
//创建了BB的匿名子类的对象
BB b = new BB(){
};
}
}
abstract class BB{
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//抽象方法
public abstract void eat();
//抽象方法
public abstract void walk();
}
class Student extends Person{
String major;
public Student(){}
public Student(String name ,int age ,String major){
super(name, age);
this.major = major;
}
public void eat(){
System.out.println("学生:多吃有营养的食物");
}
public void walk(){
System.out.println("学生:背着书包上学");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的空气");
}
}
abstract class Worker extends Person{
String skill;
// public void eat(){
// System.out.println("工人:在工厂吃盒饭");
// }
// public void walk(){
// System.out.println("工人:在车间行走");
// }
}
- 举例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bjH1GjMV-1594390601955)(assets/1594370898800.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-43wQmoCm-1594390601957)(assets/1594370912376.png)]
- abstract的补充说明
/**
* 不能用abstract修饰变量、代码块、构造器;
*
* 不能用abstract修饰私有方法、静态方法、final的方法、final的类。
*
* @author Begonia_sea
* @create 2020-07-10
*/
public abstract class AbstractTest1 {
// private abstract void method();
//
// public static abstract void method1();
}
class A extends AbstractTest1{
}
- 练习1
public abstract class GeometricObject {
protected String color;//颜色
protected double weight;//权重
public GeometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
//返回几何图形的面积
public abstract double findArea();
}
- 练习2
/**
* @author Begonia_sea
* @create 2020-07-10
*/
public abstract class Employee {//员工类
private String name;//姓名
private int id;//编号
private double salary;//薪水
public Employee(String name, int id, double salary) {//构造方法
this.name = name;
this.id = id;
this.salary = salary;
}
public abstract void work();//工作方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return
"name='" + name + '\'' +
", id=" + id +
", salary=" + salary;
}
}
/**
* @author shkstart
* @create 2020-07-10 14:35
*/
public class CommonEmployee extends Employee{//普通员工类
public CommonEmployee(String name, int id, double salary) {//构造方法
super(name, id, salary);//调用父类的构造方法
}
@Override
public void work() {//工作方法
System.out.println("在工地搬砖");
}
@Override
public String toString() {
return "CommonEmployee{ " + super.toString() +"}";
}
}
/**
* @author Begonia_sea
* @create 2020-07-10
*/
public class Manager extends Employee {
private double bonus;//薪水
public Manager(String name, int id, double salary) {//构造方法
super(name, id, salary);//调用父类的构造方法
}
@Override
public void work() {//工作方法
System.out.println("在办公室工作");
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public String toString() {
return "Manager{" +
super.toString() +
",bonus=" + bonus +
"} ";
}
}
package com.atguigu.exer1;
/**
* @author shkstart
* @create 2020-07-10 14:35
*/
public class EmployeeTest {
public static void main(String[] args) {
Manager manager = new Manager("马爷", 1001, 5000);
manager.setBonus(10000);
System.out.println(manager);
manager.work();
CommonEmployee commonEmployee = new CommonEmployee("杨展", 102, 500);
System.out.println(commonEmployee);
commonEmployee.work();
}
}
- 练习3
/**
* 编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个Employee对象的
* 生日,则将该雇员的工资增加100元。
*
* 实验说明:
* (1)定义一个Employee类,该类包含:
* private成员变量name,number,birthday,其中birthday 为MyDate类的对象;
* abstract方法earnings();
* toString()方法输出对象的name,number和birthday。
*
* @author Begonia_sea
* @create 2020-07-10
*/
public abstract class Employee {
private String name;
private int number;
private MyDate birthday;
public Employee(String name, int number, MyDate birthday) {
this.name = name;
this.number = number;
this.birthday = birthday;
}
public Employee() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
//abstract方法earnings();
public abstract double earnings();
@Override
public String toString() {
return "name='" + name + '\'' +
", number=" + number +
", birthday=" + birthday.toDateString();
}
}
/**
* (2)MyDate类包含:
* private成员变量year,month,day ;
* toDateString()方法返回日期对应的字符串:xxxx年xx月xx日
*
* @author Begonia_sea
* @create 2020-07-10
*/
public class MyDate {
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public MyDate() {
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public String toDateString(){
return year + "年" + month + "月" + day + "日";
}
}
/**
* 定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处理。
* 该类包括:private成员变量monthlySalary;
* 实现父类的抽象方法earnings(),该方法返回monthlySalary值;
* toString()方法输出员工类型信息及员工的name,number,birthday。
*
*
* @author shkstart
* @create 2020-07-10 14:46
*/
public class SalariedEmployee extends Employee {
private double monthlySalary;//月工资
public SalariedEmployee(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) {
super(name, number, birthday);
this.monthlySalary = monthlySalary;
}
public SalariedEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public double getMonthlySalary() {
return monthlySalary;
}
public void setMonthlySalary(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
@Override
public double earnings() {
return monthlySalary;
}
//toString()方法输出员工类型信息及员工的name,number,birthday
@Override
public String toString() {
return "SalariedEmployee{" + super.toString() + "}";
}
}
/**
* (4)参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的员工处理。
* 该类包括:
* private成员变量wage和hour;
* 实现父类的抽象方法earnings(),该方法返回wage*hour值;
* toString()方法输出员工类型信息及员工的name,number,birthday。
*
*
* @author Begonia_sea
* @create 2020-07-10
*/
public class HourlyEmployee extends Employee {
private int hour;//小时数
private int wage;//单位小时的工资
@Override
public double earnings() {
return hour * wage;
}
public HourlyEmployee() {
}
public HourlyEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public HourlyEmployee(String name, int number, MyDate birthday, int hour, int wage) {
super(name, number, birthday);
this.hour = hour;
this.wage = wage;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public int getWage() {
return wage;
}
public void setWage(int wage) {
this.wage = wage;
}
//toString()方法输出员工类型信息及员工的name,number,birthday。
@Override
public String toString() {
return "HourlyEmployee{" + super.toString() + "}";
}
}
import java.util.Scanner;
/**
* 定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各类雇员对象的引用。
* 利用循环结构遍历数组元素,输出各个对象的类型,name,number,birthday,以及该对象生日。
* 当键盘输入本月月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息。
*
* @author Begonia_sea
* @create 2020-07-10
*/
public class PayrollSystem {
public static void main(String[] args) {
Employee[] emps = new Employee[2];
emps[0] = new SalariedEmployee("杨超宇",1001,new MyDate(1994,4,02),20000);
emps[1] = new HourlyEmployee("闫宏浩",1002,new MyDate(1988,7,10),240,100);
Scanner scanner = new Scanner(System.in);
System.out.println("请输入当前的月份:");
int month = scanner.nextInt();
for (int i = 0; i < emps.length; i++) {
System.out.println(emps[i]);
double monthlyMoney = emps[i].earnings();
if(month == emps[i].getBirthday().getMonth()){
monthlyMoney += 200;
}
System.out.println("月工资为:" + monthlyMoney);
}
}
}
2:接口
- 基本使用
/**
* interface关键字的使用
* 1. 我们使用interface来声明一个接口。
* 接口与类,是Java中并列关系的两个结构。
*
* 2. 接口,可以理解为特定功能的封装。通过类实现接口的方法,进而体现功能的扩充。同时,还不
* 影响此类单继承父类的情况。
* 而且,一个类可以实现多个接口。
* 3. 格式:class SubClass extends SuperClass implements 接口1,接口2,...
*
* 4. 关于接口的使用:
* JDK 7及之前:只能定义全局常量 和 抽象方法
* > 全局常量使用:public static final 修饰。也可以省略不写
* > 抽象方法使用:public abstract 修饰。也可以省略不写
*
* JDK 8: 增加了对静态方法、默认方法的定义。
* JDK 9: 增加了对私有方法的定义。
*
* 5. 实现类在实现了接口之后,必须要实现接口中的所有抽象方法,方可实例化。
* 否则,实现类如果没有实现接口中的所有抽象方法,则此实现类仍为抽象类。
*
* 6. 接口中不能定义构造器的。也就是说,接口不能实例化。
*
* 7. 类与接口之间是实现关系,而且是可以多实现的。
* 接口与接口之间是继承关系,而且是可以多继承的。
*
*
* 补充说明:
* 类继承类的关系:is - a
* 类实现接口的关系: like - a
* 类及其属性的关系: has - a
*
* @author Begonia_sea
* @create 2020-07-10
*/
- 代码演示
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyable.MAX_SPEED);
// Flyable.MAX_SPEED = 8000;
}
}
interface Flyable{
//全局常量
public static final int MIN_SPEED = 1;
int MAX_SPEED = 7900;
//抽象方法
public abstract void fly();
void stop();
}
interface AttackAble{
void attack();//攻击
}
abstract class Plane implements Flyable{
@Override
public void fly() {
}
// @Override
// public void stop() {
//
// }
}
class Bullet implements Flyable,AttackAble{
@Override
public void fly() {
}
@Override
public void stop() {
}
@Override
public void attack() {
}
}
interface AA{
}
interface CC{
}
interface DD extends AA,CC{
}
- 体会接口作为标准、规范的存在
/**
* 1. 接口的本质是契约,标准,规范
*
* 2. 接口的使用:实现了多态性。
*
* 3. 匿名实现类的理解
*
* @author Begonia_sea
* @create 2020-07-10
*/
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的实现类的对象printer
Printer printer = new Printer();
com.transferData(printer);
//2.创建了接口的实现类的匿名对象
com.transferData(new Flash());
//3. 创建接口的匿名实现类的对象
USB camera = new USB(){
@Override
public void start() {
System.out.println("照相机开始工作");
}
@Override
public void stop() {
System.out.println("照相机结束工作");
}
};
com.transferData(camera);
//4. 创建接口的匿名实现类的匿名对象
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3开始工作");
}
@Override
public void stop() {
System.out.println("mp3结束工作");
}
});
}
}
class Computer{
public void transferData(USB usb){ //体现了多态性。
usb.start(); //虚方法调用
System.out.println("========具体的数据传输细节=======");
usb.stop();
}
}
interface USB{
void start();
void stop();
}
class Printer implements USB{ //打印机
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
class Flash implements USB{//U盘
@Override
public void start() {
System.out.println("U盘开始工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
- java8中接口的新特性
import java.net.SocketTimeoutException;
/**
* @author Begonia_sea
* @create 2020-07-10
* */
public interface CompareA {
public static void method1() {
System.out.println("CompareA:北京");
}
public default void method2() {
System.out.println("CompareA:上海");
}
default void method3() {
System.out.println("CompareA:广州");
}
public default void method4(){
System.out.println("CompareA:深圳");
}
}
/**
* @author Begonia_sea
* @create 2020-07-10
*/
public interface CompareB {
public default void method2() {
System.out.println("CompareB:上海");
}
}
/**
* @author Begonia_sea
* @create 2020-07-10
*/
public class SuperClass {
public void method4(){
System.out.println("SuperClass:深圳");
}
}
/**
* @author Begonia_sea
* @create 2020-07-10
*/
public class SubClass extends SuperClass implements CompareA,CompareB {
public void method3() {
System.out.println("SubClass:广州");
}
public void method4(){
System.out.println("SubClass:深圳");
}
public void method2() {
System.out.println("SubClass:上海");
}
public void method(){
//6. 如何在子类(或实现类)中调用父类或接口中被重写的方法
//调用父类的方法:
super.method4();
//调用接口中的方法:
CompareA.super.method2();
CompareB.super.method2();
}
}
/**
* @author Begonia_sea
* @create 2020-07-10
*/
public class SubClassTest {
public static void main(String[] args) {
//1. 接口中静态方法的调用:只能使用接口本身来调用,其实现类不可以调用。
CompareA.method1();
// SubClass.method1();
//2. 可以通过实现类的对象,调用接口中的默认方法
SubClass sub1 = new SubClass();
sub1.method2();
//3.实现类可以重写接口中的默认方法。
sub1.method3();
//4.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,则子类在没有
//重写此方法的情况下,默认调动的是父类中声明的方法。--->类优先原则
//补充:如果子类(或实现类)重写了上述的方法,则调用的就是自己重写的方法。
sub1.method4();
//5.如果实现类实现了多个接口,且多个接口中声明了同名同参数的方法。则
//子类必须重写此方法。否则,编译不通过。 --->接口冲突。
sub1.method2();
//6. 见SubClass内
sub1.method();
}
}
3:内部类
- 基本知识点
/**
* 类的成员之五:内部类
*
* 1. 分类:
* 成员内部类:直接声明在外部类的内部。
*
* 局部内部类:声明在方法内、代码块内等的内部类。
*
* 2. 关于成员内部类的使用:
* 2.1 作为外部类的一个成员:
* > 可以使用4种不同的权限进行修饰
* > 可以使用static进行修饰
* > 可以在内部类中调用外部类的成员
*
* 2.2 作为类的:
* > 可以在内部声明属性、方法、构造器、代码块、内部类....
* > 可以被abstract、final修饰。
*
*
*
* 3. 学习内部类需要掌握的三个知识点
* ① 如何创建成员内部类的对象
* ② 如何在成员内部类中调用外部类的属性、方法
* ③ 熟悉局部内部类的基本使用: 见 InnerClassTest1.java
*
* @author Begonia_sea
* @create 2020-07-10
*/
-
代码举例
-
外部类的使用
public class InnerClassTest { public static void main(String[] args) { //创建静态的成员内部类 Person.Bird bird = new Person.Bird(); //创建非静态的成员内部类 Person p = new Person(); Person.Dog dog = p.new Dog(); dog.info(); dog.show("旺财"); } } class Person{ String name = "小明"; int age = 1; //静态的成员内部类 static class Bird{ } //非静态的成员内部类 class Dog{ String name = "小花"; public void info(){ //直接调用外部类的属性和方法 System.out.println(age); Person.this.eat(); } public void show(String name){ System.out.println(name); System.out.println(this.name); System.out.println(Person.this.name); } public void eat(){ System.out.println("狗吃骨头"); } } public void eat(){ System.out.println("人吃饭"); } }
-
内部类的使用
/** * 体会局部内部类的使用 * * @author Begonia_sea * @create 2020-07-10 */ public class InnerClassTest1 { //此种方式使用局部内部类:不常见 public void method(){ //声明一个局部内部类 class A{ } } //常见如下的操作: public Comparable getComparable(){ //方式一: /*//内部声明一个接口的实现类 class MyComparable implements Comparable{ @Override public int compareTo(Object o) { return 0; } } return new MyComparable();*/ //方式二:创建了接口的匿名实现类的匿名对象 return new Comparable(){ @Override public int compareTo(Object o) { return 0; } }; } }
-