• 面向对象02


    DAY11

    • 访问权限修饰符

    访问权限修饰符的访问控制分为2个层面:

    修饰类中的成员(成员变量&成员方法)——控制类中的成员,对其他类的可见性

    修饰类——通常用来限定类库中的类(自定义数据类型),对于外部使用者的可见性

    对类中成员的访问限制,有4种:public、protected、默认权限、private(成员方法和成员变量在访问权限上是相同的)

     public

    任意类都可以访问,实际上就是没有限制访问权限

    protected

    同包中的其他类,和不同包的(可见)子类均可见

    默认权限

    同包中的其他类可见

    private

    仅对同类中的其他成员可见

    类的访问权限

    public:使类具有公共访问权限

    protected:不能用来修饰类(并非所以类)(通过子类对象可以跨包访问到)

    默认权限:只有同包中的类,能访问默认权限的类

    private:不能修饰类(并非所有类)

    • 封装

    一种信息的隐藏技术

    类
        成员变量(一定要考虑访问权限)
        构造方法
            无参构造方法
            带参构造方法
        成员方法
    // 针对private成员变量,专门定义了public的方法,让外部能够访问私有成员变量的值 getxxx()//让外部读取到私有成员变量的值 setxxx()//让外部通过该方法,修改私有成员变量的值

    为了清楚的get和set方法分别获取和改变的是哪个成员变量的值,常用命名规则:

    成员变量名字:xxx

    返回值 getxxx()

    void setxxx(修改参数目标值)

    提供get/set方法的好处:

    1. 可以满足某些场景下需要访问私有成员变量的值
    2. 通过定义get和set方法,来实现对私有成员变量的读写分离
    3. 因为,一旦一个成员变量被private修饰,别人就无法直接 对象名.访问。只能通过set(),此时我们在set方法中,就可以自己通过代码控制别人的修改

    给成员变量赋值的方式

    1.无参构造方法+setxxx()

    Student st = new Student()

    st.name = setName()

    2.带参构造方法

    • 继承

    父类(基类,超类)

    子类(派生类,导出类)

    继承的语法:class 子类名 extends 父类名{}

    不同数据类型之间“is  a”的关系

    a.一种类型(类) 继承 另外一种类型(类)

    b.从数据类型看,可以把子类类型当做父类类型

      从数据类型的角度,数据类型:一个数据集合和基于这个数据集合的一组操作

    当子类继承父类,子类拥有了父类中定义的成员(父类中的数据集和基于数据集的操作)

    继承的优点:

    1. 代码复用(方法,类)
    2. 提高了代码的可维护性(这是一把双刃剑)--通过减少了冗余代码
    3. 弱化了Java中的类型约束(可以让父类引用指向子类对象)(多态的前提之一)
    Human human = new Human();
    Student student = new Student();
    //一个子类对象就被看成了一个父类对象
    huamn = student;
    class Human{}
    class Student extends Human{}

    继承的缺点:

    父类的修改可能会出现在所有的子类当中(我们无法选择这些修改可以反应在哪些类中,不可以反应在哪些类中)

    继承的局限性:

    Java继承的特点:在Java只能实现单重继承

    单重继承:简单来说Java的extends关键字后只能跟一个

    class A{}
    class B{}
    class C extends A,B{} (x)//不能同时继承过个类
    
    //但是可以有层次的继承
    class A{}
    class B extends A{}
    class C extends B{}//c中继承了A和B

    注意事项:

    1. 子类不能继承父类的构造方法
    2. 子类只能访问父类所有非私有的成员(成员方法和成员变量)(例如有private的成员,那么能被继承,但是不能访问)

    子类对象的内存映像:

    对一个子类对象而言,其内存中的数据,分成了两部分:

    1.从父类中,继承下来的成员变量的值

    2.子类中,自己定义的成员变量的值

    在给这两部分数据赋初值时,java语言的结论是,一定是先父后子

    子类对象的初始化问题(子类中成员变量赋予初值先后顺序)

    实现先父后子的核心思路:

    1. 首先,构造方法本身的功能,就是初始化对象成员变量值的
    2. 所以,显然对我们只需要保证,父类的构造方法先于子类的构造方法运行
    3. 如何让父类构造方法,先于子类构造方法运行(在子类的构造方法的第一条语句的位置,先去调用父类)

    子类的初始化方式

    1. 子类对象的隐式初始化方式(JVM来自动保证父类构造方法先执行)
    2. 子类对象的显式初始化方式(coder通过代码的方式保证父类构造方法先执行)

     子类对象的隐式初始化:

    1.了解对象的隐式初始化

    a.当父亲提供了默认的构造函数(无参构造方法)

    b.且子类的构造方法中,没有显示调用父亲的其他构造方法

    c.则在执行了类的构造方法之前,会(JVM)自动执行父亲的构造方法(无参构造方法 )

    子类对象的显式初始化方式:

    核心问题:如何在Java语法层面,显式的调用父类的构造方法

    super关键字:super代表父类对象的引用

    如何保证先调用父类构造方法执行,后执行子类构造方法?

    只需要在子类构造方法第一条语句的位置,通过super调用父类的构造方法即可

    注意事项:

    1. 必须保证子类每个构造方法都要满足子类对象的初始化(即如果子类中有多个构造方法,每个都要保证显示初始化的执行流程)
    2. 在子类构造方法中,通过super调用,父类构造方法时,该super语句必须出现在子类构造方法的第一条语句的位置
    3. this()(调用当前类的构造方法)和super()(调用父类构造方法)都可以卸载构造方法的方法体中,他们都需要在第一条的位置,他们不能共存
    class ExplicitFather{
        int fatherI;
        public ExplicitFather(int fatherI){
            this.fatherI = fatherI;
        }
    }
    class ExplicitSon extends ExplicitFather{
        int sonI;
        public  ExplicitSon(int sonI, int fatherI){
            super(fatherI);
            this.sonI = sonI;
        }
        public ExplicitSon(){
            super(23);
        }
    }

    DAY12

    父类域的隐藏(仅仅发生在子类当中)

    1.在子类中是否可以定义和父类中同名的成员变量?————可以

    2.那么在子类中访问这个同名变量,究竟访问到的是父类对象中的值,还是子类对象中的值?——子类中定义的同名成员变量值

    如果是在父类中访问呢?——父类方法访问到的是父类中定义同名成员变量的值

    3.是否可以在子类对象中,同时访问到子类对象和父类对象中的同名成员变量的值?

    ——可以,在子类方法体中,可以通过super.关键字,访问到父类定义的同名成员变量值

    在父类子类中,如果定义了同名成员变量,记住以下结论:

    1.如果调用的是子类方法,通过变量名访问同名成员变量,访问到的就是子类中定义的同名成员变量

    2.如果调用的是父类方法,通过变量名访问同名成员变量,访问到的就是父类中定义的同名成员变量

    对于子类中的方法,在子类对象上访问成员变量值的时候,有一个查找规则:当我们在子类的方法体中,访问子类对象的成员变量值的时候

    1.首先,在子类对象中,查找子类自己,定义的成员变量中有没有目标成员变量

    2.如果找到,就直接访问

    3.如果在子类对象上,在子类自己定义的成员变量中,没找到目标变量,则会自动在父类对象上,查找目标变量值并访问

    • 方法的覆盖或重写(override)

    1.子类中能否能定义和父类方法声明一模一样的方法?——可以

    2.如果可以,那么在子类对象中访问这个一摸一样的方法,究竟访问到的是父类对象中的方法,还是子类对象中的方法?——子类中定义的方法

    如果是在父类中访问呢?——子类中定义的方法

    3.是否可以在子类对象中,同时访问到子类对象和父类中方法声明一模一样的方法呢?——可以,通过super.关键字 可以在子类中访问到父类中定义的成员方法

    当我们在子类对象上调用方法,该方法在运行时,怎么确定运行哪个方法?

    1.当方法执行的时候(如果子类方法调用了其他方法)

      优先在子类方法中找目标方法,如果子类中找到了目标方法,执行子类中定义的目标方法

    2.如果说,在子类中,没有找到目标方法,接着到父类中找目标方法,如果找到就执行父类中定义的方法

    使用场景:用来在子类中,修改父类方法的方法实现(并非真的修改父类中的方法)

    方法覆盖的条件:

    主要看的是子类和父类的方法声明部分:访问权限  返回值   方法签名(方法名+参数列表)

    1.方法声明的访问权限的条件

      并非子类和父类方法的访问权限要相同,只要子类方法的访问权限不小于父类方法的访问权限

    2.方法返回值

    1)基本数据类型的方法返回值:子类必须和父类的方法返回值类型相同

    2)引用数据类型

    a.子类父类返回值类型相同

    b.子类方法返回值类型 是 父亲方法返回值类型的 子类类型(因为可以把子类类型看做是父类类型)

    class A{}
    class B{}
    class C extends A{}//C是A的子类
    
    class Father{
        protected int testAccess(){
        System.out.println("father access");
        return 0;
    }
    public A testReferenceReturn(){
        return null;
        }
    }
    class Son extends Father{
        @Override
        public int testAccess(){
        System.out.println("son access");
        return 0;
        }        
        @Override// 测试有没有实现覆盖的注解@override
        public C testReferenceReturn(){
        return null;
        }
    }

    3.方法签名(数据类型的角度)

    子类方法的方法签名必须和父类一样

    注意事项:父类中不是所有的方法都能被子类覆盖

    1.父类中私有方法不能被重写

    2.父类中静态方法不能被重写

    3.被final修饰

    • final关键字

    final可以修饰类,变量,成员方法

    1. 修饰类,类不能被继承
    2. 修饰变量,变量就成了常量,只能赋值一次
    3. 修饰方法,方法不能被重写

    final修饰变量时分为两种情况:

    修饰局部变量:必须在使用局部变量之前,初始化一次局部变量的值,且仅一次

    修饰成员变量:(不包括jvm赋予的默认初值 )可以在定义时进行初始化,也可以选择在构造方法中初始化

    • 多态

    某一个事物,在不同时刻(或条件下)表现出的不同状态(行为), 对于成员变量没有所谓的多态

    多态实现的前提条件:

    1. 继承
    2. 方法覆盖
    3. 父类引用指向子类对象

     多态成员的访问特点

    Animal animal =  new Dog();

    成员变量:编译看左边,运行看左边(实际运行的效果,由引用变量的类型来决定)

    成员方法:编译看左边,运行看右边

    解释:

    1.编译看左边:父类引用指向子类对象,此时编译看左边是在说,通过引用变量可以访问到的子类成员的范围,是由引用类型来决定的 

    a.迄今为止,我们都是通过一个中间人即引用变量,间接访问堆上对象

    b.也就是说,只有通过引用变量,我才能访问到堆上的对象

    2.对于成员变量的运行看左边

    一个对象属性(成员变量)和行为,一个对象的属性(成员变量表示),表示了一对象的外貌在多态中,此时对于子类对象而言,把子类对象赋值给父类类型的引用,就相当于给子类对象披上了一个父类类型马甲,因此,该子类对象开起来,就是一个父类对象(外貌特征表现出的就应该是父类的外貌特征)

    3.对于成员方法的,运行(结果)看 右边(多态)

    就是说对于成员 方法而言,通过引用变量,实际访问到的行为(方法),是由引用实际指向的对象来决定的

    多态的优点:

    提高了程序的维护性(由继承保证)

    提高了程序的扩展性(由多态保证)

    多态的弊端:

    1.无法通过父类类型的引用,去访问子类特有的方法

    解决方案:引用变量的类型转换(父类和子类)

    a.子类类型的引用变量—>父类类型的引用变量(向上转型)     编译器天然允许

    b.子类类型的引用变量—>父类类型的引用变量(向下转型)     默认编译器不允许(因为一旦赋值不恰当,可能引起错误)

    对于引用变量,我们也可以强制类型转化

    子类类型 引用变量  = (子类类型)父类型的引用变量

    DAY13

    1.

    2.ClassCastException,为了成功的完成强制类型转化,必须想办法判断,animal父类引用指向的究竟是不是Duck对象

    instanceof关键字(运算符):判断目标是否是指定类型的对象   运算类型:boolean

    语法格式:对象名(对象的引用变量)  instanceof    实例类型(目标类的类名)

    引用变量:不管什么类型的 引用变量,都可以被赋值null,如果null instanceof任意一个类 ——false

    • 抽象类(abstract)

    为了让方法声明单独存在(声明有这样的行为),必须在声明中加入abstract关键字,被abstract修饰的方法叫做抽象方法

    注意:包含抽象方法的类,必须是抽象类,同时,抽象类可以不包含抽象方法

    语法:

    类:abstract class 类名{}

    public abstract void eat{};抽象方法只有方法声明,没有方法体

    特征:

    1.抽象类不能直接实例化:new 抽象类

    但是抽象类可以间接实例化

    抽象类类型 引用 = new 具体子类();

    2.抽象类的子类:

    a.可以是具体类(子类必须覆盖实现抽象父类中,所有的抽象方法)

    b.抽象类的子类可以是抽象类(当子类没有覆盖并实现,抽象父类中所有的抽象方法)

    注意事项:

    a.有抽象方法的类一定是抽象类

    b.抽象类不一定有抽象方法

    抽象类成员特点:

    构造方法:同普通类(不能实例化,为什么有构造方法?)

    成员变量:同普通类

    成员方法:可以是抽象方法(只是为了声明类中有这样的行为,而无法确定具体行为的实现),

    也可以是非抽象方法:作用是用来做一个代码复用

    抽象类不能实例化,为什么有构造方法?

    1.因为抽象类中,可以像普通类一样,定义成员变量,而这些成员变量,在创建子类对象的时候,依然是初始化

    2.在子类独享中,抽象父类中定义的成员,它们值的初始化,交给抽象父类的构造方法来完成(各司其职)

    abstract不能和以下关键字共存

    1.private不能被覆盖

    2.final不能被覆盖

    3.static不能被覆盖

    对于为什么冲突的理解:

    1.abstract定义抽象方法,对于抽象方法而言,如果在代码中要使用,其实永远是通过多态,覆盖实现的抽象父类的抽象方法

    2.而被private,final,static关键字修饰的方法,都不能在子类中被覆盖,而是意味着这些方法,无法在程序中运行

    DAY14

    • 接口

    解决类的单重继承限制

    接口的语法

    1.接口用关键字interface表示:interface 接口名{}

    2.在java语言中 interface也可以表示一种数据类型

    a.类和接口都可以用来表示数据类型(类和接口是地位对等的 ,只不过他们的侧重点不一样)

    主要从操作(行为)描述:

    b.类定义的一个数据集合基于这个数据集的一组操作(行为),类所描述的这一组行为,他们是有关系的(间接),都可以访问同一个数据集合

    c.接口表示数据类型,侧重于描述,一组具有特殊功能的行为,这些行为可以完全没有任何关系,接口中的方法,他们的关系比较松散

    3.类实现接口和implements表示

    类与类之间可以有一种关系:继承

    类和接口,可以有实现关系,实现关系用implements表示(一个类可以实现接口)

    类和接口的实现关系(类可以实现接口):实现关系其实是一种实质上的继承关系

    格式:class类名implements 接口名{}

    接口的特征:

    4.接口不能直接实例化(接口中对于方法只能有抽象方法)(jdk7以前)

    a.不能直接实例化一个接口(new接口)

    b.接口可以间接实例化

    接口类型的引用  = new 接口实现子类()

    接口的特点:

    1.无构造方法

    2.成员变量:只能是常量,修饰符public static final

    成员方法:只能是抽象方法,修饰符public abstract

    5.接口的子类

    a.可以是抽象类

    b.也可以是具体类

    Java语言实现了多重继承:

    1.接口与接口之间可以实现多重继承

    2.同时,一个类可以实现多个接口

    完整的类定义的语法

    class 类名extends 另一个类的类名 implements 接口1 ,接口2,。。。接口n{}

    抽象类和接口的比较

      抽象类 接口
    成员区别

    变量

    有抽象方法

    非抽象方法

    自定义常量(静态)

    抽象方法(jdk7以前成立)

    关系区别

    类和类——继承,单继承

    类与接口——实现,单实现(实现一个接口),多实现(实现多个接口)

    接口与接口——继承,单继承,多继承

    设计理念区别

    1.被继承体现的是is a的关系

    1)抽象类可以被其他类继承,而且子类只能extends一个类

    2)抽象类被子类继承以后,子类和抽象类的关系是is a

    2.共性的功能

    1.被实现体现的是like a的关系

    1)一个类可以同时多个接口(实现也是一种是实质上的继承关系)

    2)类实现接口之后,类和接口的关系用like a 来描述

    2.功能的扩展

    说明is a 和like a 差别:

    is a :一个子类,只能继承一个父类,继承在最理想的使用情况下,是子类不自己定义自己成员,此时在理想情况下,其实父类和子类,是完全相互替代的  父类引用/子类引用 = new 子类对象();

    like a :因为一个类可以同时实现多个接口,每个接口只表示子类中的一部分成员,通过一个接口只能看到一个类的冰山一角

    •  内部类

    定义在其他类内部的类

    按照内部类在类中定义的位置的不同,可以分为如下两种格式:

    成员位置(成员内部类)

    局部位置(局部内部类)

    内部类的访问特点:

    内部类可以直接访问外部类的成员,包括私有

    外部类要访问内部类的成员(甚至私有成员变量和成员方法也可以访问到),必须创建对象

    成员位置内部类,也依赖于外部类对象而存在

    ————————————————————————如何在外部类的外部,创建一个内部类对象

    内部类的访问语法(外部类的外部访问)

    外部类名.内部类名 对象名 = 外部类对象.内部类对象

    //1.定义指向内部类的引用变量
    MemberOuter.MemberInner obj;
    //2.创建指向内部类的引用变量
    MemberOuter outer = new MemberOuter;
    //3.在外部类对象上,创建外部类对象
    obj = outer.new MemberInner();
    //一步完成

    MemberOuter.MemberInner obj = new MemberOuter().new MemberInner();

    成员位置内部类用static修饰,就不依赖与外部类对象而存在了

    静态内部类:整个类都是一个静态上下文

    在外部类的外部,创建一个静态成员位置内部类 

    外部类名.内部类名 对象名 = new外部类名.内部类名();

    局部内部类:定义在类中,方法体中的类

    内部类的 访问特点:

    1.内部类可以直接访问外部类的成员,包括私有

    2.外部类要访问内部类的成员,必须创建对象

    注意:局部内部类对象的创建要简单的多,因为局部内部类只能在定义该类的方法体中才能被访问

    先定义局部内部类,然后才能创建对象

    局部内部类特点:

    可以访问到方法体中的局部变量

    但是在局部内部类中,我们只能访问方法体中的自定义常量——原因在于生命周期的冲突

    局部内部类对象 vs 局部变量

    1.局部变量的生命周期,随着方法的执行结束,即栈帧销毁,而从内存消失

    2.但是对于局部内部类对象而言,存储在堆上。对象的销毁和方法栈帧,没有直接关系,简单来说就是方法运行完了,局部变量不存在了,但是对象还在

    3.所以,如果方法运行完毕之后,还有人可以使用这个对象,那么就可以通过该局部内部类对象去访问这个局部变量,而此时,局部变量早已随着方法的执行完毕,从内存中消失了

    如何解决这个冲突——final

    effectively final 的变量:定义之后在方法体中,只被赋值一次且仅赋值一次的变量

    4.匿名内部类 对象

    创建匿名内部类对象的前提:存在一个类或接口(这里的类可以是具体类也可以是抽象类)

    匿名内部类对象:

    new 类名或接口名(){重写方法}

    本质:是一个继承了类或者实现了接口的子类匿名对象

    匿名对象:创建一个对象的时候,没有让引用变量指向该对象(没有给对象起名字)

    匿名对象我们只能在创建这个对象的时候引用一次,且仅一次

  • 相关阅读:
    1.python简介
    JSP标准标签库:JSTL
    冒泡排序算法
    中英文金额大写转换器
    递归与斐波那契数列
    web.xml配置文件详解
    Servlet及相关类和接口
    Servlet初始化及处理HTTP请求
    [转]jqGrid 属性、事件全集
    java web 过滤器跟拦截器的区别和使用
  • 原文地址:https://www.cnblogs.com/wbh1996/p/12923857.html
Copyright © 2020-2023  润新知