Java面向对象

面向对象

就是凡是都是靠别人来完成的自己不用亲力亲为就可以达到目的。

面向过程和面向对象不一定都是互斥的,但可以全部面向过程不能全部面向对象(所有的事情自己亲历亲为也是可以的,我们之前写的所有代码都是面向过程。)

例如:让女朋友做饭 你这个角度而言 面向对象(自己不用做,指挥别人就可以)
从女朋友这个角度而言呢?如果做 面向过程;如果GF不做 叫外卖 面向对象
从餐馆这个角度而言呢?应该是要做饭 面向过程;如果餐馆不做 可以叫别家餐馆做
.....别的餐馆都不做 这个饭始终没人做 相互踢皮球

从中可以看出什么 这个事最终要被处理-面向过程

面向过程其实是最基本的思路 而面向对象是基于面向过程的思路

对象与类

面向对象的好处

可以仿真模拟现实生活中的事物、可以实现更加复杂的业务逻辑。

如:淘宝在买东西的时候 查看商品->付款->生成订单->物流信息。

 在面向对象的思想里面
        p1=创建一个Point对象并且制定x=1,y=2
        p2=创建一个Point对象并且指定x=3,y=4
        p1.x p1.y
        p1.getDistance(p2) 让p1自己去和p2之间计算距离
        好处在于将数据和操作统一起来了
        意味着将点拟人化 该事物的数据和操作就可以统一起来了 

对象

就是真实存在的且具体事物就称之为对象。

类相当于大楼设计图纸、对象就是由该图纸所建成的大楼。

类就是用于描述事物的
    类主要描述事物的那些方面呢?
      属性-数据-成员变量
      行为-函数-成员函数 

 

 比如我们要描述一个坐标
        属性 x y
        行为 getDistance()

class Point{
    double x;
    double y;

    public double getDistance(Point other){
        ...
    }
}

也就是说,这个事物本身自带的属性,后来培养的行为。

注意*:一个类一个.java文件,可以方便我们的管理,也就意味着当我们创建一个类的时候,其实特就定义了一个数据类型。

对象就是由一个类所描述的内容从而产生一个具体的事物。

在我们创建对象时需要用new关键字。

 格式为:类名/数据类型   变量名    =   new   类名()

访问对象中的成员的格式为:变量名.成员 

对象的内存图解

1.在堆内存中开辟一个空间并分配地址

2.按照类的描述,在该空间中定义成员变量并且有默认初始化值

3.加载成员函数进入方法区(只加载一次)
4.对象创建完毕,将空间地址赋值给相应的变量
5. 变量(p1/ p2)调用成员变量

     先通过该变量所存储的地址去堆空间中找,然后在该空间中找相应的成员变量。

 6.变量(p1/p2)调用成员函数
        直接去方法区中找该成员函数
        将该函数加载进栈内存开始运行
        为了方便区分哪个对象调用的该成员函数
        由this这个关键字段 来区分 this主要存的是当前对象的地址
        注意:当成员函数在操作变量的时候 
            先在当前函数的空间里找 局部变量
            如果没有找到,再去this所指向的堆内存中对象所属空间里去找 

class Test02{
    /*
    定义一个解决一元二次方程的类
        数据 
            a,b,c,delt
        行为
            isSolved() 判断是否有解
            getRoot1() 获取第一个解
            getRoot2() 获取第二个解
    QuadrationEquation
    */
    public static void main(String[] args){
        QuadrationEquation qe=new QuadrationEquation();
        qe.a=10;
        qe.b=50;
        qe.c=5;
        System.out.println(qe.isSovled());
        System.out.println(qe.getRoot1());
        System.out.println(qe.getRoot2());
    }
}

 

class Test03{
    /* 
    点类Point
        数据 x横坐标 y纵坐标
        行为 getDistance(Point other) 返回当前点和传入点other之间的距离

    三角形类Triangle
        数据 Point p1,p2,p3
        行为 getArea() 返回当前三角形的面积
             getLength() 返回当前三角形的周长
    */
    public static void main(String[] args){
        Triangle t=new Triangle();
        Point p1=new Point();
        p1.x=0;
        p1.y=10;
        Point p2=new Point();
        p2.x=0;
        p2.y=0;
        Point p3=new Point();
        p3.x=10;
        p3.y=0;
        t.p1=p1;
        t.p2=p2;
        t.p3=p3;
        System.out.println(t.getLength());
        System.out.println(t.getArea());
    }
}
class Test01{
    public static void main(String[] args){
        Point p1=new Point();
        Point p2=new Point();
        p1.x=10;
        p1.y=20;
        p2.x=30;
        p2.y=40;
        System.out.println(p1.getDistance(p2));
        System.out.println(p2.getDistance(p1));
    }
}

 封装与private关键字

private关键字就是一个权限关键字。(public、protected默认不写)

private关键字表示私有权限,该成员变量或成员函数只能够在类中被访问,外界不可访问。

    我们可以通过对象直接修改对象中的成员变量
    弊端:如果赋予了一个错误的值 那么势必回导致程序后期的运行结果
    就是说我们对象的成员变量并不是完全需要向外界可访问的
    如果能够被外界访问 那么势必也能被外界修改

 class Person{
        int age;
    }
    Person p=new Person();
    System.out.println(p.age);  //只是访问并打印
    p.age=-10;  //不符合现实业务逻辑 给出的是一个错误的数据

我们防范外界直接修改的成员变量,private私有化关键字

 成员变量加了private的话 修改不行了 获取也不行了

 此时就死局了~ 不能保证后期对成员变量不进行修改或获取

setter是Java当中的修改器,主要修改成员变量

本身就是一个成员函数,命名一般为:setXxx  、setAge   、setName

getter是Java中的访问器,主要访问成员变量(返回成员变量) getter看需求

   *********建议:今后的代码中 成员变量一律私有 然后再去设置访问器和修改器
   ******** 注意:如果成员变量和局部变量重名了 如何区分呢?只需要在成员变量之前加this.即可 

面向对象的三大特征:封装、继承、多态。

封装:从字面意义上来看 封装就是将一些杂七杂八的东西进行统一的管理
    最大的好处就是节约代码 方便管理 降低耦合性

在代码中有什么体现:
    循环:主要解决有规律且重复性执行的代码
    函数:主要解决具有独立功能的一段代码 后期进行复用即可
    数组:主要解决多种同类型数据的操作 统一操作 方便类管理
    类:主要将数据和行为进行统一方便操作 仿真现实中的事物

成员变量与局部变量的区别

存储位置

局部变量存储在栈内存中函数所属的空间里

成员变量存储在堆内存中对象所属的空间里

生命周期

局部变量随着函数的进栈而存在,随着函数的弹栈而消亡

成员变量随着对象的创建而存在,随着对象的销毁而消亡

访问范围

局部变量的访问范围仅仅在函数中

成员变量的访问范围在当前类中

初始化值

局部变量必须先进行初始化值,之后才能被调用。

成员变量在创建时有默认初始化值。

构造函数

我们只能将对象创建完毕之后,再进行对成员变量的赋值。

有些对象创建之前成员变量就有值(不含默认初始化)
 有些对象创建之后成员变量才有值

 

构造函数的主要作用:在创建对象之时对成员变量进行赋值操作
    构造函数的格式:
    权限修饰符 函数名(参数列表){
        函数体;
    }
    对比和之前学过的函数来说 
    构造函数
        没有函数类型关键字 :
        没有返回值类型(并不意味着没有return)
        函数名必须是类名
    但凡创建一个对象 构造函数就执行一次
    问题:我们之前并没有写构造函数
            如果类中没有定义任何构造函数的情况下,则会有一个默认无参的构造函数
            public ClassName(){}
            如果类中有明显定义的构造函数 则默认无参的构造函数不存在了
        所以 一般而言 我们最好将那个无参的构造函数写出来!!!!!!!
    成员变量的赋值其实经历了三个阶段
        默认初始化-    显式初始化  -      针对性初始化
                  类中成员变量被赋值        构造函数

 

6.7 对象的内存图解II


    1.在堆内存中开辟一个空间并分配地址
    2.对成员变量进行【默认初始化】
    3.相应的构造函数进栈 刚开始就对成员变量进行【显式初始化】
    4.接着再去执行构造函数中的内容【针对性初始化】
    5.构造函数执行完毕 弹栈 将对象的地址赋值给相应变量即可

class Person{
    private String name="小明"; //每一个Person对象创建之前都叫小明
    private int age=5;      //每一个Person对象创建之前都是5岁
    //private int wheelNum=4; //轮胎的个数
    
    /* 
    隐藏默认的
    public Person(){

    }
    */
    public Person(){    //无名 无年龄
        System.out.println("姓名:"+this.name+",年龄:"+this.age);
    }
    public Person(int age){//无名 有年龄
        this.age=age;
        System.out.println("姓名:"+this.name+",年龄:"+this.age);
    }
    public Person(String name,int age){ //有名 有年龄
        this.name=name;
        this.age=age;
        System.out.println("姓名:"+this.name+",年龄:"+this.age);
    }
    void show(){
        System.out.println("今年"+age+"岁");
    }
    public void setAge(int age){
        if(age<0||age>150){     //局部变量age
            this.age=0;          //成员变量age
        }else{
            this.age=age;        //左边成员 右边局部
        }
    }
    public int getAge(){
        return age;
    }
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return this.name;
    }
}
class Point{
    private double x;
    private double y;
    public Point(){

    }
    public Point(double x,double y){
        this.x=x;
        this.y=y;
    }
    public double getDistance(Point other){
        return Math.hypot(x-other.x,y-other.y);
    }
    public void setX(double x){
        this.x=x;
    }
    public void setY(double y){
        this.y=y;
    }
    public double getX(){
        return this.x;
    }
    public double getY(){
        return this.y;
    }
}
/** 
仿照Java自带的String类 写一个自己的MyString类,
基本支持String中大部分的功能。
其实String的本质就是一个一维的字符数组,然后再加上其相关的操作
数组的长度一旦确定 则不可更改;
String的长度一旦确定 也不可更改;
更重要的是,String的内容一旦确定 也不可更改;
String是一个不可变对象 意味着我们不能在原地修改String的内容 只能重新创建一份进行修改。
@author HENG
@version 1.0
*/
class MyString{
    private char[] value;
    /**
    创建一个空串"",也就是说字符串长度为0
    */
    public MyString(){
        this.value=new char[0];
    }
    /**
    创建一个由指定字符编码组成的字符串
    */
    public MyString(byte[] bytes){
        this.value=new char[bytes.length];
        for(int i=0;i<value.length;i++){
            value[i]=(char)bytes[i];
        }
    }
    /**
    创建一个由指定字符组成的字符串
    */
    public MyString(char[] value){
        this.value=new char[value.length];
        for(int i=0;i<value.length;i++){
            this.value[i]=value[i];
        }
    }
    public char charAt(int index){
        if(index<0||index>=value.length){
            System.out.println(">>>角标越界"+index);
            return (char)-1;
        }
        return value[index];
    }
    public int indexOf(int ch){
        for(int i=0;i<value.length;i++){
            if(value[i]==ch){
                return i;
            }
        }
        return -1;
    }
    public int length(){
        return value.length;
    }
    //比较两个字符串之间的大小
    //两个字符数组从左到右挨个比较元素 如果出现第一个不相等的元素 返回差值即可
    //如果某一个数组遍历完了也没有发现不相等的 返回长度的差值即可
    public int compareTo(MyString other){
        int min=Math.min(length(),other.length());
        for(int i=0;i<min;i++){
            if(value[i]!=other.value[i]){
                return value[i]-other.value[i];
            }
        }
        return length()-other.length();
    }
    public boolean contains(MyString other){
        char[] c1=value;
        char[] c2=other.value;
        if(c2.length>c1.length){
            return false;
        }
        for(int i=0;i<c1.length;i++){
            boolean flag=true;
            for(int j=0;j<c2.length;j++){
                if(c2[j]!=c1[i+j]){
                    flag=false;
                    break;
                }
            }
            if(flag){
                return true;
            }
        }
        return false;
    }
}
/**
Stack是一个简单的由一维数组实现的栈结构
支持入栈出栈等常见操作,但不支持动态扩容操作
为了方便简化代码,默认此Stack中只能存储int型数据
@author HENG
@version 1.0
*/
public class Stack{
    private int[] data; // 容器 用于存储栈元素 data.length表示栈的最大容量
    private int top=-1;    // 栈顶标记 用于标记栈顶元素的位置 当栈为空时 top=-1 栈中有效元素的个数top+1
    private int capacity=10;    //默认最大容量为10
    /**
    创建一个默认容量为10的栈
    */
    public Stack(){
        this(capacity);
    }
    /**
    创建一个指定容量为capacity的栈
    @param capacity 由调用者传入的指定容量
                    如果capacity<0 则容量置为0
                    如果capacity>100 则容量置为100 
    */
    public Stack(int capacity){
        if(capacity<0){
            capacity=0;
        }
        if(capacity>100){
            capacity=100;
        }
        this.data=new int[capacity];
    }
    /**
    将元素e入栈,如果栈当前已满,则无法加入
    @param e 用户指定入栈的元素
    */
    public void push(int e){
        if(size()==data.length){
            System.out.println(">>>栈已满,无法添加元素"+e);
            return;
        }
        data[++top]=e;
    }
    /**
    从栈中弹出一个元素,如果栈已经是空,则返回-1即可(没有学异常 -1表示错误)
    @return 返回当前栈顶的元素,如果栈为空则返回-1
    */
    public int pop(){
        if(isEmpty()){
            System.out.println(">>>栈为空,无法弹栈元素");
            return -1;
        }
        return data[top--];
    }
    /** 
    获取当前栈顶元素(不出栈),如果栈已经是空,则返回-1即可
    @return 返回当前栈顶的元素,如果栈为空则返回-1
    */
    public int peek(){
        if(isEmpty()){
            System.out.println(">>>栈为空,无法获取栈顶元素");
            return -1;
        }
        return data[top];
    }
    /**
    判断当前栈是否为空
    @return true表示栈空 否则栈不为空
    */
    public boolean isEmpty(){
        return top==-1;
    }
    /**
    清空当前的栈
    */
    public void clear(){
        top=-1;
    }
    /**
    获取栈中有效元素的个数
    */
    public int size(){
        return top+1;
    }
    /**
    返回栈的字符串表现形式
    */
    public String toString(){
        if(isEmpty()){
            return "[]";
        }
        String s="[";
        for(int i=0;i<size();i++){
            s+=data[i];
            if(i==size()-1){
                s+="]";
            }else{
                s+=",";
            }
        }
        return s;
    }
}
//需求:实现一个简单的栈结构Stack
class Test01{
    public static void main(String[] args){
        Stack stack=new Stack(20);
        for(int e=1;e<=20;e++){
            stack.push(e);
        }
        stack.push(21);
        System.out.println(stack.size());
        System.out.println(stack.toString());
        System.out.println(stack.peek());
        System.out.println(stack.pop());
        System.out.println(stack.toString());
        System.out.println(stack.isEmpty());
        stack.clear();
        System.out.println(stack.toString());
        System.out.println(stack.pop());
    }
}
class Test02{
    public static void main(String[] args){
        Demo d1=new Demo();
        Demo d2=new Demo(10);
        Demo d3=new Demo(10,20);
        Demo d4=new Demo(10,20,30);
    }
}
class Demo{
    int a;
    int b;
    int c;
    public Demo(){
        this(0,0,0);
        //Demo(0,0,0);//这种调用方式 其实是把Demo(...)当成成员函数去调用了
    }
    public Demo(int a){
        this(a,0,0);//Demo(a,0,0);
    }
    public Demo(int a,int b){
        this(a,b,0);//Demo(a,b,0);
    }
    public Demo(int a,int b,int c){
        this();
    }
    public void Demo(int a,int b,int c){

    }
    public void show(){
        System.out.println(a+","+b+","+c);
    }
    private void init(){
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
        System.out.println(".....");
    }
}
//需求:模仿String自定义MyString
class Test03{
    public static void main(String[] args){
        MyString s1=new MyString(); //""
        MyString s2=new MyString(new byte[]{97,98,99});//"abc"
        MyString s3=new MyString(new char[]{'a','b','c'});//"abc"
        MyString ms1=new MyString("abcdefgh".toCharArray());
        MyString ms2=new MyString("def".toCharArray());
        System.out.println(ms1.charAt(3));//d
        System.out.println(ms1.indexOf('b'));//1
        System.out.println(ms1.length());//8
        System.out.println(ms1.compareTo(ms2));//-3
        System.out.println(ms1.contains(ms2));//true

    }
}

static关键字

1.成员变量+static=静态变量

当我们在设计类的时候发现多个对象中有共享数据的时候,我们就可以把这个共享数据定义为静态的。

name age虽然每个对象都有但是值不一样  对象特有数据->成员变量

country虽然每个对象也都有 但是值一样  对象共有的数据->静态变量

静态的东西从堆中对象的空间里抽取出来,放到了静态方法区

我们去上课 要喝水  水杯/水壶  ?特有的             饮水机 ? 共有的

上述可以知道,共有的东西存在于一个特定的空间,静态方法区

我们去上课,饮水机在公司,下课后饮水机依然在公司

上述可以说明:共有的数据要活的比对象长。 

 

 2.成员函数+static=静态函数

静态函数就i是意为着对象的共有行为吗?不是

我们当前的成员函数如果不访问任何成员变量的情况下,这个函数就可以定义为静态的。

这就意味着静态函数不能直接调用当前类中的成员变量。

因为静态的生命周期要长于对象。

所以静态是优先于对象存在的。

静态也称之为是类的成员,我们可以直接通过类去调用。

(类:静态成员。)

 

为什么主函数是静态的?

主函数是程序的入口,优于其他的运行。

假设主函数是非静态的,那么必须先创建对象才能调用主函数。

静态变量有没有初始化值?有(运行时常量  永久代JVM)

也有显示初始化

 

3.类的分类

实体类

就是为了描述一个事物 person point

类中基本内容都是成员函数/成员变量

也会存在一个静态成员

工具类

提供一些已经被实现好的功能  向外部供应。

所以工具类中基本上全都是静态函数

类.Xxx    类.Xxx()  Math Arrays

为什么工具类中都是静态的?

      1.共有的

       2.长时间存在

       3.加载一次,后期随便使用

 一个道理:
                当我们钉一个钉子的时候 找榔头
                你是造一个榔头 还是用已存在的榔头?
            如果工具类可以被创建对象 是不是就想用的时候去创建
                效率较低

主类/测试类

主要用于运行/测试代码

这个类中会有主函数的存在

实体类是可以存在主函数的,但是不推荐

工具类一般不会存在主函数。

静态函数中是否存在this这个关键字?不可能

静态变量,我们在定义的时候,一般而言这个变量是不可修改的  加上final修饰。

对象的内存图解Ⅲ

      Javac将Java源代码进行编译生成字节码文件。

      Javac将字节码文件加载进虚拟机中 ,开始运行程序。

            字节码具体被加载进方法区里面

             方法区可以分为非静态方法区和静态方法区。

              所有非静态的代码(二进制)内容加载进非静态区

             所有静态代码(二进制)内容加载进静态代码区

JVM接下来会根据参数(Java字节码文件名(类名))去静态区找主函数

将主函数代码加载进虚拟机栈进行运行

静态变量与成员变量的区别

生命周期

  成员变量随着对象的创建而创建,随着对象的消亡而消亡。

  静态变量随着类的加载而创建,随着程序结束而消失。

调用方式

  成员变量必须先创建对象再通过对象去调用

  静态变量可以被对象调用也可以直接用类调用

储存位置

   成员变量存在于堆内存中对象的所属空间里

   静态变量存在于静态方法区中类的所属空间里

命名

   成员变量-对象的特有属性

   静态变量-对象的共有属性  类成员

代码块

代码块{……}

局部代码块:存在于函数当中(包括函数)for(){……}  if(){……}

构造代码块:直接在类中出现的{……}

   当对象创建一次时,构造代码块执行一次,作用等同于构造函数

静态代码块:直接在类中出现的static{……}

   当类被加载的时候,仅仅只执行一次

   作用于对类进行一些初始化操作 JDBC

单例模式

设计模式:就是我们的前辈们总结的一些编程技巧

它并不是随着Java的诞生而诞生的

它是由Java的广大使用者总结出来的一套编程经验(常见26种)

 

单例模式:使用场景是某一个类只能创建一个对象

1.既然只能创建一个对象的话,就不能让外界去创建对象

    限制使用new是不现实的

    只能从对象的创建流程中考虑,只要有一个步骤不行,对象就创建不出来。

    开辟空间分配地址,是由计算机底层觉得的,我们是控制不了的

    构造函数执行,只需将构造函数私有化即可

2.既然外界不能创造对象,我们还是得保证对象的创建

    所以我们只能在类内部创建对象

    Single s = new Single();

    它能否写成成员变量的形式?

    所以private static

3.内部创建出对象,还是得向外界提供

    因为private外界不能直接访问

    所以见解,向外界提供一个函数,外界通过调用函数获取对象。

继承

继承的由来:当我们在定义若干个类的时候,发现某一些类中具有相同的属性和行为,那么,我们就可以将这些相同的部分进行抽取,独立生成另外一个类,那么这个生成出来的类我们称之为是父类,其他的容易被抽取内容的类称之为子类。

     子类与父类之间就是所谓的继承关系,用extends来表示

在现实生活中,父与子之间是一对多 还是多对多的关系?

在Java中,继承是单继承(一个子类只能有一个父类,但是一个父类可以有若干个子类)

但是在C++当中,继承是多继承的,不太符合实际的社会问题,所以Java更加符合现实编程

(也不代表Java当中就没有多继承的时候! 如果是类与类之间就必须是单继承;如果是接口与接口之间,可以是多继承)

既然有了继承,那么在Java当中就有了继承体系

既然有了父子关系,那么就会产生族谱这个东西

说一点:我们常用的继承体系   异常体系     集合体系      IO体系     网络体系     多线程体系

C->B->A(C就是B的儿子,A就是C的爷爷)

在Java继承体系当中,所有的类的最终父类都是Object!     (Object就不存在爸爸了)

如果我们在定义一个类的时候,没有显著声明父类的时候 南无该类的父类默认是Object

*****注意一点:在分析设计继承的时候一定要符合社会社会常识问题

     子类和父类之间必须是is a 关系  子类必须是父类的一种同一体系的

所以,千万不要为了获取某个类的功能而把这个类叫爸爸!

 

子父类中成员变量/静态变量的特点

     如果只有子类有 且非私有 那么就调用子类的

     如果只有父类有 且非私有 那么就调用父类的

     如果子父类都有 且非私有 那么久调用子类的

   (成员变量之间是不存在重写的!!!)

子类.属性 顺序 子类对象成员->子类静态->父类成员->父类静态

子类成员函数在内部调用变量时 局部变量->子类对象成员->子类静态->父类成员->父类静态

 

子父类中构造函数的特点

     现象:子类构造函数在调用运行的时候 先执行父类的构造函数

     在子类的构造函数当中,有一句默认的super(……)隐藏了,而且这句代码必须在第一行

     对super的调用必须是构造器中的第一个

     为什么?道理很简单 当儿子问老爸要钱的时候 ,老爸是需要准备一下钱的

     既然子类继承自父类 那么必然会继承到父类当中的一些数据

     所以,在子类构造函数当中,必须先让父类把这些数据进行一些初始化才能继承给子类

     *****注意:父类的构造函数被调用,但不代表父类就被创建对象了!

          所以this是当前对象的引用,而super不是父类对象的引用,而是父类空间的引用

     并且注意super(……)如果父类没有默认无参构造函数那么子类构造函数中super()失效了

     所以在调用父类构造函数时,一定要注意父类构造函数的参数情况!适时修改super(……)

 

     this(……)是当前类中 本类构造函数调用本类构造函数的方式

     super(……)是本类构造函数调用父类构造函数的方式

     都必须在第一行,那么这两者是否有冲突?

     如果本类构造函数中不存在调用关系,那么每一个本类构造函数第一句都是super(……)

     如果本类构造函数当中存在调用关系,那么最后被调用的第一句绝对就是super(……)

     this(……)的调用是单向的还是递归的?   是单向的,那么最后被调用的第一句绝对就是super(……)

   

子父类中成员函数的特点:

     如果只有子类有 且非私有 南无就调用子类的

     如果只有父类有 且非私有 那么就调用父类的

     如果子父类都有 且非私有 那么就调用子类的(函数重写)

函数重写:在子父类中,同名函数

函数由什么组成:函数声明(权限 类型 返回值类型 函数名 参数列表)+ 函数体({}里面的内容)

重写的意义在于哪?在于子类继承了父类的函数声明(功能),但是子类可以将该函数的具体实现进行优化或更改

           郭德纲会说相声 郭麒麟也会说相声

           子承父业!

     1.保留父类的功能声明 子类可以进一步优化

     2.保留父类的功能声明子类可以重新定义

重写当中应该注意到的一些细节:

1.函数重名 但是参数列表不同 不构成重写关系

2.函数重名 参数列表相同 构成重写关系 返回值类型也必须是一样的

3.子类重写父类函数时,权限>=父类权限

4.当然 如果父类权限为private 子类压根就继承不到 何谈重写

抽象类

     抽象类:模糊不清的类 不具体的类

     当我们抽取一个父类的时候,发现子类当中的一些共同方法在父类中无法进行具体的实现

     并且这些方法只能在子类中具体实现时,父类当中这些函数就只保留函数声明即可,不必写函数体

     那么此时这个函数就是抽象函数!  有抽象函数的类就是抽象类

     特点:

     1.抽象类能否创建对象?不能,对象本身是一个具体的东西 而抽象类中含有不具体的内容

     2.抽象类必须作为父类存在吗? 必须 抽象类就是等着被继承呢!

     3.抽象类和一般类有什么区别? 就是一般类的特殊情况

          唯一的区别只在于抽象类中有抽象函数!!!

     4.抽象类中必须有抽象函数吗?不一定AWT界面开发

     5.abstract这个关键字不能和那些关键字共存?

           private抽象函数就等着被子类重写实现呢!

           static 静态是优先于对象存在的,在加载静态数据的时候 肯定是具体的数据

               类名.抽象函数是很尴尬的!

               如果抽象函数是可以被静态的,那么我们还需要对象干什么?

多态

多种状态:就是指一个对象可以有多种状态(他在继承体系中的位置变化)

D->C->B->A->Animal

位置变化只能是向上变,但不能低于自身

对于C而言可以当作B来看,也可以当作A来看,也可以当作Animal

     小明     男人     人     动物

小明的学校开家长会,小明不想让他爸爸去,他让大明去 大明就是小明他哥

大名冒充爸爸去参加家长会的话,那么所表现出来的行为是不是应该符合他爸的行为呢?

不同的视觉有不同的角色

无论是在那个视觉场合,对象本身变了没有?只不过我们需要对象在不同的场合表现出相对应的行为

在Java中,多态代码表现就是父类引用指向子类对象

多态的前提:继承 重写

多态的好处:对代码的功能进行了可扩展性

     子类对象可以当作父类对象去使用,但是有限制,只能调用父类函数或重写函数

     不能使用子类特有的行为

 

多态当中 成员变量的特点:只能访问父类中的成员变量

多态当中 成员函数的特点:

     如果子类没有重写 且父类中有 调用父类的

     如果子类有重写的 调用子类重写的

     如果不存在重写 父类没有 那就报错了

 

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值