随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
abstract可以用来修饰类或者方法
1.抽象类:
此类不能实例化
抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
2.抽象方法:
抽象方法只有方法的声明,没有方法体
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
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.abstract不能用来修饰:属性、构造器等结构
2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类
注意写法!!
//创建了一匿名子类的对象:p
Person p = new Person(){
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void breath() {
System.out.println("好好呼吸");
}
};
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以 把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用, 这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽 象出来,供不同子类实现。这就是一种模板模式。
/**
* 功能:模板方法例子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("保本理财");
}
}
接口(interface)是抽象方法和常量值定义的集合。
注意:在java中接口和类是两个并列的结构
DK7及以前:只能定义全局常量和抽象方法
全局常量:默认public static final定义的。但是书写时,可以省略不写。
抽象方法:默认public abstract定义的。
除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
1.接口中不能定义构造器的!意味着接口不可以实例化
2. Java开发中,接口通过让类去实现(implements)的方式来使用.
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
3.Java类可以实现多个接口,弥补了Java单继承性的局限性
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("打印机结束工作");
}
}
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("打印机结束工作");
}
}
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();
}
}
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
一方面,作为外部类的成员:
1.调用外部类的结构
2.可以被static修饰
3.可以被4种不同的权限修饰
另一方面,作为一个类:
1.类内可以定义属性、方法、构造器等
2.可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
3.可以被abstract修饰
方法内、代码块内、构造器内
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{
}
}
}
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;
}
};
}
}
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("经理:完成自己的工作,管理普通员工");
}
}
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基础教程