美文网首页
黑马程序员-面向对象1

黑马程序员-面向对象1

作者: 狼孩 | 来源:发表于2014-11-02 18:18 被阅读115次

    -------android培训java培训期待与您交流!----------

    1.面向对象概念

    a.面向对象概念

    • 理解面向对象:面向对象是面向过程而言。是一种思想。将功能封装进对象,强调具备了功能的对象。
    • 任何事物都能抽象成对象,比如人。人都有共性:年龄,性别,身高,学历等等。把人抽象成对象,而这个人对象内部的功能可以定义成年龄,性别,身高等等这些;而对于外界想要调用你这个人的某个功能属性,对他来说不必关心你人对象内部的实现,他只管调用你的这个对象某个功能,获取他需要的结果即可。方便快捷,提高编程效率。
    • 面向对象三个特征:封装、继承、多态

    b.类与对象的关系

    • 类:对现实生活中事物的描述。
    • 对象:就是实实在在的个体的这类事物。
    • 定义:
      A. 定义类就是在描述事物,也就是在定义属性和行为。属性和行为共同成为类中的成员(成员变量,成员函数)。
      B. 对象由new操作符来生成,在堆内存产生一个实体。
    • 示例:
    //定义类
        class People{
        //属性
        public int age;
        public string name;
        ...
        //定义方法 行为
        public int age()
        {
                return age;
        }
    
        //对象
        People p = new People();
        p.age();
        ...
    
    • 成员变量和局部变量
      A.最大区别区别:作用的范围不一样。成员变量作用于整个类中,从属于类,不必初始化。局部变量作用于函数中或者语句中,必须手动初始化。
      B.内存的位置:成员变量在堆内存中,因为对象的存在才存在于内存中。局部变量存在栈内存中。
    • 匿名对象
      A.匿名对象是对象的简化形式,没有名字的对象。格式为new 实例名称();
      B.匿名对象两种使用情况:
      (1).当对对象方法仅进行一次调用时
      (2).匿名对象可以作为实际参数进行传递
    new People().age = 23;
    
    age(new People());
    

    c.封装
    • OOP三大特征之一。
    • 概念:指隐藏独享的属性和实现细节,仅对外提供公共访问方式。
    • 封装的好处:将变化隔离、便于使用、提高重用性、提高安全性
    • 封装原则:将不需要对外提供的内容都隐藏起来、把属性都隐藏,提供公共方法对其访问。
    • private:私有权限反问修饰符。用于修饰类中的成员(成员变量,成员函数),私有指只在本类中有效。仅仅是封装的一种表现形式。

    d.构造函数

    • 特点:函数名与类名相同、不用定义返回值类型、不可以写return语句。
    • 作用:给对象初始化,用于对象初始化。
    • 注意:当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数,用于对象初始化。当在类中定义了初始化构造函数,默认的构造函数就没有了。
    • 特点:构造函数和一般函数在写法上不同在运行上也不同,构造函数是在对象一建立就运行,给对象初始化。而一般方法是对象调用才执行,给是对象添加对象具备的功能一个对象建立,构造函数值运行一次,而一般方法可以被该对象调用多次。
    //定义类
    class People{
        //默认构造函数
        People(){}
    }
    
    • 定义构造函数的时间:当对象需要一定的特征或者行为,就需要对其进行构造函数。

    构造代码块

    //定义类
    class People{
        /**
         * 作用:给对象进行初始化
         * 特点:对象一建立就运行,而且优先于构造函数执行,针对所有的对象进行初始化都会先被执行一次。
         * 和构造函数的区别:
         *             构造代码块是给所有对象进行统一初始化。
         *             构造函数时给对应的对象进行初始化。
         * 用处:定义给不同对象的共性进行初始化。
         */
        {
            System.out.println("构造代码块");
        }
    }
    

    e.this关键字

    • 用于区分局部变量和成员变量同名情况。
    • this代表它所在的函数所属对象的引用。
    • this代表本类对象。
        private int age;
        private String name;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    • 应用:当定义类中功能时,该函数内部要用到调用该函数的对象是,这时使用this来代表使用此对象。凡是本类功能内部使用了本类对象,都用this表示。
    class People{
        private int age;
    
        /**
         * 构造函数
         * @param age
         */
        People(int age)
        {
            this.age = age;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
    
        /**
         * 比较两个人的年龄是否相等。此处的this代表当前调用的对象的引用也就是p1。
         * @param p 人的对象变量
         * @return boolean
         */
        public boolean compare(People p)
        {
            return this.age == age;
        }
    
        
        public static void main(String[] args) {
            People p1 = new People(20);
            People p2 = new People(23);
            boolean b = p1.compare(p2);
            System.out.println("b = " + b);
    
        }
    }
    
    • this与构造函数:this用与构造函数的之间互相调用。而且只能定义在构造函数的第一行。因为初始化要先执行
    class People{
        private int age;
        private String name;
    
        /**
         * 空构造函数
         */
        People()
        {
        }
    
        /**
         * 构造函数
         * @param age
         */
        People(int age)
        {
            this();//调用People()构造函数
        }
    
        /**
         * 构造函数
         * @param age
         * @param name
         */
        People(int age, String name)
        {
            this(23);//调用People(int age)构造函数
            this.name = name;
        }
    

    f.static关键字

    • static修饰符,修饰变量、方法和代码块。
    • 当成员被static修饰后,可以用类名直接调用。格式:类名.静态成员。
        static String name;
    
        public static void main(String[] args) {
            System.out.println("People.name = " + People.name);
        }
    
    • 特点:随着类的加载而加载,静态随着类的消失而消失,生命周期最长、优先于对象的存在、被所有对象所共享、可以直接被类名所调用。
    • 实例变量和静态成员变量区别:
      A.存放位置:(1)静态成员变量随着类的加载而存在方法区中。(2)实例变量随着对象的建立而存在于堆内存中。
      B.生命周期:(1)静态成员变量最长,随着类的消失而消失。(2)实例变量随着对象的消失而消失。
    • 静态使用注意点:
      A.静态方法只能访问静态成员(方法与变量)。非静态方法即可以访问静态也可以访问非静态。
      B.静态方法中不可以定义this、super关键字。因为静态优先于对象存在。
      C.主函数是静态的。
    • 静态优缺点:
      A.优:对对象的共享数据进行单独空间的存储,节省空间。可以直接被类名调用。
      B.缺:生命周期过长、访问出现局限性(只能访问静态)。

    静态的使用时间:

    • 静态变量(类变量)定义:当对象中的出现对象调用的共享数据时,该数据被静态所修饰存在于方法区中;对象中的特有数据定义成非静态存在于堆内存中。
    • 静态函数定义:当类中的某个功能没有访问到非静态数据(对象特有的数据),那么该功能可以定义成静态的(static)。
    class People{
        String name;
    
        //没有关联到非成员变量name,那么这个函数可以设置成static的,方便后面直接通过类名调用
        public static void show()
        {
            System.out.println("没有访问到成员变量");
        }
    
        public static void main(String[] args) {
            //调用此方法时,与name没有关系。没有封装进数据。可以不建立对象来调用,设置成static的通过类名调用方便明了。
            People.show();
        }
    }
    

    静态代码块

    • 格式:
        static
        {
            System.out.println("静态代码块");
        }
    
    • 特点:随着类的加载而执行,只执行一次,用于给类进行初始化。并优先于主函数。

    g.mian函数

    public static void main(String[] args)
    
    • public:表示全局所有访问权限最大。也就是封装性。
    • static:表示只能通过类调用。主函数随着类的加载就已经存在了。
    • void:主函数没有具体返回值。
    • main:不是关键字,特殊的一个词,可以被JVM识别。
    • String[] args:函数的参数,是一个字符串数组。

    主函数是固定格式:JVM识别


    h.对象初始化过程:
    People p = new People("zhangsan", 23);

    1.因为new用到了People.class,所以会先找到People.class文件并加载到内存中。
    2.执行该类中的static代码块,如果有的话。再给People.class类进行初始化。
    3.在堆内存中开辟空间,分配内存地址。
    4.在堆内存中建立对象的特有属性,并进行默认初始化。
    5.对属性进行显示初始化。
    6.对对象进行构造代码块初始化。
    7.对对象进行对应的构造函数初始化。
    8.将内存地址赋给内存中的引用变量p。


    i.继承
    • 面向对象特征之二。
    • 把对象间的共性特征进行抽取,类与类之间有关系,最后抽象成一个共性类,被抽取的类的继承自这个共性类就可。减少代码量,提高复用性。
    • 形式:
    继承类 extends 被继承类
    
    • Java只支持单继承。支持多层继承:B继承A,D继承B。D类可以使用A类的功能。
    • 继承关系中类成员的特点:
      A. 变量:如果子类中出现非私有的同名变量时,子类要访问本类中的变量,用this。子类要访问父类中的同名变量,用super,super跟this的使用几乎一致。super代表父类对象的引用,this代表本类对象引用。
    /**
     * Created by Sergio on 2014/11/2.
     */
    public class ExtendsDemo1 {
        public static void main(String[] args) {
            Sun s = new Sun();
            s.show();
        }
    }
    
    class Parents{
        int num = 5;
    }
    
    //子继承父类
    class Sun extends Parents{
        int num = 4;
        void show()
        {
            System.out.println(num);//访问的是子类的变量,相当于this.num
            System.out.println(super.num);//碰到同名变量可以使用super关键字访问父类的变量。
        }
    }
    

    B. 函数:当父类出现和子类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖掉。这也叫做覆盖(重写)。

    /**
     * Created by Sergio on 2014/11/2.
     */
    public class ExtendsDemo1 {
        public static void main(String[] args) {
            Sun s = new Sun();
            s.show();
        }
    }
    
    class Parents{
        int num = 5;
        void show()
        {
            System.out.println("被覆盖");
        }
    }
    
    //子继承父类
    class Sun extends Parents{
        int num = 4;
        void show()
        {
            System.out.println(num);//访问的是子类的变量,相当于this.num
            System.out.println(super.num);//碰到同名变量可以使用super关键字访问父类的变量。
        }
    }
    

    覆盖注意点:子类覆盖父类,必须保证子类权限大于等于父类权限,才可以叫覆盖,否则编译失败。静态只能覆盖静态。
    C. 构造函数:在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式的语句super()[会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();];

    /**
     * Created by Sergio on 2014/11/2.
     */
    public class ExtendsDemo2 {
        public static void main(String[] args) {
            Sun2 s2 = new Sun2(2);
            System.out.println(s2.x);//访问的是父类抽取的x = 4;
        }
    }
    
    class Parents2{
        int x = 4;
        Parents2()
        {
            System.out.println("fu run");
        }
    
        Parents2(int x)
        {
            System.out.println("x = " + x);
        }
    }
    
    //子继承父类
    class Sun2 extends Parents2{
        Sun2()
        {
            //super();隐式的构造函数
            super(1);//根据父类构造函数来指定
            System.out.println("zi run");
        }
    
        Sun2(int x)
        {
            super(3);//根据父类构造函数来指定
            System.out.println("zi run");
        }
    }
    

    super语句一定定义在子类构造函数的第一行,初始化动作要先做。子类的所有的构造函数,默认都会访问父类中空参数的构造函数,因为子类每一个构造函数的第一行都有一句隐式super();当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问的构造函数。子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。


    j. final关键字
    • 解释:最终。修饰符。
    • 修饰的范围:类、函数、变量。
    • 特点:被final修饰的类不可以被继承,为了避免被继承,被子类复写功能。
    • final类:被final修饰的类不可以复写。
    • final变量:被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量。
    • 使用的时候。描述事物时,一些数据的出现值是固定的。可以用一个常量来表示。
    • 命名:常量的书写规范所有字母都大写。如果有多个单词定义,每个单词通过"_"链接。P_AI。比如PI。

    k. 抽象类
    • 多个类出现相同功能,但是功能主体不同,进行向上抽取,只抽取功能定义,而不抽取功能主题。
    • 定义方式:abstract 类名包含抽象方法和非抽象方法、abstract 方法名();抽象方法只有方法名没有方法内容。
    • 注意:抽象方法只存在于抽象类中。抽象类不可以用new创建对象,因为调用抽象方法没有意义。抽象方法要被使用,必须由子类复写所有的抽象方法后,建立子类对象调用;如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类,因为抽象方法只存在于抽象类中。
    • 抽象类不可以实例化,没意义。

    l. 接口
    • 格式:interface 接口名{}。接口中定义常量、方法固定修饰符如下(修饰符可以省略,interface会自动加上。):
      A. 常量:public static final
      B. 方法:public abstract
      接口中的成员都是public。接口中的方法都是抽象的。
    /**
     * Created by Sergio on 2014/11/3.
     */
    interface InterfaceDemo {
        public static final int NUM = 3;//变量定义
        public abstract void intefaceDemo();//方法定义
    }
    
    
    //接口必须被子类实现用关键字implements,接口可以被多个子类实现。子类也可以继承于一个父类。必须将接口中的所有方法实现因为接口中的方法都是抽象的
    class InterfaceTest extends ExtendsDemo2 implements InterfaceDemo,InterfaceDemo2....{
        @Override
        public void intefaceDemo() {
    
        }
    }
    

    接口是不可以创建对象的,因为有抽象方法存在。需要被子类实现,覆盖接口中的抽象方法后,子类才可以实例化,否则子类是一个抽象类。
    接口与接口之间的关系是继承关系,支持多继承关系。

    • 接口特点:
      -. 接口是对外暴露的规则
      -. 接口是程序的功能扩展
      -. 接口可以用来多实现
      -. 类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
      -. 接口与接口之间可以有继承关系

    m. 多态与关键字instanceof

    一. 概念

    • 面向对象特征之三
    • 概念:事物存在的多种体现形态。比如人分为:男人、女人。人 r = new 男人(); 人 r2 = new 女人();

    二. 多态扩展性

    1. 多态的体现:父类的引用指向了自己的子类对象(父类)。
    2. 多态的前提:类与类之间有关系,有继承或者实现。
    3. 多态的益处:多态的出现提高了程序的扩展性,通常有前提条件是:存在覆盖。
    4. 多态的弊端:只能使用父类的引用访问父类中的成员。
    5. 多态中成员的特点:
      • 非静态成员函数:
        a. 在编译时期:参与引用型变量所属的类中是否有调用的方法,如果有编译通过,如果没有编译失败。
        b. 在运行时期:参与对象所属的类中是否有调用的方法。
        总结就是:成员函数在多态调用时,编译看左边,运行看右边。
      • 成员变量:
        无论编译和运行:都参考左边(引用型变量所属的类)
      • 静态成员函数(子类不覆盖父类方法,父类走父类,子类走子类。变量也一样。):
        无论编译和运行:都参考左边
    /**
     * Created by Sergio on 2014/11/19.
     */
    public class PolymorphicDemo {
        public static void main(String[] args) {
            //调用子类覆盖父类的eat()方法,有局限性在这点上
            function(new Dog());
            function(new Pig());
        }
    
        //定义共性的功能方法eat()
        public static void function(Animal a)
        {
            a.eat();
        }
    }
    
    /**
     * 集中抽象功能的父类Animal
     */
    abstract class Animal{
        abstract void eat();
    }
    
    
    /**
     * 定义Dog类继承之Animal父类,并且拥有自己的特定功能类houseKeeping().
     */
    class Dog extends Animal{
        //覆盖父类eat()方法
        public void eat()
        {
            System.out.println("Dog.eat");
        }
    
        //子类特有的方法
        public void houseKeeping()
        {
            System.out.println("看家");
        }
    }
    
    
    /**
     * 定义Pig类继承之Animal父类,并且拥有自己的特定功能类fat().
     */
    class Pig extends Animal{
        //覆盖父类eat()方法
        public void eat()
        {
            System.out.println("Pig.eat");
        }
    
        //子类特有的方法
        public void fat()
        {
            System.out.println("养膘");
        }
    }
    

    三. 父类、子类类型转型

    /**
     * Created by Sergio on 2014/11/19.
     */
    public class PolymorphicDemo {
        public static void main(String[] args) {
            //类型提升,向上转型。将Dog类型提升为Animal类型
            Animal a = new Dog();
            a.eat();
    
            /**
             * 如果要调用子类特有的方法操作:强制将父类的引用转成子类类型,向下转型.将父类a引用强制转换成子类类型Dog。
             *
             * 注意:不能将父类对象转成子类类型。能转换的是父类指向了自己的子类对象时,该引用可以被提升也可以强制转换。
             * 多态始终都是子类在作者变化。
             */
            Dog d = (Dog)a;
            d.houseKeeping();
    
            //fun函数调用子类对象的功能
            fun(new Dog());
            fun(new Pig());
        }
    
        //提炼共性函数特征fun(Animal a)
        public static void fun(Animal a)
        {
            a.eat();
    
            /**
             * 判断传递进来的子类是那个对象的。使用关键字instanceof,判断左边对象是否属于右边类的实例,返回boolean
             * 类型数据。
             *
             * instanceof是一个二元操作符。使用的前提:1.子类型有限、2.对象需要做比较首先判断是否属于某个类的实例
             */
            if (a instanceof Dog){
                Dog d = (Dog)a;
                d.houseKeeping();
            }
            else if(a instanceof Pig)
            {
                Pig p = (Pig)a;
                p.fat();
            }
        }
    }
    
    /**
     * 集中抽象功能的父类Animal
     */
    abstract class Animal{
        abstract void eat();
    }
    
    
    /**
     * 定义Dog类继承之Animal父类,并且拥有自己的特定功能类houseKeeping().
     */
    class Dog extends Animal{
        //覆盖父类eat()方法
        public void eat()
        {
            System.out.println("Dog.eat");
        }
    
        //子类特有的方法
        public void houseKeeping()
        {
            System.out.println("看家");
        }
    }
    
    
    /**
     * 定义Pig类继承之Animal父类,并且拥有自己的特定功能类fat().
     */
    class Pig extends Animal{
        //覆盖父类eat()方法
        public void eat()
        {
            System.out.println("Pig.eat");
        }
    
        //子类特有的方法
        public void fat()
        {
            System.out.println("养膘");
        }
    }
    

    四:小示例

    package com.sergio.lianxi;
    
    /**
     * Created by Sergio on 2014/11/20.
     *
     * 需求:电脑运行实例。电脑运行基于主板。
     */
    public class PolymorphicDemo2 {
        public static void main(String[] args) {
            MotherBoard mb = new MotherBoard();
            mb.run();
            mb.usePCI(new SoundCard());
        }
    
    }
    
    /**
     * 电脑的各种部件基于电脑主板上的pci接口运行。模拟PCI接口。
     */
    interface PCI{
        public void open();
        public void close();
    }
    
    //定义主板,运行的基础
    class MotherBoard{
        public void run(){
            System.out.println("主板运行");
        }
    
        public void usePCI(PCI p)//接口型引用指向自己的子类对象
        {
            if(p != null)
            {
                p.open();
                p.close();
            }
        }
    }
    
    
    /**
     * 需要运行部件实现方式
     */
    class SoundCard implements PCI
    {
        @Override
        public void open() {
            System.out.println("声卡运行");
        }
    
        @Override
        public void close() {
            System.out.println("声卡关闭");
        }
    }
    

    2.设计模式

    单例设计模式
    • 设计模式概念:解决某一类问题最行之有效的方法,可以重复利用。java有23种设计模式。
    • 单例模式:只对外提供一个实例。在内存中只存在一个对象。
    • 三要素:(1)在类体中需要具有静态的私有的本类型的变量、(2)构造方法必须是私有的,不允许实例化、(3)提供一个公共的静态的入口方法。
    package com.sergio.lianxi;
    
    /**
     * 单例模式饿汉式。
     * 第一种方式。类一进内存就建立对象。
     * Created by Sergio on 2014/10/10.
     */
    public class SinglePattern {
        private int age;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "SinglePattern{" +
                "age=" + age +
                '}';
        }
    
        //以下三个方法是单例使用的必须写法
        /**
         * 静态私有化本类的成员变量
         */
        private static SinglePattern instance = new SinglePattern();
    
        /**
         * 私有化构造方法,禁止对象实例化
         */
        private SinglePattern(){}
    
        /**
         * 对外提供一个公共的静态入口方法
         */
        public static SinglePattern getInstance()
        {
            return instance;
        }
    }
    
    class SinglePatternTest
    {
        public static void main(String[] args) {
    
            SinglePattern s1 = SinglePattern.getInstance();
            SinglePattern s2 = SinglePattern.getInstance();
            s1.setAge(23);
            System.out.println("s2 = " + s2);
        }
    }
    
    package com.sergio.lianxi;
    
    /**
     * Created by Sergio on 2014/10/10.
     * 单例模式懒汉式。也叫延迟加载式。只有调用了getInstance方法时,才建立对象
     */
    public class SinglePattern2 {
        private static SinglePattern2 instance = null;
        private SinglePattern2(){}
        public static synchronized SinglePattern2 getInstance()
        {
    if
            if(instance == null)
            {
                instance = new SinglePattern2();
            }
            return instance;
        }
    }
    

    注意:开发时候使用饿汉式,也就是第一种。

    相关文章

      网友评论

          本文标题:黑马程序员-面向对象1

          本文链接:https://www.haomeiwen.com/subject/cffptttx.html