JAVA基础学习笔记(9):抽象类和抽象方法、接口、内部类

目录

  • 1 抽象类和抽象方法
    • 1.1 抽象类的定义
    • 1.2抽象类与抽象方法
    • 1.3 抽象方法与抽象类的使用
    • 1.4 abstract的注意点
    • 1.5 匿名子类对象
  • 2 模板方法设计模式
  • 3 接口
    • 3.1 接口的概念
    • 3.2 定义一个接口
    • 3.2.1 JDK7及以前
    • 3.2.2 JDK8
    • 3.3 接口的注意事项
    • 3.4 接口的使用
    • 3.5 创建接口匿名实现类对象
    • 3.6 Java8新特性
  • 4 内部类
    • 4.1 成员内部类
    • 4.2 局部内部类
    • 4.3 常见的三个问题
      • 4.3.1 如何实例化成员内部类的对象
      • 4.3.2如何在成员内部类中区分调用外部类的结构
      • 4.3.3 开发中局部内部类的使用
  • 本节练习
    • ex1
    • ex2

1 抽象类和抽象方法

1.1 抽象类的定义

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。

1.2抽象类与抽象方法

abstract可以用来修饰类或者方法
1.抽象类:
此类不能实例化
抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
2.抽象方法:
抽象方法只有方法的声明,没有方法体
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

1.3 抽象方法与抽象类的使用

public class AbstractTest {
	
	//抽象类无法实例化
	//Creature a = new Creature();
}

//抽象类
abstract class Creature{
	//抽象方法只能在抽象类中
	//抽象方法
	public abstract void breath();
}


abstract class Person extends Creature{
	int age;
	String name;
	
	public Person(){
		
	}
	
	public Person(int age, String name) {
		this.age = age;
		this.name = name;
	}
	
//	public void eat() {
//		System.out.println("人:吃饭");
//	}
	public abstract void eat();
	
	public void walk() {
		System.out.println("人:走路");
	}
}


class Student extends Person{
	
	public Student(){	
	}
	
	public Student(int age, String name) {
		super(age,name);
	}
	
	public void eat() {
		System.out.println("学生:多吃点补脑子的东西");
	}
	
	public void breath() {
		System.out.println("学生:深呼吸新鲜空气");
	}
}

1.4 abstract的注意点

1.abstract不能用来修饰:属性、构造器等结构
2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类

1.5 匿名子类对象

注意写法!!

//创建了一匿名子类的对象:p
		Person p = new Person(){
			@Override
			public void eat() {
				System.out.println("吃东西");
			}

			@Override
			public void breath() {
				System.out.println("好好呼吸");
			}	
		};

2 模板方法设计模式

当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以 把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用, 这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽 象出来,供不同子类实现。这就是一种模板模式。

/**
 * 功能:模板方法例子1
 * @author wuzec
 *
 */
public class TemplateMethod1 {
	public static void main(String[] args) {
		SubTemlate s1 = new SubTemlate();
		s1.spendTime();
	}
}

abstract class Template{
	
	//计算执行代码所花费的时间
	public void spendTime() {
		long start = System.currentTimeMillis();
		this.code();//不确定的部分、易变的部分
		long end = System.currentTimeMillis();
		System.out.println("花费的时间为:" + (end - start) + "ms" );
	}
	
	public abstract void code();
}

class SubTemlate extends Template{
	@Override
	public void code() {
		//打印1000以内的质数
		for(int i=2; i<=1000; i++) {
			boolean isFlag = true;
			for(int j=2; j<=Math.sqrt(i); j++) {
				if(i % j == 0) {
					isFlag = false;
					break;
				}
			}
			if(isFlag) {
				System.out.println(" " + i);
			}
		}
	}
}
/**
 * 功能:模板方法例子2
 * @author wuzec
 *
 */
public class TemplateMethod2 {
	public static void main(String[] args) {
		BankTemplate  b1 = new DrawMoney();
		BankTemplate  b2 = new ManageMoney();
		b1.process();
		System.out.println("***********");
		b2.process();	
	}
}

abstract class BankTemplate{
	//具体方法
	public void takeNumber() {
		System.out.println("取号排队!!");
	}
	
	public abstract void transact();
	
	public void evaluate() {
		System.out.println("反馈评分!!");
	}
	
	//模板方法,把基本方法组和在一起子类基本不重写
	public final void process() {
		this.takeNumber();
		this.transact();//像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码
		this.evaluate();
	}
}

class DrawMoney extends BankTemplate{
	@Override
	public void transact() {
		System.out.println("取款!!");
	}
}

class ManageMoney extends BankTemplate{
	@Override
	public void transact() {
		System.out.println("保本理财");
	}
}

3 接口

3.1 接口的概念

接口(interface)是抽象方法常量值定义的集合。
注意:在java中接口和类是两个并列的结构

3.2 定义一个接口

3.2.1 JDK7及以前

DK7及以前:只能定义全局常量和抽象方法
全局常量:默认public static final定义的。但是书写时,可以省略不写。
抽象方法:默认public abstract定义的。

3.2.2 JDK8

除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法

3.3 接口的注意事项

1.接口中不能定义构造器的!意味着接口不可以实例化
2. Java开发中,接口通过让类去实现(implements)的方式来使用.
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
3.Java类可以实现多个接口,弥补了Java单继承性的局限性
4.接口与接口之间可以继承,并且可以多继承

3.4 接口的使用

/**
*功能:接口的基本使用
*/
public class InterfaceTest {
	public static void main(String[] args) {
		Plane p1 = new Plane();
		p1.fly();
		p1.stop();
		Bullet b1 = new Bullet();
		b1.fly();
		b1.stop();
		b1.attack();
	}
}

interface Flyable{
	//全局常量
	public static final int MAX_SPEED = 7200;
	int MIN_SPEED = 1;//省略了public static final 
	
	public abstract void fly();
	void stop();//省略了public abstract
}

interface Acttackable{
	void attack();
}


class Plane implements Flyable{

	@Override
	public void fly() {
		System.out.println("飞机起飞芜湖!!!");
	}

	@Override
	public void stop() {
		System.out.println("飞机降落!!");
	}
}

class Bullet implements Flyable, Acttackable{

	@Override
	public void fly() {
		System.out.println("让子弹飞!");
	}

	@Override
	public void stop() {
		System.out.println("子弹停了下来");
	}

	@Override
	public void attack() {
		System.out.println("子弹要杀人了!!");
	}
}

abstract class Bird implements Flyable{
	
}
/**
 * 功能:接口的使用2、接口作为一种标准的例子
 * @author wuzec
 *
 */
public class USBTest {
	public static void main(String[] args) {
		Computer com = new Computer();
		Flash f1 = new Flash();
		Printer p1 = new Printer();
		com.tranData(p1);
	}
}


interface USB{
	//常量:长、宽
	int LENGTH = 10;
	int WEIGHT = 5;
	
	void start();
	void stop();
}


class Computer{
	public void tranData(USB usb) {// USB usb = new Flash() 多态
		usb.start();
		System.out.println("进行数据传输");
		usb.stop();
	}
}


class Flash implements USB{

	@Override
	public void start() {
		System.out.println("闪存开始工作");
	}

	@Override
	public void stop() {
		System.out.println("闪存结束工作");
	}
}

class Printer implements USB{

	@Override
	public void start() {
		System.out.println("打印机开始工作");
	}

	@Override
	public void stop() {
		System.out.println("打印机结束工作");
	}
}

3.5 创建接口匿名实现类对象

public class USBTest {
	public static void main(String[] args) {
		Computer com = new Computer();
		Flash f1 = new Flash();
		Printer p1 = new Printer();
		//1.创建了接口的非匿名实现类的非匿名对象
		com.tranData(p1);
		//2.创建了接口的非匿名实现类的匿名对象
		com.tranData(new Printer());
		//3.创建了接口的匿名实现类的非匿名对象
		USB phone = new USB() {
			@Override
			public void start() {
				System.out.println("手机开始工作!");
			}
			@Override
			public void stop() {
				System.out.println("手机结束工作!");
			}
		};
		com.tranData(phone);
		//4.创建了接口的匿名实现类的匿名对象
		com.tranData(new USB() {

			@Override
			public void start() {
				System.out.println("1");
			}

			@Override
			public void stop() {
				System.out.println("2");
			}
		
		});
		
	}
}

interface USB{
	//常量:长、宽
	int LENGTH = 10;
	int WEIGHT = 5;
	
	void start();
	void stop();
}

class Computer{
	public void tranData(USB usb) {// USB usb = new Flash() 多态
		usb.start();
		System.out.println("进行数据传输");
		usb.stop();
	}
}


class Flash implements USB{

	@Override
	public void start() {
		System.out.println("闪存开始工作");
	}

	@Override
	public void stop() {
		System.out.println("闪存结束工作");
	}
}

class Printer implements USB{

	@Override
	public void start() {
		System.out.println("打印机开始工作");
	}

	@Override
	public void stop() {
		System.out.println("打印机结束工作");
	}
}

3.6 Java8新特性

1.接口中定义的静态方法,只能通过接口来调用。
2.通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法。
3.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。类优先原则
4.如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。接口冲突
这就需要我们必须在实现类中重写此方法
5.如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
CompareA.java:

public interface CompareA {	
	//静态方法
	public static void method1() {
		System.out.println("CompareA:北京(静态方法)");
	}
	//默认方法
	public default void method2() {
		System.out.println("CompareA:上海(默认方法1)");
	}
	
	default void method3() {
		System.out.println("CompareA:上海(默认方法2)");
	}
}

CompareB.java:

public interface CompareB {
	default void method3() {
		System.out.println("CompareB:上海");
	}
}

SuperClass.java:

public class SuperClass {
	public void method3() {
		System.out.println("SuperClass:北京");
	}
}

SubClassTest.java:

public class SubClassTest {
	public static void main(String[] args) {
		SubClass s = new SubClass();
		//1.接口中定义的静态方法,只能通过接口来调用
		CompareA.method1();
		//2.通过实现类的对象,可以调用接口中的默认方法
		//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写之后的方法
		s.method2();
		//3.如果子类(实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
		//那么子类在没用重写的情况下,默认调用的是父类中同名同参数的方法-->类优先原则
		//4.如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
		//那么在实现类没有重写此方法的情况下,报错。-->接口冲突。
		//这就需要我们必须在实现类中重写此方法
		s.method3();
		System.out.println("******************");
		s.MyMethod();
	}
}

class SubClass extends SuperClass implements CompareA, CompareB{
	
	public void method2() {
		System.out.println("SubClass:上海(默认方法1)");
	}
	
	public void method3() {
		System.out.println("Subclass:深圳");
	}
	//5.如何在方法中底用父类、接口中被重写的方法	
	public void MyMethod() {
		method3();//调用自己定义的重写的方法
		super.method3();//调用父类中声明的方法
		//调用接口中的默认方法
		CompareA.super.method3();
		CompareB.super.method3();
	}
}

4 内部类

在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。

4.1 成员内部类

一方面,作为外部类的成员:
1.调用外部类的结构
2.可以被static修饰
3.可以被4种不同的权限修饰
另一方面,作为一个类:
1.类内可以定义属性、方法、构造器等
2.可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
3.可以被abstract修饰

4.2 局部内部类

方法内、代码块内、构造器内

4.3 常见的三个问题

4.3.1 如何实例化成员内部类的对象

4.3.2如何在成员内部类中区分调用外部类的结构

public class InnerClassTest {
	public static void main(String[] args) {
		//创建Dog实例(静态的成员内部类)
		Person.Dog dog = new Person.Dog();
		dog.show();
		//创建Bird实例(非静态成员内部类)
		Person p = new Person();
		Person.Bird bird = p.new Bird();
		bird.sing();
	}

}


class Person{
	String name;
	int age;
	
	public void eat() {
		System.out.println("人:吃饭");
	}
	
	//成员内部类
	//静态内部类
	static class Dog{
		String name = "ming";
		int age;
		public void show() {
			System.out.println("Dog:进行展示");
		}
		
	}
	
	//非静态内部类
	class Bird{
		String name  = "niao";
		int age;
		public Bird() {
			
		}
		
		public void sing() {
			System.out.println("Bird:鸟儿唱歌了");
			Person.this.eat();
		}
		
		public void display(String name) {
			System.out.println(name);//方法的形参
			System.out.println(this.name);//内部类的属性
			System.out.println(Person.this.name);//外部类的属性
		}
	}
	
	public void method() {
		 //局部内部类
		 class AA{
			 
		 }
	 }
	 
	 
	 {
		//局部内部类
		 class BB{
			 
		 }
	 }
	 
	 public Person() {
		//局部内部类
		 class CC{
			 
		 }
	 }
}

4.3.3 开发中局部内部类的使用

public class InnerClassTest1 {
	//返回一个实现的Comparable接口的类的对象
	public Comparable  getComparable() {
		
		//创建一个实现了Comparable接口的类
		//方式一:
//		class MyComparable implements Comparable{
//			@Override
//			public int compareTo(Object o) {
//				return 0;
//			}
//		}
//		return new MyComparable();
		//方式二:
		return new Comparable() {
			@Override
			public int compareTo(Object o) {
				// TODO Auto-generated method stub
				return 0;
			}
			
		};
		
	}

}

本节练习

ex1

JAVA基础学习笔记(9):抽象类和抽象方法、接口、内部类_第1张图片

public class AbstractEx {
	public static void main(String[] args) {
		Manager m1 = new Manager("Tom", 1001, 10000, 2000);
		Employee m2 = new Manager("Kim", 1002, 11000, 3000);//使用多态
		m1.work();
		m2.work();
		
		CommonEmployee ce1 = new CommonEmployee("Tony", 1001, 8000);
		Employee ce2 = new CommonEmployee("Tony", 1001, 8000);//使用多态
		ce1.work();
		ce2.work();
	}
}

abstract class Employee{
	private String name;
	private int id;
	private double salary;
	
    public Employee() {
    	super();
	}
	
	public Employee(String name, int id, double salary) {
		this.name = name;
		this.id = id;
		this.salary = salary;
	}

	public abstract void work();
	
}

class CommonEmployee extends Employee{
	
	public CommonEmployee() {
		super();
	}
	
	public CommonEmployee(String name, int id, double salary) {
		super(name, id, salary);
	}
	
	public void work() {
		System.out.println("普通员工:做好自己的工作");
	}
}

class Manager extends Employee{
	double bonus;
	
	public Manager() {
		super();
	}
	
	public Manager(String name, int id, double salary, double bonus) {
		super(name, id, salary);
		this.bonus = bonus;
	}
	
	public void work() {
		System.out.println("经理:完成自己的工作,管理普通员工");
	}
}

ex2

JAVA基础学习笔记(9):抽象类和抽象方法、接口、内部类_第2张图片
JAVA基础学习笔记(9):抽象类和抽象方法、接口、内部类_第3张图片
Employee.java:

public abstract class Employee {
	private String name;
	private int number;
	private MyDate birthday;
	
	public Employee(String name, int number, MyDate birthday) {
		super();
		this.name = name;
		this.number = number;
		this.birthday = birthday;
	}
	
	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 double  earnings();

	@Override
	public String toString() {
		return " name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString();
	}

}

MyDate.java:

public class MyDate {
	private int year; //年
	private int month; //月
	private int day; //日
	
	public MyDate(int year, int month, int day) {
		super();
		this.year = year;
		this.month = month;
		this.day = day;
	}

	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.java:

public class SalariedEmployee extends Employee {

	private double monthlySalary;

	public SalariedEmployee(String name, int number, MyDate birthday) {
		super(name, number, birthday);
	}
	
	public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) {
		super(name, number, birthday);
		this.monthlySalary = monthlySalary;
	}
	
	public double getMonthlySalary() {
		return monthlySalary;
	}

	public void setMonthlySalary(double monthlySalary) {
		this.monthlySalary = monthlySalary;
	}
	
	@Override
	double earnings() {
		return monthlySalary;
	}
	
	@Override
	public String toString() {
		return "SalariedEmployee[" + super.toString() + "]";
	}
}

HourlyEmployee.java:

public class HourlyEmployee extends Employee{
	private int hour;//工作的小时数
	private double wage;

	public HourlyEmployee(String name, int number, MyDate birthday) {
		super(name, number, birthday);
	}
	
	public HourlyEmployee(String name, int number, MyDate birthday, int hour, double 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 double getWage() {
		return wage;
	}

	public void setWage(double wage) {
		this.wage = wage;
	}

	@Override
	double earnings() {
		return hour * wage;
	}
	
	@Override
	public String toString() {
		return  "HourlyEmployee[" + super.toString() + "]";
	}
}

PayrollSystem.java:

public class PayrollSystem {
	public static void main(String[] args) {
		
		Calendar calendar = Calendar.getInstance();
		int month = calendar.get(Calendar.MONTH);//一月份:0    二月份:1
		
		Employee[] emp = new Employee[2]; //只是提供空间,并没有对每个对象进行初始化
		emp[0] = new SalariedEmployee("Tony", 1001, new MyDate(2000,1,1), 12000);
		emp[1] = new HourlyEmployee("Mike", 1002, new MyDate(2001,6,1), 10, 50);
		
		for(int i=0; i<emp.length; i++) {
			System.out.println(emp[i]);
			double salary = emp[i].earnings();

			if((month+1) == emp[i].getBirthday().getMonth()) {
				System.out.println("生日快乐奖励100元");
				salary += 100;
			}
			
			System.out.println("月工资为" + salary);
			
		}
	}
}

参考资料:
[1]尚硅谷宋康红java基础教程

你可能感兴趣的:(java基础,java,多态,抽象类,面向对象编程)