Object类是所有类型的父类
一个类如果没有父类,JVM在运行的时候会为这个类默认指定一个父类(Object)
注意:Java只能支持单继承,也就是说一个子类最多只能继承一个父类
public class Person extends Object{
}
Object成员方法如下:
场景:我定义一个类Student,这个类默认会继承Object,此时我让Student去覆写Object的toString()方法,目的将Student转换为String类型
package com.sxt.day02.demo02;
import java.util.Objects;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 10:13
* @Version 1.0
**/
public class Student {
private String name;
private int 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;
}
/**
* 将学生的属性信息转换成字符串,此时覆写了Object类型的toString()方法
* @return 学生的字符串信息
*/
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类:
package com.sxt.day02.demo02;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 10:17
* @Version 1.0
**/
public class TestStudent {
public static void main(String[] args) {
Student tom = new Student();
tom.setAge(18);
tom.setName("Tom");
// tomInfo 存储量tom对象的信息
/**
* 实体类一定要覆写Object类型的toString方法,该方法能够像外界提供对象的信息,所以也叫作名片方法
* */
/**
* 程序执行的时候jvm会检查tom对象有没有定义toString()方法,如果定义了就调用,如果没定义
* 就调用父类型的toString()方法,此时Student的父类型是Object
*/
String tomInfo = tom.toString();
System.out.println(tomInfo);
}
}
场景:我定义一个类Student,此时我让Student去覆写Object的equals()和hashCode()方法
package com.sxt.day02.demo02;
import java.util.Objects;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 10:13
* @Version 1.0
**/
public class Student {
private String name;
private int 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;
}
/**
* 将学生的属性信息转换成字符串
* @return
*/
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
// 参数的地址跟当前对象的地址一样就返回true
// this此时表示tom1 , o此时表示tom2
if (this == o) return true;
// 参数为空或者类新信息不一致,返回false
if (o == null || getClass() != o.getClass()) return false;
// 此时逐个比较tom1和tom2的每个属性值,如果属性值全部相等返回true,否则返回false
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
测试类:
package com.sxt.day02.demo02;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 10:27
* @Version 1.0
**/
public class TestEquals {
/**
* 创建两个对象,调用equals判断真假
* @param args
*/
public static void main(String[] args) {
Student tom1 = new Student();
Student tom2 = new Student();
tom1.setName("Tom");
tom1.setAge(18);
tom2.setName("Tom");
tom2.setAge(18);
// 没有覆写Object类型的equals()方法的情况下结果:false
// 如何由false变为true?此时Student需要覆写Object类型的equals()和hashCode()
System.out.println(tom1.equals(tom2));
}
}
注意:工作中定义实体类(例如:Farmer、Student),必须覆写Object类型的toString()、hashCode()、equals()方法。
如果说继承是父子之间的垂直关系(父在上,子在下),那么关联就是水平关系(例如:学生有车)
继承:is a
关联:has a
共性:都能够做到代码的复用
场景:学生有车
package com.sxt.day02.demo03;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:03
* @Version 1.0
**/
public class Car {
private String bread;
private String color;
public String getBread() {
return bread;
}
public void setBread(String bread) {
this.bread = bread;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Car(String bread, String color) {
this.bread = bread;
this.color = color;
}
/**
* 车有启动的行为
*/
public void start(){
System.out.println(bread+"启动了,颜色"+color);
}
public void speed(){
System.out.println(bread+"加速");
}
public void stop(){
System.out.println(bread+"停止");
}
@Override
public String toString() {
return "Car{" +
"bread='" + bread + '\'' +
", color='" + color + '\'' +
'}';
}
}
package com.sxt.day02.demo03;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:08
* @Version 1.0
**/
public class Student {
/**
* 学生有姓名
*/
private String stuName;
/**
* 学生有车
*/
private Car bmw = new Car("宝马","blue");
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public Car getBmw() {
return bmw;
}
public void setBmw(Car bmw) {
this.bmw = bmw;
}
public Student() {
}
public Student(String stuName, Car bmw) {
this.stuName = stuName;
this.bmw = bmw;
}
public Student(String stuName) {
this.stuName = stuName;
}
/**
* 学生具备学习方法,先开车到学校,然后开始学习
*/
public void study(){
bmw.start();
System.out.println(stuName+"开着车来学校学习");
}
}
package com.sxt.day02.demo03;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:13
* @Version 1.0
**/
public class TestStudent {
public static void main(String[] args) {
/**
* 1 创建学生对象
* 2 调用study方法,让学生开着车来学习
*/
Student tom = new Student("Tom");
tom.study();
}
}
关联的好处:代码复用,此时多个学生对象都可以使用Car的行为
package com.sxt.day02.demo04;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:32
* @Version 1.0
* 所有形状的父类,每个形状都有绘画的方法
**/
public class Shape {
public void draw(){
System.out.println("形状Shape开始绘画");
}
}
package com.sxt.day02.demo04;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:32
* @Version 1.0
* 圆形是形状的子类:子类覆盖了父类的方法
**/
public class Circle extends Shape {
public void draw() {
System.out.println("圆形Circle开始绘画");
}
}
package com.sxt.day02.demo04;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:33
* @Version 1.0
矩形是形状的子类:子类覆盖了父类的方法
**/
public class Rectangle extends Shape {
public void draw(){
System.out.println("矩形Rectangle开始绘画");
}
}
package com.sxt.day02.demo04;
/**
* @Description 三角形是形状的子类:子类覆盖了父类的方法
* @Author caojie
* @Date 2020/7/22 11:34
* @Version 1.0
**/
public class Triangle extends Shape{
public void draw(){
System.out.println("三角形 开始绘画");
}
}
package com.sxt.day02.demo04;
import com.sun.scenario.animation.shared.TimerReceiver;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:35
* @Version 1.0
* 在纸上面画形状
**/
public class Paper {
/**
* 在纸上面操作圆形(画圆形)
* @param circle
*/
public static void operatorCircle(Circle circle){
circle.draw();
}
/**
* 在纸上面画三角形
* @param triangle
*/
public static void operatorTirangle(Triangle triangle){
triangle.draw();
}
/**
* 在纸上面画矩形
* @param rectangle
*/
public static void operatorRectangle(Rectangle rectangle){
rectangle.draw();
}
/**
* 创建三个子类对象,然后调用operator相关的方法进行绘画
* @param args
*/
public static void main(String[] args) {
Circle cc = new Circle();
Triangle tt = new Triangle();
Rectangle rr = new Rectangle();
// 调用静态方法进行绘画操作
operatorCircle(cc);
operatorRectangle(rr);
operatorTirangle(tt);
}
}
上面的示例有缺陷,每增加一个子类,我都要修改Perper类,都要添加具体的operatortXXX方法,代码无法复用
优化上一个示例,只定义一个operator(Shape sh)方法,将父类作为形参,程序运行的时子类作为实参传入到父类中。
package com.sxt.day02.demo04;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:35
* @Version 1.0
* 在纸上面画形状
*
**/
public class Paper2 {
/**
* 在纸上操作(画)形状
* Paper只关注形状,不用关注具体的子类
* 此时使用父类作为形参
* @param sh
*/
public static void operator(Shape sh){
sh.draw();
}
/**
* 创建三个子类对象,然后调用operator相关的方法进行绘画
* @param args
*/
public static void main(String[] args) {
Circle cc = new Circle();
Triangle tt = new Triangle();
Rectangle rr = new Rectangle();
// 调用静态方法进行绘画操作
//操作圆形
operator(cc);
//操作 三角形
operator(tt);
// 操作矩形
operator(rr);
}
}
参数向上转型小结:父类作为形参,子类作为实参,程序运行期实参传入到形参中
// sh此时有两种状态,编译期sh指向父类型Shape,运行期sh指向子类型
public static void operator(Shape sh)
概念1:编译期不知道子类对象的类型,而是在运行期创建对象,调用恰当的方法
概念2:父类定义共性的行为,例如:Shape作为父类定义draw(), 如何绘画让子类去实现,同一个方法,可以由每个子类进行不同的实现(圆形、三角形、矩形它们的绘画方式不一样,但是他们都具备绘画的行为)
多态的支撑点:方法覆写和向上转型
目的:父类定义共性行为(做什么),通常父类不去做事,如何做全部下沉到子类。
做什么(父类定义的void draw()方法)和怎么做(子类来覆盖父类的void draw())分离
场景:形状体系,一个父类,三个子类。输入1画圆形,输入2画三角形,输入3画矩形
特点:编译期不知道创建那个子类,只有在运行期根据客户输入的数字才能创建具体的对象
package com.sxt.day02.demo05;
/**
* @Description 所有形状类型的父类
* @Author caojie
* @Date 2020/7/22 14:21
* @Version 1.0
**/
public class Shape {
/**
* 父类定义做什么
* 此时方法体为空,也是一个哑巴方法
* 怎么做下沉到子类
*/
public void draw(){}
}
package com.sxt.day02.demo05;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:32
* @Version 1.0
* 圆形是形状的子类:子类覆盖了父类的方法
**/
public class Circle extends Shape {
public void draw() {
System.out.println("形状Circle开始绘画");
}
}
package com.sxt.day02.demo05;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:33
* @Version 1.0
**/
public class Rectangle extends Shape {
public void draw(){
System.out.println("形状矩形Rectangle开始绘画");
}
}
package com.sxt.day02.demo05;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 11:34
* @Version 1.0
**/
public class Triangle extends Shape {
public void draw(){
System.out.println("三角形 开始绘画");
}
}
package com.sxt.day02.demo05;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 14:23
* @Version 1.0
* 形状工厂,唯一职责就是创建形状相关的产品
**/
public class ShapeFactory {
/**
* 根据客户输入的参数来决定创建的产品
* 输入1画圆形,输入2画三角形,输入3画矩形
* 注意:sh 此时有两种状态,编译期sh是Shape类型,运行期一旦该方法被调用sh就是子类型
* @param index
* @return 形状
*/
public static Shape create(int index){
Shape sh = null;
switch (index) {
case 1:
sh = new Circle();
break;
case 2:
sh = new Triangle();
break;
case 3:
sh = new Rectangle();
break;
}
return sh;
}
}
package com.sxt.day02.demo05;
import java.util.Scanner;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 14:26
* @Version 1.0
* 在纸上绘画形状
* 1 定义Scanner
* 2 接收用户的输入
* 3 根据用户输入的数字使用工厂的静态方法来创建具体的对象
* 4 调用对象的draw()方法进行绘画
* 多态好处:外界只用关注父类(Shape),可以完全忽略子类的存在
**/
public class Paper {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入数字:输入1画圆形,输入2画三角形,输入3画矩形");
int num = input.nextInt();
// check
if(num<1 || num>3){
System.err.println("输入错误程序退出:输入1画圆形,输入2画三角形,输入3画矩形");
return;
}
//使用工厂创建对象
Shape sh = ShapeFactory.create(num);
//调用对象的draw()行为
sh.draw();
}
}
抽象是建立在多态的基础上的,将所有事物像的行为抽取出来,定义在父类中。例如:Shape类有一个draw()方法
抽象的特征:1 是一个很泛的概念,无法实例化对象(无法创建对象)
2 父类不能new对象,只能将共有的行为抽取到父类中
抽象的关键字:abstract,该关键字可以修饰类、修饰方法。一旦某个类被abstract修饰那么该类叫做抽象类,抽象类通常作为父类,让子类去继承。如果一个子类继承了抽象类那么必须覆盖抽象类中的所有抽象方法。
抽象类中可以定义抽象方法、也可以定义非抽象方法、还可以定义静态属性和非静态属性
抽象类不能使用new关键字创建对象。
注意:如果一个抽象类中没有抽象方法那么将失去意义,因为抽象类通常作为父类,子类去继承抽象类覆写抽象方法。
场景:定义一个抽象类Shape作为父类,每个形状都有绘画的行为和清除(clear())的行为, 他们是一个整体,每个形状必须先绘画然后清除
package com.sxt.day02.demo06;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 15:11
* @Version 1.0
*
**/
public abstract class Shape {
/**
* 抽象类不仅仅能够定义抽象方法,还能够定义具体方法,一旦抽象类中定义了具体方法,
* 那么子类可以无条件的使用,前提是具体方法不能私有
*
*/
public void action(){
draw();
clear();
}
/***
*
* 一旦某个方法使用abstract修饰,该方法就是一个抽象方法,抽象方法不能有方法体
* 编译错误:抽象方法不能有方法体
* Abstract methods cannot have a body
*/
// public abstract void draw(){}
public abstract void draw();
public abstract void clear();
}
小结:抽象类中具体方法可以调用抽象方法,上面代码编译期draw()和clear()是父类的方法,运行期由于在工厂中创建了具体类型的对象,所以运行期draw()和clear()调用的是子类的方法。
子类可以覆盖父类的抽象方法,也可以使用父类具体方法,工作中尽量不要覆盖父类的具体方法,只覆盖父类的抽象方法。
工作中如果使用抽象类,抽象类通常作为父类
子类继承父类最后继承抽象类,尽量不要继承具体类
package com.sxt.day02.demo06;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 15:18
* @Version 1.0
**/
// 编译错误:子类继承抽象类,必须覆写抽象类中的抽象方法
// Class 'Circle' must either be declared abstract or implement abstract method 'draw()' in 'Shape
// class Circle extends Shape{
// }
class Circle extends Shape{
/**
* @Override 跟功能无关:告诉我此时子类的draw()方法是覆盖了父类的draw()方法
*/
@Override
public void draw() {
System.out.println("圆形绘画");
}
@Override
public void clear() {
System.out.println("圆形清理");
}
}
package com.sxt.day02.demo06;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 15:30
* @Version 1.0
**/
class Rectangle extends Shape{
@Override
public void draw() {
System.out.println("矩形绘画");
}
@Override
public void clear() {
System.out.println("矩形清理");
}
}
package com.sxt.day02.demo06;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 15:30
* @Version 1.0
**/
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("三角形绘画");
}
@Override
public void clear() {
System.out.println("三角形清理");
}
}
package com.sxt.day02.demo06;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 15:33
* @Version 1.0
**/
public class ShapeFactory {
public static Shape createShape(int index) {
Shape sh = null;
switch (index) {
case 1:
sh = new Circle();
break;
case 2:
sh = new Triangle();
break;
case 3:
sh = new Rectangle();
break;
}
return sh;
}
}
测试类:
package com.sxt.day02.demo07;
import com.sxt.day02.demo06.Shape;
import com.sxt.day02.demo06.ShapeFactory;
import java.util.Scanner;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 15:35
* @Version 1.0
**/
public class Paper {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入数字:输入1画圆形,输入2画三角形,输入3画矩形");
int num = input.nextInt();
// check
if(num<1 || num>3){
System.err.println("输入错误程序退出:输入1画圆形,输入2画三角形,输入3画矩形");
return;
}
// 根据输入的整数创建形状
Shape sh = ShapeFactory.createShape(num);
sh.action();
}
}
接口是一个标准,或者说接口是一个协议,如果某个类实现了接口就必须准许接口的标准(协议)
JDK1.8以前接口只能定义常量,定义方法声明,不能定义方法的实现,方法实现必须由子类去覆写
JDK1.8之后,提供了一个default关键字,可以在接口中定义方法的实现
一个类最多只能继承(extends)一个父类
一个类可以实现(implements)N个接口
接口中定义的属性必须赋初始值,也就意味着接口中的属性都是 public static final
JDK1.8之前接口中定义的方法,默认是public abstract
小结:接口使用interface关键字定义,如果子类实现接口必须使用implements
一个子类可以实现多个接口,可以变相的多重继承
接口是一个标准,如果某个类实现接口必须覆盖接口中定义的所有方法,除了default以外
接口和实现类之间的关系?
肯德基和肯德基加盟店之间的关系,加盟店必须实现KFC所有的标准
package com.sxt.day02.demo08;
public interface Shape {
// int num =10;
// 程序运行的时候默认会为你添加 public static final
public static final double CIRCLE_PI = 3.14;
public void draw();
// 接口中没有定义public,jvm运行的时候自动帮你加上 public abstract
// public abstract void clear();
void clear();
// 接口不能定义private和protected
// protected void aac();
}
场景1:定义一个形状接口Shape,改接口只有一个方法draw(), 圆形去实现Shape接口
package com.sxt.day02.demo09;
/**
* 形状是一个接口,也是一个标准,所有实现Shape的子类必须实现接口中所有的方法
*/
public interface Shape {
void draw();
}
package com.sxt.day02.demo09;
import java.sql.SQLOutput;
/**
* @Description Circle 实现Shape接口,必须覆写接口中所有的方法(除了default不用覆写)
* @Author caojie
* @Date 2020/7/22 16:27
* @Version 1.0
**/
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("圆形正在绘画...............");
}
}
package com.sxt.day02.demo09;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:28
* @Version 1.0
**/
public class Test {
public static void main(String[] args) {
Shape sh = new Circle();
sh.draw();
}
}
场景2:定义一个形状接口Shape, 有clear()和draw()方法,定义三个形状分别是圆形、矩形、三角形去实现接口,一次创建10个形状,具体的形状使用随机数产生,1圆形2三角形3矩形
从这里开始看 !!!!!
package com.sxt.day02.demo10;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:33
* @Version 1.0
**/
public interface Shape {
void draw();
void clear();
/**
* default 修饰的方法是默认实现的方法,子类可以不用实现默认方法
* 实现类可以使用default修饰的方法
*/
public default void action(){
draw();
clear();
}
}
package com.sxt.day02.demo10;
import java.sql.SQLOutput;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:36
* @Version 1.0
**/
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("圆形绘画");
}
@Override
public void clear() {
System.out.println("圆形清除");
}
}
package com.sxt.day02.demo10;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:36
* @Version 1.0
**/
public class Rectangle implements Shape{
@Override
public void draw() {
System.out.println("矩形绘画");
}
@Override
public void clear() {
System.out.println("矩形清除");
}
}
package com.sxt.day02.demo10;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:37
* @Version 1.0
**/
public class Triangle implements Shape{
@Override
public void draw() {
System.out.println("三角形绘画");
}
@Override
public void clear() {
System.out.println("三角形清除");
}
}
package com.sxt.day02.demo11;
import com.sxt.day02.demo10.Circle;
import com.sxt.day02.demo10.Rectangle;
import com.sxt.day02.demo10.Shape;
import com.sxt.day02.demo10.Triangle;
import java.util.Random;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:41
* @Version 1.0
* 1定义形状数组
* 2 创建随机数对象
* 3 通过数字产生形状 1圆形2三角形3矩形
* 4 调用形状的方法
**/
public class Paper {
/*
运行期存储具体的形状
*/
private static Shape [] shapes = new Shape[10];
// 填充数组的元素
static{
Random random = new Random();
for (int i = 0; i < shapes.length ; i++) {
//产生随机数
int num = random.nextInt(3)+1;
switch (num){
case 1:
shapes[i] = new Circle();
break;
case 2:
shapes[i] = new Triangle();
break;
case 3:
shapes[i] = new Rectangle();
break;
}
}
}
public static void main(String[] args) {
// 便利数组的每个元素,调用action()方法
for(Shape sh : shapes){
sh.action();
System.out.println("---------------------------------------");
}
}
}
场景:如果创建的对象是圆形(Circle)除了执行draw()方法和clear()方法之外还要计算面积
如何做?
需要判断Shape对象是否是圆形,如果是将其向下转换为Circle,然后调用Circle的draw()方法
package com.sxt.day02.demo10;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:33
* @Version 1.0
**/
public interface Shape {
void draw();
void clear();
/**
* default 修饰的方法是默认实现的方法,子类可以不用实现默认方法
* 实现类可以使用default修饰的方法
*/
// public default void action(){
// draw();
// clear();
// }
}
package com.sxt.day02.demo10;
import java.sql.SQLOutput;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:36
* @Version 1.0
* 注意:工作中向外界只暴露接口,实现类最好向外界隐藏(不适用public修饰,外界无法new)
**/
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("圆形绘画");
}
@Override
public void clear() {
System.out.println("圆形清除");
}
/**
* 计算面积的方法是圆形独有的,其他子类没有这个方法
* @param radius 半径
* @return 面积
*/
public double calcArea(int radius){
return radius * radius * 3.14;
}
}
package com.sxt.day02.demo10;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:36
* @Version 1.0
**/
public class Rectangle implements Shape{
@Override
public void draw() {
System.out.println("矩形绘画");
}
@Override
public void clear() {
System.out.println("矩形清除");
}
}
package com.sxt.day02.demo10;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:37
* @Version 1.0
**/
public class Triangle implements Shape{
@Override
public void draw() {
System.out.println("三角形绘画");
}
@Override
public void clear() {
System.out.println("三角形清除");
}
}
测试类:
package com.sxt.day02.demo11;
import com.sxt.day02.demo10.Circle;
import com.sxt.day02.demo10.Rectangle;
import com.sxt.day02.demo10.Shape;
import com.sxt.day02.demo10.Triangle;
import java.util.Random;
/**
* @Description TODO
* @Author caojie
* @Date 2020/7/22 16:41
* @Version 1.0
* 1定义形状数组
* 2 创建随机数对象
* 3 通过数字产生形状 1圆形2三角形3矩形
* 4 调用形状的方法
**/
public class Paper {
/*
运行期存储具体的形状
*/
private static Shape [] shapes = new Shape[10];
// 填充数组的元素
static{
Random random = new Random();
for (int i = 0; i < shapes.length ; i++) {
//产生随机数
int num = random.nextInt(3)+1;
switch (num){
case 1:
shapes[i] = new Circle();
break;
case 2:
shapes[i] = new Triangle();
break;
case 3:
shapes[i] = new Rectangle();
break;
}
}
}
public static void main(String[] args) {
// 便利数组的每个元素,调用action()方法
for(Shape sh : shapes){
// sh.action();
sh.draw();
// sh编译期是Shape类型,将强制转换为Circle,强制转换也叫作向下转型
// 向下转型不安全,因为sh编译期是Shape,形状不一定是圆形
// 通常在工作中向下转型之前要做check,判断当前的sh是否是圆形的实例
// 条件成立:表示sh是圆形的实例,执行向下转型
if(sh instanceof Circle){
Circle circle = (Circle)sh;
double area = circle.calcArea(3);
System.out.println("圆形面积="+area);
sh.clear();
}
sh.clear();
System.out.println("---------------------------------------");
}
}
}
toString() equals()
平行关系: has a 学生有车
编译期父类作为形参,运行期子类可以向上转换为父类
编译期就已经知道对象的类型
运行期根据客户传递的参数创建对象,调用恰当的方法
Shape sh;
sh 编译期是父类 运行期根据工厂创建的形状就是一个子类型
抽出向的行为
父类定义做什么,怎么做下沉到子类。目的:做什么和怎么做分离
通常父类定义共性的行为,父类最好不定义属性,所有的属性下沉到子类,因为 圆形和三角形他们的属性不同。
接口和抽象类的共性:都是用于父子之间的继承
子类通常使用extends关键字继承父类,使用implements实现接口
一个子类可以实现多个接口
预习:抽象类和接口区别
接口多继承
内部类
垃圾回收