这里写自定义目录标题
第13章 抽象和类
01 作业回顾
***练习
- 编写一个Person类,包括属(name,age),构造器,方法say(返回自我介绍的字符串)。
编写一个student类,继承Person类,增加id,score属性,以衣构造器,并覆盖say方法。
编写Test类,创建Peron和Student对象,调用say方法输出自我介绍。
package day11;
class Person{
protected String name;
protected int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void say(){
System.out.println("name:" + name);
System.out.println("age:" + age);
}
}
class Student extends Person{
private int id;
private int score;
public Student(String name,int age,int id, int score) {
super(name,age);
this.id = id;
this.score = score;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public void say() {
super.say();
System.out.println("id:" + id);
System.out.println("score: " + score);
}
}
public class Day113 {
public static void main(String[] args) {
Person p = new Person("张三",20);
p.say();
Student s = new Student("李四", 10, 1, 99);
s.say();
}
}
/*
name:张三
age:20
name:李四
age:10
id:1
score: 99
*/
02 抽象类
2.1 示例
2.1.1 初步设计
package day11;
class GraphicObject {
protected int x;
protected int y;
protected String color;
public GraphicObject(int x, int y, String color) {
super();
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void moveTo(int x,int y) {
this.x = x;
this.y = y;
}
public void showLocation(){
System.out.println("x = " + x + ", y = " + y);
}
//不知道如何实现
public void draw() {
}
class Circle extends GraphicObject {
public Circle(int x, int y, String color) {
super(x,y, color);
}
public void draw() {
System.out.println("draw a circle at[" + x + "," + y + "]");
}
}
class Rectangle extends GraphicObject {
public Rectangle(int x, int y, String color) {
super(x, y, color);
}
public void draw() {
System.out.println("draw a Rectangle at [" + x + "," + y + "]");
}
}
}
public class Day115 {
public static void main(String[] args) {
Circle c = new Circle(1, 1, "红色");
c.draw();
Rectangle r = new Rectangle(2, 2, "蓝色");
r.draw();
}
}
/*
draw a circle at[1,1]
draw a Rectangle at[2,2]
*/
图形对象都具有某些状态(位置,线条颜色)和 行为(moveTo,draw)。
对于所有的图形,这些状态和行为中的一些是相同(位置,线条颜色,moveTo)。
draw有些特殊。每个子类的draw方法提供的功能不同。
可以在父类中提供一个draw方法,在子类中使用方法重写来完成特定的draw方法。
GraphicObject(图形)应该是抽象的,不应该有具体的对象。
对于这种情况可以使用抽象类来实现。
2.1.2 加入抽象类思想,进行优化改进
package day11;
//有抽角方法的类必须声明为抽象类
abstract class GraphicObject {
protected int x;
protected int y;
protected String color;
public GraphicObject(int x, int y, String color) {
super();
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void moveTo(int x,int y) {
this.x = x;
this.y = y;
}
public void showLocation(){
System.out.println("x = " + x + ", y = " + y);
}
//声明为抽象的方法,因为不知道如何云实现它
public abstract void draw();
}
class Circle extends GraphicObject {
public Circle(int x, int y, String color) {
super(x,y, color);
}
//子类必须实现父类的抽象方法,否则这个子类必须声明为抽象类
public void draw() {
System.out.println("draw a circle at[" + x + "," + y + "]");
}
}
class Rectangle extends GraphicObject {
public Rectangle(int x, int y, String color) {
super(x, y, color);
}
public void draw() {
System.out.println("draw a Rectangle at [" + x + "," + y + "]");
}
}
public class Day115 {
public static void main(String[] args) {
//编译错误,抽象类不能被实例化
// GraphicObject g = new GraphicObject(0, 0, "黑色");
Circle c = new Circle(1, 1, "红色");
c.draw();
Rectangle r = new Rectangle(2, 2, "蓝色");
r.draw();
}
}
2.1.3
子类必须实现父类的抽象方法,否则这个子类必须声明为抽象类
2.2
抽象类使用abstract关键字来声明,它可以包含抽象方法,也可以不包含抽象方法。
声明为抽象类,又不包含抽象方法,仅仅是为了避免被实例化。
抽象类不能被实例化,但是可以被继承。
如果一个类包含了抽象方法,那么它必须声明为一个抽象类。
如果一个类继承了抽象类,它通常要实现抽象类的抽象方法,如果没有,那么这个子类也必须被声明为抽象的。
抽象类天生就是用来被继承的。抽象类实现了它所有子类必须使用的通用方法。这样子类就可以直接调用。
抽象方法则留给子类根据自己的情况做不同的实现。
定义抽象方法的意义在于:给所有的子类制定一种规则,子类必须要实现抽象方法。
抽象类使用abstract关键字来声明,它可以包含抽象方法,也可以不包含抽象方法。
03 接口
接口定义了一个类所能对外提供的功能。接口不能被实例化,只能被实现。
接口可以理解为纯粹的抽象类,接口中的所有方法都是抽象的。
接口描述了一种规则。
3.1 示例
3.1.1
package day11;
//使用关键字interface声明了一个接口
//接口描述了一种功能
interface Flyable{
// public abstract void fly();
//public abstract不是必须的,接口的方法默认就是public abstract
void fly();
}
//使用关键字implements来实现一个接口
class Aeroplane implements Flyable{
//实现一个接口,必须实现接口中的所有方法,否则这个类必须声明为抽象类
@Override
public void fly() {
System.out.println("飞机能飞");
}
}
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("鸟能飞");
}
}
public class Day117 {
public static void main(String[] args) {
Bird bird = new Bird();
bird.fly();
Aeroplane aeroplane = new Aeroplane();
aeroplane.fly();
}
}
3.1.2 使用接口类型的变量
package day11;
//使用关键字interface声明了一个接口
//接口描述了一种功能
interface Flyable{
// public abstract void fly();
//public abstract不是必须的,接口的方法默认就是public abstract
void fly();
}
//使用关键字implements来实现一个接口
class Aeroplane implements Flyable {
// 实现一个接口,必须实现接口中的所有方法,否则这个类必须声明为抽象类
@Override
public void fly() {
System.out.println("飞机能飞");
}
}
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("鸟能飞");
}
}
public class Day117 {
public static void main(String[] args) {
Bird bird = new Bird();
bird.fly();
Aeroplane aeroplane = new Aeroplane();
aeroplane.fly();
//使用接口类型的变量
//Aeroplane实现了Flyable接口,因此这个对象可以被Flyable类型的变量引用
Flyable f1 = new Aeroplane();
f1.fly();//多态,会调用其实际引用对象的fly方法
//Bird实现了Flyable接口,因此这个对象可以被Flyable类型的变量引用
Flyable f2 = new Bird();
f2.fly();//多态,会调用其实际引用对象的fly方法
}
}
3.1.3
接口中的变量总是public static final的,接口中的变量不能声明为private。
//接口中的变量总是public static final的,接口中的变量不能声明为private。
package day11;
interface ExampleInterface1 {
//接口中的變量默认是public static final
//一般常量用大写
int VALUE1 = 10;
public int VALUE2 = 20;
public static int VALUE3 = 30;
public static final int VALUE4 = 40;
//接口中不允许private变量
// private int value5 = 50;//编译错误
}
public class Day118 {
public static void main(String[] args) {
System.out.println(ExampleInterface1.VALUE1);
}
}
3.2 接口的继承
package day11;
interface Interface1 {
void method1();
}
//Interface2继承了Interface1中的所有方法声明
interface SubInterface1 extends Interface1 {
void method2();
}
//ctrl + 1 自动修复错误
//实现Interface1接口,必须要实现method1和method2两个方法
class Class1 implements SubInterface1 {
@Override
public void method1() {
// TODO Auto-generated method stub
}
@Override
public void method2() {
// TODO Auto-generated method stub
}
}
public class Day119 {
public static void main(String[] args) {
}
}
一个类可以实现多个接口,它必须要实现接口中的所有方法。
package day11;
interface Singer {
void song();
}
interface Dancer {
void dance();
}
//一个类可以实现多个接口,它必须要实现接口中的所有方法
//可以不实现接口中的所朋方法,但是必段志明为抽象类。
class Actor implements Singer,Dancer {
@Override
public void dance() {
System.out.println("dance");
}
@Override
public void song() {
System.out.println("song");
}
}
public class Day120 {
public static void main(String[] args) {
Singer s1 = new Actor();
s1.song();//多态,调用实际引用对象的方法
// s1.dance(); //编译错误,变量的类型是Singer ,所以只能看到Singer中的方法
//强制类型转换
Dancer s2=(Dancer)s1;
s2.dance();
// s2.song(); //编译错误,变量的类型是Singer ,所以只能看到Singer中的方法
}
}
04 内部类
4.1 可以将一个类的定义放到另外一个类的内部,这叫做内部类。
//Foo是一个外部类
class Foo {
//Bar是一个内部类
class Bar {
}
}
4.2 例
//Foo是一个外部类
class Foo {
private int v1;
public Foo(int v1) {
super();
this.v1 = v1;
}
public void fooF() {
Bar bar = new Bar();
bar.barF();
}
//Bar是一个内部类
class Bar {
public void barF(){
//内部类可以直接访问外部类的数据
//内部类的对象有一个外部类对象的引用outer,无视访问修饰符
//outer不是java的关键字
System.out.println(v1);
}
}
}
public class Day121 {
public static void main(String[] args) {
//创建了一个外部类的对象
Foo f = new Foo(10);
f.fooF();
}
}
4.3 局部内部类
例一
//Foo是一个外部类
class Foo {
private int v1;
public Foo(int v1) {
super();
this.v1 = v1;
}
public void fooF() {
//Bar是一个局部内部类
class Bar {
public void barF(){
//内部类可以直接访问外部类的数据
//内部类的对象有一个外部类对象的引用outer,无视访问修饰符
//outer不是java的关键字
System.out.println(v1);
}
}
Bar bar = new Bar();
bar.barF();
}
}
public class Day121 {
public static void main(String[] args) {
//创建了一个外部类的对象
Foo f = new Foo(10);
f.fooF();
}
}
例2.1
//Foo是一个外部类
class Foo {
private int v1;
public Foo(int v1) {
super();
this.v1 = v1;
}
public void fooF() {
Bar bar = new Bar();
bar.barF();
}
//Bar是一个局部内部类
class Bar {
public void barF(){
//内部类可以直接访问外部类的数据
//内部类的对象有一个外部类对象的引用outer,无视访问修饰符
//outer不是java的关键字
System.out.println(v1);
}
}
}
public class Day121 {
public static void main(String[] args) {
// //创建了一个外部类的对象
// Foo f = new Foo(10);
// f.fooF();
//创建内部类的对象,必须有外部类的对象
Foo f = new Foo(10);
Foo.Bar bar = f.new Bar();// f.new Bar(); ->new Bar(f);
bar.barF();
}
}
例2.2
//Foo是一个外部类
class Foo {
private int v1;
public Foo(int v1) {
super();
this.v1 = v1;
}
public void fooF() {
Bar bar = new Bar();
bar.barF();
}
//Bar是一个局部内部类
class Bar {
public void barF(){
//内部类可以直接访问外部类的数据
//内部类的对象有一个外部类对象的引用outer,无视访问修饰符
//outer不是java的关键字
System.out.println(v1);
}
}
}
public class Day121 {
public static void main(String[] args) {
// //创建了一个外部类的对象
// Foo f = new Foo(10);
// f.fooF();
//创建内部类的对象,必须有外部类的对象
Foo f = new Foo(10);
//使用f.new Bar() 编译器会将f作为参数传递给Bar的构造函数
Foo.Bar bar1 = f.new Bar();// f.new Bar(); ---> new Bar(f);
bar1.barF();
Foo.Bar bar2 = f.new Bar();
bar2.barF();
}
}
局部内部类可以使内部类无法被外部察觉。
4.4 静态内部类
有时候使用内部类只是为了把一个类隐藏在另个一个类的内部,并不需要内部类引用外部类的对象。
这种情况可以使用静态内部类。
4.5 匿名内部类
4.6 练习
将Frock类声明为抽象类,在类中声明抽象方法calcArea方法,用来计算衣服的布料面积。
编写Shirt类继承Frock类,实现calcArea方法,用来计算衬衣所需的布料面积(尺寸 * 1.3)。
编写Coat类继承Frock类,实现calcArea方法,用来计算外套所需的布料面积(尺寸*1.5)。
编写Test类,测试calcArea方法。
/*
*将Frock类声明为抽象类,在类中声明抽象方法calcArea方法,用来计算衣服的布料面积。
*编写Shirt类继承Frock类,实现calcArea方法,用来计算衬衣所需的布料面积(尺寸 * 1.3)。
*编写Coat类继承Frock类,实现calcArea方法,用来计算外套所需的布料面积(尺寸*1.5)。
*编写Test类,测试calcArea方法。
*/
package day11;
abstract class Frock {
protected int size;
protected abstract double calcArea();
}
class Shirt extends Frock {
public Shirt(int size) {
this.size = size;
}
@Override
protected double calcArea() {
return size * 1.3;
}
}
class Coat extends Frock {
public Coat (int size) {
this.size = size;
}
@Override
protected double calcArea() {
return size * 1.5;
}
}
public class Day122 {
public static void main(String[] args) {
Shirt s = new Shirt(170);
System.out.println(s.calcArea());
Coat c = new Coat(180);
System.out.println(c.calcArea());
}
}