面向对象笔记

概念

面向对象:oop (Object Oriented Programming)

​ 是一种编程思想(写代码的固定套路/步骤)

​ 面向对象:c# python object-c java scala

面向过程:pop (Procedure Oriented Programming)

​ 面向过程:c c++

解决吃饭:

​ 1 自己做饭:

​ 洗菜–洗米–煮米–炒菜–盛饭–吃饭–刷碗

​ 面向过程:亲力亲为

​ 按动作把解决问题的过程分成多个步骤 逐个步骤去完成 最终解决问题

​ 2 让别人帮你做

​ 找饭店—点菜(指挥厨师做饭)—吃饭

​ 面向对象:找正确的对象(万物皆对象)

​ 找具有帮助我解决问题功能的对象 指挥对象解决问题

面向对象优点:

​ 1 由执行者转换为指挥者 简化过程

​ 2 提高代码复用性

​ 3 更符合现在人的生活–(怎么生活 就怎么写代码)

面向对象的步骤

需求:让大象进行自我介绍

给电脑描述人这种数据的类型-------->电脑中创建一个人的模型----->模型的数据和大象保存一致----->电脑中有个大象的模型----->大象电脑中进行自我介绍

public class Demo01Oop {
    /*
	需求:让大象进行自我介绍

	给电脑描述人这种数据的类型-------->
	电脑中创建一个人的模型----->
	模型的数据和真实大象保存一致----->
	电脑中有个大象的模型----->
	大象电脑中进行自我介绍    
	
	分析过程用代码实现
	1 给电脑描述人的类型
	         数据+功能      
	             用变量表示数据
	             用方法表示功能  
	            创建一个类 描述人这个类型:通过变量表示数据 通过方法表示功能      
	2 根据描述 在电脑中创建一个 人类的模型   
	              格式:类名 对象名=new 类名();
	3                   
	*/
    public static void main(String[] args) {
        //2 根据描述 在电脑中创建一个 人类的模型   
        Person p1=new Person();
        //3 给对象的变量赋值(与现实实物的数据保持一致)
        p1.sex='男';
        p1.age=66;
        p1.name="大象";
        p1.job="喝水";
        //4 调用对象的方法 来解决问题
        p1.show();

    }
}
//创建一个类 描述人这个类型           
class Person{
    //通过变量表示数据 
    char sex;
    int age;
    String name;//String是字符串类型
    String job;

    //通过方法表示功能    
    void show() {
        System.out.println("我加"+name+",今年"+age+"岁,我是"+sex+"生,职位是:"+job);
    }
    void smoke() {
        System.out.println(name+"正在吸烟!");
    }
}

类和对象的概念

**成员:类中定义的变量和方法
成员变量:类中定义的变量
成员方法:类中定义的方法
类中定义什么成员变量 此类创建的对象就拥有什么属性
类中定义什么成员方法 此类创建的对象就拥有什么功能
类: 对一类事物的描述
是成员变量和成员方法的封装
是用于创建对象的模板/图纸
对象:多个基本数据有机组合形成一个复杂数据
对象是根据类创建的实例
现实实物在电脑中的模型 **

public class Demo02Oop {
	//面向对象的方法 不用再加修饰符

	public static void main(String[] args) {
		//2 根据类创建对象
		Student s1=new Student();
		//Student类中定义了什么变量  此类创建的对象就有什么数据
		//Student类中定义了什么方法 此类创建的对象就有什么功能
		//3 给对象的变量赋值
		s1.age=19;
		s1.name="梁贵莹";
		s1.sex='男';
		s1.sid=1001;
		//4 调用对象的方法
		s1.show();
		s1.printHe(12, 13);
		
		Student s2;//定义一个引用  此引用要指向一个Student类型的对象
		s2=new Student();//一个new 就新创建一个对象
		s1=s2;//让s1指向s2指向的对象(21行的对象)   s1和第八行的对象无关了 
		//对象的变量不赋值 有默认初始值:0/null
		s2.show();//学生:name=null,age=0,sid=0,sex=' '
		s2.sex='女';
		s2.show();
		//每个对象都拥有一套类中定义的变量和方法        
		System.out.println(s1);//com.zhiyou100.day07.Student@7852e922		
	}
}
//1 创建类描述学生这个类型
// 类中需要定义那些变量和方法 取决于需求
class Student{
	//通过变量表示数据
	int sid;
	String name;
	char sex='男';//给此类创建的所有对象的sex属性赋默认值
	int age;
	//通过方法表示功能
	void show() {
		System.out.println("学生:name="+name+",age="+age+",sid="+sid+",sex="+sex);
	}
	//方法中可以使用两种变量:类中直接定义的变量+参数列表
	//把什么样的变量 在类中定义
	//把什么样的变量 在方法的参数列表中定义
	void printHe(int a,int b) {
		System.out.println(name+"正在算术:"+a+"+"+b+"="+(a+b));
	}
}

方法重载

public class Demo03Overload {
    //重载:overload
    //同一个类中  几个方法 方法名相同 参数列表不同的现象
    //重载要求:必须是同一个类
    //       方法名必须相同
    //       参数列表必须不同:参数个数不同   参数类型不同  参数顺序不同
    //方法重载:类似于生活中的同卵双胞胎
    //为什么几个方法要重载:这几个方法功能基本一致  只是需要的参数不同而已
    public static void main(String[] args) {
        //创建对象
        Stu s=new Stu();
        s.name="梁贵莹";
        s.add(1, 2);
        s.add(1, 1.2);//重载方法调用 通过参数列表区分
        s.show();//普通方法调用 通过名字区分
    }

}
//一个源文件中可以有多个class
//只能有一个public修饰的class 并且此class的名字必须和源文件名字一致
class Stu{
    String name;
    //求和:两个int
    void add(int a,int b) {
        System.out.println(name+"正在求和:两个int "+a+"+"+b+"="+(a+b));
    }

    //求和:一个int 一个double
    void add(int a,double b) {
        System.out.println(name+"正在求和:1个int 1个double "+a+"+"+b+"="+(a+b));
    }
    void add(int a,int b,int c) {
        System.out.println(name+"正在求和:三个int "+a+"+"+b+"+"+c+"="+(a+b+c));
    }
    void add(double a,int b) {
        System.out.println(name+"正在求和:1个double 1个int  "+a+"+"+b+"="+(a+b));
    }
    void show() {}
}

构造方法

public class Demo04Constructor {
    /*构造方法:构造器  构造函数 Constructor
     *构造方法:类中定义的用于构建创造对象的方法
     *构造方法特点:
     *        1  构造方法没有返回值 不用void标示
     *        2  构造方法名字必须和类名相同   
     *        3  对象不能调用构造方法
     *        4  构造方法只能被关键字new调用  每调用一次 创建一个新的对象
     *        5  一个类如果没有构造方法    默认有一个无参数的构造方法
     *        6  构造方法的参数列表一般是给对象的属性赋值
     * */
	public static void main(String[] args) {
		//创建对象
		Teacher t=new Teacher();
		t.age=31;
		t.show();
		Teacher t1=new Teacher();

	}
}
class Teacher{
	int age;
	String name;
	String subject;
	float salary;
	void show() {
		System.out.println("Teacher:name="+name+",age="+age+".subject="+subject+",salary="+salary);
	}
//	//Teacher类中没有Teacher() 但可以使用  说明编译器默认添加一个
//	void Teacher() {//普通方法
//		//This method has a constructor name
//		System.out.println("void Teacher()");
//	}
	Teacher(int a,String n) {//构造方法
		    age=a;name=n;//构造方法的参数列表一般是 给对象的属性赋值
			System.out.println("Teacher(int a,String n) ");
	}
	Teacher() { }
}

this使用

/*this: 当前对象:::哪个对象调用当前方法 this指的就是哪个对象
     *  使用场景1:成员变量与局部变量重名时  变量名指向的是局部变量
     *          通过this.变量名来调用成员变量
     *          注意:方法中调用成员  前面默认有this.
     *  使用场景2:  构造方法相互调用通过this(参数列表) 
     *          注意:this(参数列表) 必须是第一个语句
     * */
class Demo{
	int a=2;
	int b;
	int c;
	int e;
	Demo(){}
	//为什么写多个构造方法:满足创建不同对象的需求
	Demo(int a,int b,int c){
		this.a=a;this.b=b;this.c=c;
		System.out.println("Demo(int a,int b,int c)");
	}
	Demo(int a,int b,int c,int e){
		this(a,b,c);//调用构造方法Demo(int a,int b,int c) 复用其方法体
		this.e=e;
		System.out.println("Demo(int a,int b,int c,int e)");
	}
	void show() {
		System.out.println("a="+a+",b="+b);
	}
	//局部变量:方法参数列表以及方法体中定义的变量
	//成员变量:类中定义的变量
	void hai(int a) {
		int c=2;
		//此方法中可以访问到两个a:成员变量a和方法参数a
		//成员变量与局部变量重名
		System.out.println("a="+a);//变量名默认指向的局部变量----就近原则
		System.out.println("this.a="+this.a);//通过this.变量来调用成员变量
		System.out.println("this="+this);
		System.out.println(b);//方法中调用成员 前面默认有this.  //this.b
		show();//this.show();
	}
}

构造方法和普通方法区别

//4  总结构造方法和普通方法的区别
//构造方法:类中用于构建创建对象的方法
//普通方法:类中定义的具有指定功能的代码块
//相同之处:都是方法-都是类的成员
//不同之处1:格式不同
//        普通方法必须有返回值类型的标示  没有返回值用void标示
//        构造方法没有返回值  不用void标示
//不同之处2:调用不同
//        普通方法被对象调用  一个对象可以调用多次
//        构造方法不能被对象调用  只能被关键字new调用 每调用一次创建一个对象
//不同之处3:是否有默认
//        一个类如果没有定义构造方法 默认有一个无参数的构造方法
//不同之处4:命名不同
//       构造方法名字必须是类名  普通方法名字可以是类名(但不规范)
//不同之处5:作用不同
//       构造方法作用:创建对象
//       普通方法作用:代表的是本类创建的对象具有的某个指定功能

setValue

给对象赋值的方式

/*需要一个红色的车:
     *  1 出厂就是红色的
     *  2 买回来后自己喷漆
     *  3 买回来后 去4s店喷漆
     *  4 出厂定制
     *给对象的属性赋值方式
     *方式1:对象名.属性名
     *    eg:c.color='红';
     *    特点:必须先创建对象   只能给当前对象的属性赋值
     *    缺点:不安全 不可控  Car类无法控制color属性的合理取值
     *方式2: 通过构造方法参数列表给属性赋值   
     *    eg:Car cc=new Car("bmw");
     *    特点:对象一创建 属性就有指定的值  只能给当前对象的属性赋值
     *        数据可控
     *方式3:  在类中直接给成员变量赋值
     *    eg:double money=19999;
     *    特点:此类创建的所有对象的此属性的初始值都是此值
     *        
     *方式4:通过普通方法的参数列表给属性赋值
     *     eg: cc.setNumber("豫A 88888");
     *    特点:必须先创建对象   只能给当前对象的属性赋值      
     *        首选  
     */

创建对象内存图

在这里插入图片描述

Private 属性私有化封装

/*封装:对实现细节进行包装隐藏
     *   类---对描述同一类事物的数据和功能的封装
     *   属性私有化: 让属性对可信任的类/对象可见  对不可信任的类/对象隐藏
     *   目的:数据可控     
     *   
     *1  属性添加修饰符private (只有在本类中可以访问)  
     *2  提供公共的getter/setter方法 来间接访问
     *      public 类型  getXxx();
     *      public void setXxx(类型 xxx);
     *3  不可信任的对象 通过调用方法来操作属性
     * 
     *注意:所有的属性必须私有化
     * */
public static void main(String[] args) {
        Demo02 d1=new Demo02();
        d1.sex='1';
        //d1.age=19;//无法直接访问
        d1.setAge(-19);
        d1.show();
    }
}
class Demo02{
    private int age;
    char sex;
    public static void main(String[] args) {
        Demo02 d1=new Demo02();
        d1.sex='1';
        d1.age=19;//本类为可信任的类 可以直接访问
    }
    public int getAge() {return this.age;}
    public void setAge(int age) {
        if(age<=0||age>=130) {return;}
        this.age=age;
    }
    void show() {
        System.out.println("age="+age+",sex="+sex);
    }
}

Static 静态

/*
     * 案例Stu1:每个学生都有自己的name和sex
     *        每个学生也都拥有属于自己的班级名称  公司名称 饮水机----和现实不一致---现实中这些数据只有一份 大家共同使用
     *        
     * static:静态的   修饰符:可以(修饰内部类+静态代码块+)成员变量+普通方法
     * static修饰成员变量:
     *       1 static修饰的变量 不但可以被对象调用  还可以通过类名直接调用
     *       2 static修饰的变量是共享数据  所有对象共用一个
     * static修饰普通方法
     *       1 static修饰的方法 不但可以被对象调用  还可以通过类名直接调用
     *       2 静态方法只能调用静态成员(静态成员变量+静态普通方法)  
     *         非静态方法可以调用所有的成员(静态成员+非静态成员)
     *
     * 什么情况下把一个成员变量定义为静态变量
     *     :当数据不是仅属于某个对象  而是所有对象公用时  定义为静态变量
     * 什么情况下把一个普通方法定义为静态方法
     *     :当一个方法中不涉及非静态成员时  尽量把此方法定义为静态方法
     *
     * 静态成员(静态成员变量+静态普通方法) 在静态区域中加载
     * 当类加载 会为此划分一块区域作为静态区域 来加载本类所有静态成员
     * 
     * 类成员---被static修饰的成员--static修饰的成员变量和成员方法
     * 实例成员--没有被static修饰的成员
     * 类变量--被static修饰的成员变量
     * 类方法--被static修饰的成员方法
     * 实例变量--没有被static修饰的成员变量 
     * 实例方法--没有被static修饰的成员方法     
     * 
     * */

static内存图

在这里插入图片描述

Extends 继承

 /*
               继承: 龙生龙 凤生凤
               关键字:extends  
               概念: 当定义一个新类时 如果新类拥有一个现有的类所有成员 
               可以让此新类从现有的类派生、衍生
                新类:子类
                现有的类:父类、超类、根类
                格式: class 子类 extends 父类{}  
                作用:   实现类的复用+创建类与类之间的关系      
                特点:    1  子类会继承父类中定义的所有实例成员
          				 2  子类继承了父类的私有成员  但不能直接使用         
          				 3  子类不能继承父类的构造方法
         				 4  子类中可以定义父类没有的成员--子类特有
          				 5  子类可以根据自己的需求对继承于父类的成员进行重新定义
                 重新定义父类的成员变量要求:变量名相同即可    
                 重写定义父类的普通方法要求:
                 方法声明必须和父类一致:方法名相同 参数列表相同 返回类型相同
           				 6   java只支持类与类的单继承:一个子类只能有一个直接父类
           				 7   所有的类直接或者间接继承Object::::
           				     一个类如果没有继承其他类 默认继承Obejct类
     * */
 public static void main(String[] args) {
        Teacher t1=new Teacher();
        t1.show();
        System.out.println("t1.name="+t1.name);
    }
}
class Person{
    private int age;
    String name="父类name";
    void show() {System.out.println(name+":"+age);}

    Person(){}
    Person(int a){}
}
//Teacher中拥有Person类中的所有成员
class Teacher extends Person{
    //	int age;
    //	String name;
    //	void show() {System.out.println(name+":"+age);}

    //String name="子类name";//重新定义成员变量
    int name=1;//重新定义成员变量
    void show(int a) {}//子类特有
    void show() {//重新定义普通方法---重写 override
        System.out.println(name+":"+salary);
    }

    float salary;//子类特有
    void hai() { }
}

继承内存图

在这里插入图片描述

重载(Overload)和重写(Override)的区别

概念: 重载--overload--同一个类中几个方法 方法名相同参数列表不同的现象
      重写--override--子类根据自己的需求对父类的方法进行重新定义
相同之处:说的都是方法
        要求方法名相同
不同之处: 
      1 涉及的类个数不同:
              重载只涉及一个类
              重写必须继承  涉及子类和父类
      2  要求不同:
              重载要求:方法名相同参数列表不同
              重写要求:除了范围修饰符可以扩大 其他方法声明必须和父类完全相同
      3  影响不同:
              重载的方法之间互相没有影响:只是调用时不同通过方法名区分 而是通过参数列表区分
              重写:子类重写父类的方法 子类中从父类继承的方法被隐藏
      4 意义不同:
              重载:几个方法基本功能相同  只是方法运行需要的原始数据不同而已
              重写:子类根据自己的需求 对父类已有的功能进行扩展
       

范围修饰符

//范围修饰符:让被修饰者具有一些本来不具有的特征
	//        用来指定被修饰者的作用范围
	//public protected  (default) private
	//可以修饰:类、成员变量、方法
	/* 关键字     名称                 作用范围                       
	 * public    公共的                整个项目
	 * protected 受保护的              本包+其他包的子类
	 * (default) 省略的                本包
	 * private   私有的                本类
	 * */
注意:类只能加public和省略两种情况

super

/*
     *super: 和 this比较起来学习
     *this:当前对象/我自己的
     *使用场景1:成员变量和局部变量重名  通过this.变量名来指向成员变量
     *        注意:方法体中提到实例成员(成员变量+成员方法)  前面默认有this.
     *使用场景2: 构造方法之间相互调用  通过this(参数列表)
     *        注意:this(参数列表) 必须是第一个语句
     *                
     *super: 父类  /我爹的
     *使用场景1: 子类重新定义父类已有的成员  子类中从父类继承的成员会被隐藏
     *        在子类方法中 通过super.成员  调用父类因被重新定义而隐藏的成员
     *        注意:子类方法中  所有的子类成员前面默认有super.
     *使用场景2:  所有的子类构造方法中第一个语句必须是super(参数列表) 来调用父类的构造方法
     *        (在创建子类对象时  通过super(参数列表)来调用父类的构造方法 把父类中定义的实例成员加载进子类对象内存中)
     *        注意:所有子类构造方法中第一个语句默认是super()          
     * */

final

public class Demo07Final {
    /* 

     * final :修饰符    最终的
     *       可以修饰:类+成员方法+成员变量+局部变量
     *       
     * final修饰类(最终类): 不能被继承
     * 
     * final修饰的方法(最终方法):    不能被子类重写
     * 
     * final修饰的变量(常量):值不能更改
     *       1:final修饰的成员变量没有默认初始值
     *       2:final修饰的变量不能二次赋值        
     * 
     * 把变量定义为final优点:
     *       1 简化书写    
     *       2 增加可读性
     * 
     * 注意:final常量命名规范:所有字母大写 单词之间用_分割
     *      final String MY_PERSON_ID="410185198600000000";
     * */
    public static void main(String[] args) {
        DemoFinal  d=new DemoFinal();
        Demo071 d1=new Demo071(1);
        d1.hai();
        System.out.println(d1.b2);
        //d1.b2=1;//The final field Demo071.b2 cannot be assigned

        System.out.println(3.1415926);
        final double pi=3.1415926;
        System.out.println(pi);
        System.out.println(pi);

        final int a=1;//final类型的基本数据类型数据:不能二次赋值
        final Demo77 d7=new Demo77();//final修饰的引用数据类型数据:不能再指向其他对象 
        d7.a=11;
    }
}
class Demo77{
    int a;
}
class Demo071{
    int a;
    //final修饰的成员变量没有默认初始值  必须显式赋值
    //final int b;//The blank final field b may not have been initialized
    //给final成员变量赋值方式1:
    final int b1=1;//所有对象的b1值都是1
    final int b2;
    //给final成员变量赋值方式2:
    Demo071(int b2){
        this.b2=b2;
    }
    final void hai() {
        System.out.println(b2);
    }
}
class Demo071Zi extends Demo071{
    //Cannot override the final method from Demo071
    //void hai() {}
    Demo071Zi(){super(1);}
}
final class DemoFinal{}
//class DemoFinalZi extends DemoFinal{}
//The type DemoFinalZi cannot subclass the final class DemoFinal

非静态final变量的赋值方式

1、定义初始值

final int a=10;

2、非静态代码块

final int b;
	{
		b=10;
	}

3、调用构造方法初始化

final int c;
	C(int c){
		this.c=c;
	}

静态final变量的赋值方式

为什么不能用构造方法初始化变量的值?

答:因为静态变量是随着类加载而加载的,构造方法是对象被创建时才被调用的方法,创建对象在类加载之后,所以构造方法不能对静态变量进行初始化。

1、定义初始化

static final  int d=10;

2、静态代码块

final static int e;
	static {
		e=10;
	}

成员变量和局部变量的区别:

  • 1、从语法形式上看,成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数
    成员变量可以被public,private,static等修饰符所修饰,而局部变量不能被访问控制修饰符及static所修饰
    但是,成员变量和局部变量都能被fianl所修饰
    2、从变量内存中地存储方式看,成员变量是对象的一部分,而对象存在于堆内存中,局部变量存在于栈内存
    3.从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而
    局部变量随着方法的调用而自动消失*。
    4、成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外:被final修饰的但没有被static修饰的成员变量必须显示地赋值);而局部变量则不会自动赋值

抽象

public class Demo01Abstract {
    /*抽象:abstract
     *概念:笼统  模糊  不具体
     *    修饰符:只能修饰类和方法
     *特点:
     *     1  抽象方法不能有方法体
     *     2  有抽象方法的类必须是抽象类       但抽象类可以没有抽象方法
     *     3  抽象类不能创建对象  但可以定义引用
     *     4  抽象类有构造方法:抽象类的构造方法不是用于创建本类对象  而是用于帮助创建子类对象
     *         (在创建子类对象时  把抽象类中的非抽象方法和成员变量加载进子类对象内存中)
     *     5  抽象类的子类除非重写所有的抽象方法(重写抽象方法---实现)  否则任然是抽象类
     *作用:为子类定义规范
     *思考:什么情况下把一个方法定义为抽象方法:::当信息不完整 方法体无法实现时 
     *    什么情况下把一个类定义为抽象类:::类没有必要创建对象时 
     * */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo01 d;
        //d=new Demo01();//Cannot instantiate the type Demo01  抽象类不能创建对象

    }
}
abstract class Demo01{
    Demo01(){}
    void hehe() {}
    abstract void hai();
    //	- The abstract method hai in type Demo01 can only be defined by an abstract class
    //有抽象方法的类必须是抽象类
    //	- Abstract methods do not specify a body
    //抽象方法不能有方法体
}
class Demo01Zi extends  Demo01{
    Demo01Zi(){
        super();
    }
    void hai() {}
}
abstract class Demo02{
    void hehe() {} 
}
//某公司的雇员分为以下若干类:
//Employee:这是所有员工总的父类,属性:员工的姓名,员工的生日月份。
//       方法:getSalary(int month) 根据参数月份来确定工资,如果该月员工过生日,则公司会额外奖励100元。
abstract class Employee{
    String name;
    int birthMonth;
    //此Employee类是所有员工的类父类---此类中的成员 是所有员工类共同的成员
    //员工都有getSalary 不同员工的工资结构不同
    abstract double getSalary(int month);//信息不完整   需要发多少工资 不明确 此方法功能无法实现  方法体没法写
    void hai() {}
}
class HourlyEmployee extends Employee{
    void hai() {}
    double hourSalary;
    int hours;
    //子类根据自己的需求 实现父类的抽象方法
    double getSalary(int month) {
        hai();
        super.hai();
        return hours*hourSalary+(hours>160?(hours-160)*0.5*hourSalary:0)+(month==birthMonth?100:0);
    }
}

抽象练习

public class LianXi01 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Circle  c=new Circle();
        c.r=12;
        System.out.println("周长="+c.qiuZC());
        System.out.println("面积="+c.qiuMJ());
    }
}
//创建一个形状类shape:有求周长和求面积方法
//Shape类没有必要创建对象   信息不完整
abstract class Shape{
    //求周长方法:信息不完整(不知道具体的形状 没有公式) 方法功能无法实现  应该写成抽象方法
    abstract double qiuZC();
    abstract double qiuMJ();
}
//shape类存在的意义:不是创建对象  而是为子类定义规范
//(必须有求周长和求面积的方法  方法声明必须和我一样  但方法体根据自己需求写)
//创建子类circle类:有属性半径和圆周率
class Circle extends Shape{
    double r;
    final double PI=3.14;
    //根据自己的需求  实现抽象方法
    double qiuZC() {
        return 2*PI*r;
    }
    double qiuMJ() {
        return r*r*PI;
    }
}
//创建子类rect类:有属性长和宽
class Rect extends Shape{
    double chang;
    double kuan;
    //根据自己的需求  实现抽象方法
    double qiuZC() {
        return 2*(chang+kuan);
    }
    double qiuMJ() {
        return chang*kuan;
    }
}

多态的概念(什么是多态)

public class Demo02DuoTai {

	public static void main(String[] args) {
		Fu fu=new Fu();//正宗的父类对象
		Zi zi=new Zi();
		 
		Fu fuzi=new Zi();//引用是父类类型  对象是子类类型
	    //多态:等号两边多种形态  
		//    给子类对象起个父类类型的名字、把子类对象伪装成父类类型、让父类引用指向子类对象     }
}
class Fu{
	String name="fu-name";
	int a=1;
	void show() {System.err.println("fu--show方法");}
	void hai() {System.out.println("fu-hai方法");}
}
class Zi extends Fu{
	String name="zi----name";
	int b=1;
	void show() {System.err.println("zi------show方法");}
	void nihao() {System.out.println("子类特有方法");}
}

多态的特点(多态的对象有什么特点)

public class Demo02DuoTai {
	public static void main(String[] args) {
		Fu fu=new Fu();//正宗的父类对象
		Zi zi=new Zi();
		 
		Fu fuzi=new Zi();//引用是父类类型  对象是子类类型
	    //多态:等号两边多种形态  
		//    给子类对象起个父类类型的名字、把子类对象伪装成父类类型、让父类引用指向子类对象
        System.out.println(fuzi.a);
        
        //多态对象:被伪装成父类类型的子类对象  起了父类类型名字的子类对象
        //父亲:脸上标志瘊子                      吸烟--吸水烟袋  吃饭
        //儿子:脸上标志刀疤   红头发      吸烟--吸华子      吃饭   玩游戏
        //把儿子伪装成父亲:::脸上是瘊子 不能有红头  吸烟--吸华子  吃饭  不能玩游戏
        System.out.println(fuzi.a);//父类继承的属性a
        System.out.println(fuzi.name);
        //System.out.println(fuzi.b);  //子类特有成员变量被隐藏
        //fuzi.nihao();                //子类特有成员方法被隐藏
        fuzi.hai();//父类继承的方法
        fuzi.show();//zi------show方法
        //把子类对象伪装成父类类型::
        //                 隐藏子类特有的成员+
        //                 隐藏子类重新定义的成员变量+
        //                 显示父类被重写定义而隐藏的成员变量
        //多态对象的特点:除了重写的方法 其他和父类对象完全相同
	}

}
class Fu{
	String name="fu-name";
	int a=1;
	void show() {System.err.println("fu--show方法");}
	void hai() {System.out.println("fu-hai方法");}
}
class Zi extends Fu{
	String name="zi----name";
	int b=1;
	void show() {System.err.println("zi------show方法");}
	void nihao() {System.out.println("子类特有方法");}
}

多态的使用(什么时候使用多态)

使用场景一:

案例:动物园:狗猫兔子 都有吃和运动功能 ,写方法实现喂所有动物

不使用多态

public class Demo03DuoTaiUse01 {
	public static void main(String[] args) {
	}
	//static void wei(Dog d)   只能喂狗
	static void wei(Dog1 d) {
		d.eat();
		d.yunDong();
	}
	static void wei(Cat1 d) {
		d.eat();
		d.yunDong();
	}
	static void wei(Rabbit1 d) {
		d.eat();
		d.yunDong();
	}
	/*不使用多态缺点:
	 *    1 代码复用性差:需要为每种动物都写一个wei方法
	 *    2 模块之间的耦合度高:饲养员类与dog/cat/rabbit类 关联紧密
	 *    3 扩展性差:如果有新的动物   需要更改饲养员类
	 * */
}
class Dog1{
	private String name;
	Dog1(String name){this.name=name;}
	void eat() {System.out.println("狗:开始吃骨头!!");}
	void yunDong() {System.out.println("狗:吃饱抓老鼠");}
}
class Cat1{
	private String name;
	Cat1(String name){this.name=name;}
	void eat() {System.out.println("猫:开始吃鱼!!");}
	void yunDong() {System.out.println("猫:吃饱晒太阳");}
}
class Rabbit1{
	private String name;
	Rabbit1(String name){this.name=name;}
	void eat() {System.out.println("兔子:开始吃胡萝卜!!");}
	void yunDong() {System.out.println("兔子:吃饱了挖洞");}
}

使用多态

public class Demo03DuoTaiUse02 {

	public static void main(String[] args) {
		Dog2  d=new Dog2("二哈");
		wei(d);//等价于Animal2 a=d;  多态
		Cat2 c=new Cat2("波斯猫");
		wei(c);

	}
	//4 定义方法时 参数列表定义为父类类型  此方法就可以接受所有子类类型的对象
	static void wei(Animal2 a) {
		a.eat();
		a.yunDong();
	}
	/*
	 * 使用多态场景1:定义方法时 参数列表定义为父类类型  这样就可以传递任意子类类型的对象
	 * 好处:
	 *    1 代码复用性强:所有animal的子类都可以使用wei(Animal2 a) 方法
	 *    2 降低模块之间的耦合度:饲养员类只与Animal2类 关联
	 *    3 提高程序的扩展性:如果有新的动物 不需要更改饲养员类  只要新动物继承Animal2类即可 使用wei方法
	 * */
}
//1  创建父类:抽取所有子类的共同属性和功能
abstract class Animal2{
	//信息不完整  eat功能的方法体无法实现
	abstract void eat() ;
	abstract void yunDong() ;
}
//2 所有子类继承父类
class Dog2  extends Animal2{
	private String name;
	Dog2(String name){this.name=name;}
	//3 根据子类需求实现所有的抽象方法
	void eat() {System.out.println("狗:"+name+"开始吃骨头!!");}
	//3 根据子类需求实现所有的抽象方法
	void yunDong() {System.out.println("狗:"+name+"吃饱抓老鼠");}
}
class Cat2 extends Animal2{
	private String name;
	Cat2(String name){this.name=name;}
	void eat() {System.out.println("猫:"+name+"开始吃鱼!!");}
	void yunDong() {System.out.println("猫:"+name+"吃饱晒太阳");}
}
class Rabbit2 extends Animal2{
	private String name;
	Rabbit2(String name){this.name=name;}
	void eat() {System.out.println("兔子:"+name+"开始吃胡萝卜!!");}
	void yunDong() {System.out.println("兔子:"+name+"吃饱了挖洞");}
}

总结:定义方参数列表时 定义为父类类型 就可以传递任意子类类型的对象

使用场景二:

案例:定义一个台灯类:Lamp: 有方法on 可以开启灯泡的发亮功能,灯泡有红灯泡和绿灯泡

不使用多态

public class Demo04DuoTaiUse01 {

	public static void main(String[] args) {
		RedBulb r=new RedBulb("红灯1号");
		GreenBulb g=new GreenBulb("绿灯1号");
		
		Lamp lamp=new Lamp();
		lamp.red=r;
		lamp.on();
		lamp.green=g;
		lamp.on();
	}
}
/*不使用多态缺点:
  1 代码复用性差:需要在台灯类中为每种灯泡定义属性
 *2 模块之间的耦合度高:台灯类中直接关联了所有的灯泡类型
 *3 程序的扩展性差:如果有新的灯泡  需要在lamp中添加新的属性 并且还需要修改on方法 
 * */
class RedBulb{
	private String name;
	public RedBulb(String name) {
		this.name = name;
	}
	void shine() {System.out.println("红灯泡:"+name+"正在发亮!!!红光 红光");}
}
class GreenBulb{
	private String name;
	public GreenBulb(String name) {
		this.name = name;
	}
	void shine() {System.out.println("绿灯泡:"+name+"正在发亮!!!绿光 绿光 绿光 绿光 绿光 绿光 绿光");}
}
class Lamp{
	//灯泡是台灯一部分:定义两个属性来分别接受给当前台灯关联的灯泡对象
	RedBulb red;
	GreenBulb green;
	void on() {
		if(red!=null) {red.shine();}
		if(green!=null) {green.shine();}
	}
}

使用多态

public class Demo04DuoTaiUse02 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		RedBulb2 r=new RedBulb2("红灯1号");
		GreenBulb2 g=new GreenBulb2("绿灯1号");
		Lamp2 l=new Lamp2();
		l.b=r;//等价于:Bulb2 b=new RedBulb2("红灯1号"); //多态
		l.on();
		l.b=g;//等价于:Bulb2 b=new GreenBulb2("绿灯1号");//多态
		l.on();
	    
	}
	//多态使用场景2:定义类的成员变量时  定义为父类类型 这样就可以赋值任意子类类型的对象
}
//1 创建父类:提取所有子类的共同方法和属性来形成父类
abstract class Bulb2{
     String name;
	public Bulb2(String name) {
		this.name = name;
	}
	abstract void shine();
}
//2 所有子类继承父类
class RedBulb2 extends Bulb2{
	
	public RedBulb2(String name) {
		super(name);
	}
	//3 根据子类需求 实现父类的抽象方法
	void shine() {System.out.println("红灯泡:"+name+"正在发亮!!!红光 红光 红光 红光");}
}
class GreenBulb2 extends Bulb2{
	public GreenBulb2(String name) {
		super(name);
	}
	void shine() {System.out.println("绿灯泡:"+name+"正在发亮!!!绿光 绿光 绿光 绿光 绿光 绿光 绿光");}
}
class Lamp2{
	//4 定义成员变量时:如果定义为具体的子类类型  就只能接受一种子类类型的对象
	//                需要定义为父类类型
	Bulb2 b;
	void on() {
		if(b!=null) {b.shine();}
	}
}

多态使用场景2:定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象

使用场景三

案例:三个类型:Circle rect square 都有自己的属性和求周长求面积方法
写方法 参数是int n;n>0 返回一个正方形, n<0 返回一个长方形, n==0 返回一个圆形

只能通过多态来实现

public class Demo05DuoTaiUse {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Shape2 s=getShape(1);//多态

	}
    //返回的对象是三种类型  返回值类型只能声明为父类类型
	public static  Shape2   getShape(int n) {
		if(n==0) return new Circle2(1);
		if(n>0) return new Square2(1);
		return new Rect2(3, 1);
	}
}
abstract class Shape2{
	abstract double qiuZC();
	abstract double qiuMJ();
}
class Circle2 extends Shape2{
	
	public Circle2(double r) {this.r = r;}
	double r;
	final double PI=3.14;
	double qiuZC() {return 2*PI*r;}
	double qiuMJ() {return r*PI*r;}
}
class Rect2 extends Shape2{
	double chang,kuan;
	
	public Rect2(double chang, double kuan) {
		this.chang = chang;this.kuan = kuan;
	}
	double qiuZC() {return 2*(chang+kuan);}
	double qiuMJ() {return chang*kuan;}
}
class Square2 extends Shape2{
	double bianChang;
	
	public Square2(double bianChang) {
		this.bianChang = bianChang;
	}
	double qiuZC() {return 4*bianChang;}
	double qiuMJ() {return bianChang*bianChang;}
}

使用场景3:定义方法返回值类型时 定义为父类类型 这样就可以返回任意子类类型的对象

使用场景四:

案例:三个类型:Circle rect square 都有自己的属性和求周长求面积方法
创建一个数组 装2个圆 2个长方形 2个正方形

只能通过多态实现


public class Demo06DuoTaiUse {
	public static void main(String[] args) {
		//定义数组前先明确:元素类型+元素个数
        //元素类型只能定义为父类类型---元素是三种类型
		//元素个数---6
		Shape3[]  arr=new Shape3[6];
		arr[0]=new Square3(1);//多态
		arr[1]=new Circle3(2);
		arr[2]=new Rect3(3, 1);
		arr[3]=new Square3(11);
		arr[4]=new Circle3(21);
		arr[5]=new Rect3(31, 11);
		for (int i = 0; i < arr.length; i++) {
			Shape3 s=arr[i];
			System.out.println("周长:"+s.qiuZC());
			System.out.println("面积:"+s.qiuMJ());
		}
	}
	

}
abstract class Shape3{
	abstract double qiuZC();
	abstract double qiuMJ();
}
class Circle3 extends Shape3{
	
	public Circle3(double r) {this.r = r;}
	double r;
	final double PI=3.14;
	double qiuZC() {return 2*PI*r;}
	double qiuMJ() {return r*PI*r;}
}
class Rect3 extends Shape3{
	double chang,kuan;
	
	public Rect3(double chang, double kuan) {
		this.chang = chang;this.kuan = kuan;
	}
	double qiuZC() {return 2*(chang+kuan);}
	double qiuMJ() {return chang*kuan;}
}
class Square3 extends Shape3{
	double bianChang;
	
	public Square3(double bianChang) {
		this.bianChang = bianChang;
	}
	double qiuZC() {return 4*bianChang;}
	double qiuMJ() {return bianChang*bianChang;}
}

使用创建4:定义数组元素类型时 定义为父类类型 这样就可以装任意子类类型的对象

总结

/*
     * 使用创建1:定义方法参数列表时 定义为父类类型 这样就可以传递任意子类类型的对象
     * 使用创建2:定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象
     * 使用创建3:定义方法返回值类型时 定义为父类类型 这样就可以返回任意子类类型的对象
     * 使用创建4:定义数组元素类型时 定义为父类类型 这样就可以装任意子类类型的对象
     * 
     * 什么是多态:给子类对象起个父类类型的名字
     * 多态对象有什么特点:除了重写的方法 其他和父类对象完全相同
     * 什么时候使用多态:
     * 总而言之:定义方法参数列表、方法返回值类型、类的成员变量、数组元素类型时 都定义为父类类
               型,这样就可以传递、返回、赋值、装任意子类类型的对象
     * 
     * */

向上转型

把子类对象伪装成父类类型

给子类对象起个父类类型的引用

多态前提:

​ 继承:子类和父类定义关联关系

​ 向上转型:父类引用指向子类对象

​ 重写:多态对象除了重写的方法 其他和父类对象完全相同

多态内存图

在这里插入图片描述

package

package com.zut.oop;
public class Demo01Package {
    /*
     * package:包
     * 
     * 作用:对项目的资源进行分类  类似于文件夹
       命名:域名倒写
     * 注意:1 package声明必须是源文件的第一个语句
     *      2 常用的基础类库的包:
     *           io--流
     *           sql--数据库
     *           text---文本
     *           net---网络
     *           lang---最基础的包
     *           util---工具类包
     *           math---数学运算
     *     3 类的全称:包名.类名
     *           不加包名 默认是本包
     * */
	public static void main(String[] args) {
		Demo01Package  dp;
		com.zhiyou100.day04_oop.Demo01Package  dp2;
	}
}

Interface

  /* 抽象类:不是用于创建对象  而是为子类的创建定义规范
     * 概念:当一个类的所有方法都是抽象方法时---接口
     * interface: 为实现类定义规范
     *            和抽象类的使用完全相同
     * 接口关键字:interface
     * 特点:1 接口中的成员变量默认修饰符:public static final
     *     2 接口中的方法默认修饰符:public abstract
     *     3 类"继承"接口--类实现接口
     *       此类称之为接口的实现类  使用关键字implements
     *       格式:class 实现类 implements 接口{}           
     *     4 java支持一个实现类可以同时实现多个接口  同时不影响继承父类
     *           class Demo04Zi1 extends Fu4 implements TestInterface,TestInte1
     *     5 接口没有构造方法
     *     6 接口的实现类需要实现所有的抽象方法 否则是抽象类
     *     7 接口的作用:定义引用(指向的是实现类对象---多态)+为实现类定义规范 
     *     8 接口与接口之间是多继承关系
     *           interface TestInte3 extends TestInte1,TestInte2
     *           
     * 接口和类的关系
     *            关系                     关键字                        案例
     * 类与类之间         单继承              extends    class Zi extends Fu{}
     * 类与接口之间     多实现           implements  class Zi implements Inte1,Inte2{}
     * 接口与接口之间  多继承            extends     interface InteZi extends Inte2,Inte3{}
     * 
     *       
     * 
     * */

package com.zhiyou100.day04_oop;

public class Demo04Interface   {
    /* 抽象类:不是用于创建对象  而是为子类的创建定义规范

概念:当一个类的所有方法都是抽象方法时---接口
 interface: 为实现类定义规范

和抽象类的使用完全相同

接口关键字:interface
 特点:1 接口中的成员变量默认修饰符:public static final

2 接口中的方法默认修饰符:public abstract

3 类"继承"接口--类实现接口

此类称之为接口的实现类  使用关键字implements

格式:class 实现类 implements 接口{}           

4 java支持一个实现类可以同时实现多个接口  同时不影响继承父类

class Demo04Zi1 extends Fu4 implements TestInterface,TestInte1

5 接口没有构造方法

6 接口的实现类需要实现所有的抽象方法 否则是抽象类

7 接口的作用:定义引用(指向的是实现类对象---多态)+为实现类定义规范 

8 接口与接口之间是多继承关系

interface TestInte3 extends TestInte1,TestInte2

接口和类的关系
            关系                     关键字                        案例

类与类之间         单继承              extends    class Zi extends Fu{}
 类与接口之间     多实现           implements  class Zi implements Inte1,Inte2{}

接口与接口之间  多继承            extends     interface InteZi extends Inte2,Inte3{}

 */
public static void main(String[] args) {
System.out.println(TestInterface.a);

}
}
class Demo04Zi1 extends Fu4 implements TestInterface,TestInte1{
	public void hai() {}
	public void nihao() {}
}
interface TestInte1{
	int a=1;
	void nihao();
}
interface TestInte2{
	int b=1;
	void hai();
}
interface TestInte3 extends TestInte1,TestInte2{
//	int a=1;
//	void nihao();
//	int b=1;
//	void hai();
}
class Fu4{}

抽象类和接口的区别

抽象类和接口的区别
概念:抽象类:abstract class
接口:interface
相同之处:
1 都可以抽象方法
2 都只能定义引用 不能创建对象
3 存在的意义都是为子类/实现类的创建定义规范
不同之处:
1 抽象类中可以没有抽象方法
接口中的方法默认修饰符:public abstract
2 抽象类是类有构造方法
接口没有构造方法
3 接口中的属性默认修饰符:public static final 不能有实例成员变量
4 子类继承抽象类只能单继承 使用关键字extends
实现类可以同时实现多个接口 使用关键字implements
接口之间是多继承关系 使用关键字extends

import

在java源文件中引入其他包的类

package com.zut.oop;

import com.zut.oop_fuxi.Demo01Abstract;
//当前文件中com.zut.oop_fuxi.Demo01Abstract可以简写为Demo01Abstract
//所有java源文件默认引入包:java.lang
public class Demo02Import {

	public static void main(String[] args) {
		Demo01Package  pd;//提到的类 不加包名 默认是本包
		com.zut.oop.Demo01Package  pd2;
		
		com.zut.oop_fuxi.Demo01Abstract dba11
            =new com.zut.oop_fuxi.Demo01Abstract();
		com.zut.oop_fuxi.Demo01Abstract dba12
            =new com.zut.oop_fuxi.Demo01Abstract();
		com.zut.oop_fuxi.Demo01Abstract dba13
            =new com.zut.oop_fuxi.Demo01Abstract();
		Demo01Abstract dba14=new Demo01Abstract();
		
		java.lang.String s;
	}
}

instanceof


public class Demo03Instanceof {
    /*
     * instanceof 关键字:运算符
     *      判断对象的具体类型:
     * */
	public static void main(String[] args) {
		Animal[] array=getArr();
		for (int i = 0; i < array.length; i++) {
			Animal a=array[i];//使用者只能把元素作为父类类型来使用
			a.eat();
			//获取子类特有的成员::::
			//需要把:伪装成父类类型的多态对象打回本来的子类类型---向下转换
			if(a instanceof Cat) {//判断多态对象的本质类型
				Cat c=(Cat)a;//向下转型格式: 子类类型引用=(子类类型)多态对象;
				c.saiTaiYang();
			}
			if(a instanceof Dog) {//在向下转型前 必须通过instanceof 判断多态对象的具体类型
				Dog d=(Dog)a;
				d.zhuoLaoShu();
			}
//			Cat c=(Cat)a;//向下转型   //ClassCastException
//			c.saiTaiYang();
		}
		
		
		
		Animal a=new Animal("动物1");
		Cat c=new Cat("cat1");
		Animal a1=c;//通过a1访问 就是多态对象 通过c访问就是子类对象
		System.out.println("a1 instanceof Animal  ="+(a1 instanceof Animal));//true
		System.out.println("a1 instanceof Dog  ="+(a1 instanceof Dog));//false
		System.out.println("a1 instanceof Cat  ="+(a1 instanceof Cat));//true

	}
	public static Animal[]  getArr() {
		 Animal[]  arr=new  Animal[6];
		 arr[0]=new Animal("动物1号");
		 arr[1]=new Cat("波斯猫");
		 arr[2]=new Dog("二哈");
		 arr[3]=new Animal("动物2号");
		 arr[4]=new Cat("大脸猫");
		 arr[5]=new Dog("大黄");
		 return arr;
		 
	}

}
class Animal{
	String name;
	public Animal(String name) {this.name=name;}
	void eat() {System.out.println(name+"动物--食草动物+食肉动物");}
}
class Cat extends Animal{
	public Cat(String name) {super(name);}
	void eat() {
		System.out.println(name+"猫吃鱼!");
	}
	void saiTaiYang(){
		System.out.println(name+"猫在晒太阳!");
	}
}
class Dog extends Animal{
	public Dog(String name) {super(name);}
	void eat() {
		System.out.println(name+"狗吃骨头!");
	}
	void zhuoLaoShu(){
		System.out.println(name+"狗在捉老鼠!");
	}
}






			a.eat();
			//获取子类特有的成员::::
			//需要把:伪装成父类类型的多态对象打回本来的子类类型---向下转换
			if(a instanceof Cat) {//判断多态对象的本质类型
				Cat c=(Cat)a;//向下转型格式: 子类类型引用=(子类类型)多态对象;
				c.saiTaiYang();
			}
			if(a instanceof Dog) {//在向下转型前 必须通过instanceof 判断多态对象的具体类型
				Dog d=(Dog)a;
				d.zhuoLaoShu();
			}
//			Cat c=(Cat)a;//向下转型   //ClassCastException
//			c.saiTaiYang();
		}
		
		
		
		Animal a=new Animal("动物1");
		Cat c=new Cat("cat1");
		Animal a1=c;//通过a1访问 就是多态对象 通过c访问就是子类对象
		System.out.println("a1 instanceof Animal  ="+(a1 instanceof Animal));//true
		System.out.println("a1 instanceof Dog  ="+(a1 instanceof Dog));//false
		System.out.println("a1 instanceof Cat  ="+(a1 instanceof Cat));//true

	}
	public static Animal[]  getArr() {
		 Animal[]  arr=new  Animal[6];
		 arr[0]=new Animal("动物1号");
		 arr[1]=new Cat("波斯猫");
		 arr[2]=new Dog("二哈");
		 arr[3]=new Animal("动物2号");
		 arr[4]=new Cat("大脸猫");
		 arr[5]=new Dog("大黄");
		 return arr;	 
	}
}
class Animal{
	String name;
	public Animal(String name) {this.name=name;}
	void eat() {System.out.println(name+"动物--食草动物+食肉动物");}
}
class Cat extends Animal{
	public Cat(String name) {super(name);}
	void eat() {
		System.out.println(name+"猫吃鱼!");
	}
	void saiTaiYang(){
		System.out.println(name+"猫在晒太阳!");
	}
}
class Dog extends Animal{
	public Dog(String name) {super(name);}
	void eat() {
		System.out.println(name+"狗吃骨头!");
	}
	void zhuoLaoShu(){
		System.out.println(name+"狗在捉老鼠!");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值