黑马程序员_001_面向对象的特性

来源:互联网 发布:mac鼠标移动速度 编辑:程序博客网 时间:2024/05/29 10:12
------- android培训、java培训、期待与您交流! ----------
面向对象的特性:封装、继承和多态。
1、封装:(Encapsulation)
        封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问的方式。
        好处:
                将变化隔离。
                便于使用。
                提高重用性。
                提高安全性。
        封装原则:
                将不需要对外提供的内容都隐藏起来。
                把属性都隐藏,提供公共方法对其进行访问。
        类中方法是最小的封装体。类也是封装体。包也是封装体。
2、继承
        有时不同类之间有共性的东西,如下的name和age
        class Student
        {
                String name;
                int age;
                void study()
                {
                        System.out.println("study");
                }
        }

        class Worker
        {
                String name;
                int age;
                void work()
                {
                        System.out.println("work");
                }
        }

      /*
       继承:将不同类之间的通性描述提取出来,单独描述,关键字extends
                  只要让学生和工人与单独描述的这个类有关系,就可以了
        优点:提高了代码的复用性,让类与类之间产生了关系,有了这个关系,才有了多态的特性
        注意:千万不要为了获得其他类的功能,简化代码而继承,必须是类与类之间有所属关系才可以继承,所属关系is a 。
         另外:Java中,只支持单继承,不支持多继承(一个子类只能有一个父类)。因为多继承容易带来安全隐患,当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定调用哪一个。但是java保留 了这种机制,并用另一种体现形式来完成表示,多实现。
java支持多层继承(祖-父-子--孙),也就是一个继承体系。
        如何使用一个继承体系中的功能?
        想要使用体系,先查询体系父类的描述,因为父类中定义的是该体系中共性功能。通过了解共性功能,就可以知道该体系的基本功能。那么这个体系已经可以基本使用了。那么在具体使用时,要创建最子类的对象,因为有可能父类不能创建对象(如抽象类),创建子类对象可以使用更多功能,包括基本的和特殊的。总结:查阅父类功能,创建子类对象使用功能。
        */
        class Person
        (
                String name;
                int age;
        )
       class Student  extends Person
        {
                void study()
                {
                        System.out.println("study");
                }
        }

        class Worker extends Person
        {
                void work()
                {
                        System.out.println("work");
                }
        }

        特别注意:子类不能继承父类构造函数。
        子父类中的构造函数,子类构造函数不能覆盖父类的构造函数,因为函数名不同。在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式语句super();,super();在每个子类的构造函数中都有,且调用的是父类中空参数的构造函数。如果父类中没有空参数的构造函数,有带参数的构造函数,则子类构造函数中必须手写super(参数);,不能默认。
        class Fu
        {
                Fu()
                {
                        System.out.print("fu");
                }
        }
        class Zi extends Fu
        {
                  Zi()
                {
                        //super();该语句为隐的,不写系统会自动加上。调用的是Fu();
                        System.out.println("zi");
                }
        }
        class ExtendsDemo
        {
                public static void main(String[] args)
                {
                        Zi z = new Zi();
                        //结果:fu  zi   
                }
        }
为什么子类构造函数一定访问父类构造函数?
        因为父类中的数据子类可以直接获取,所以子类对象在建立时需要查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时,要先访问以下父类中的构造函数,如果要访问父类中指定的构造函数,可以通过手动定义super的参数。在一个构造函数中不能同时存在super和this。
子类的实例化过程
        子类所有构造函数,默认都会访问父类中空参数的构造函数,因为子类每个构造函数内的第一行都有一句隐式的super();当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。当然,子类中的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,子类中至少会有一个构造函数会访问父类中的构造函数。
super调用函数:且一定放在子类构造函数的第一行(第一行,指的是初始化过程先做)
        构造函数:super(参数);
        一般函数:super.函数名(参数);

3、多态:可以理解为事物存在的多种体现形态。
      人:男人、女人
      动物:猫、狗
      动物 x = new 猫();

      多态的体现
            父类的引用指向了自己的子类对象
            父类的引用可以接受自己子类的对象
abstract class Animal
{
    public abstract void eat();
}
class Cat extends Animal
{
        public void eat()
        {
                System.out.println("吃鱼");
        }
        public void catchMouse()
        {
                System.out.println("抓老鼠");
        }
}
class Dog extends Animal
{
        public void eat()
        {
                System.out.println("吃骨头");
        }
        public void kanJia()
        {
                System.out.println("看家");
        }
}
class DuoTaiDemo
{
        public static void main(String[] args)
        {
                /*
                Cat c = new Cat();
                c.eat();
                Dog d = new Dog();
                d.eat();
                */
                /*
                Cat c = new Cat();
                function(c);
                Dog d = new Dog();
                function(d);
                */
                Animal a = new Cat();//父类的引用指向了自己子类对象
                                                    //类型提升,向上转型。子类型转为父类型
                
                   // 如果想要调用子类的特有方法,该如何做?
                   // 强制将父类引用转成子类类型,向下转型
                    Cat c = (Cat)a;
                    c.catchMouse();
                
                    Animal a = new Animal();
                    Cat c = (Cat)a;//这种方式不行,将父类对象转为子类类型。
                                 //我们能转换的是父类的引用指向了子类对象时,可以转换
                                //多态自始至终都是子类对象在做着变化
              //  a.eat();
                function(a);
        }
        /*
        public static void function(Cat c)
        {
                c.eat();
        }
        public static void function(Dog d)
        {
                d.eat();
        }
        */
        public static void function(Animal a)
        {
                a.eat();
                if(a instanceof Cat)//引用a 是不是Cat类型的
                {
                        Cat c = (Cat)a;
                        c.catchMOuse();
                }
                else if(a instanceof Dog
                {
                        Dog c = (Dog)a;
                        c.kanJia();
                }
        }
}

    多态的前提必须是类与类之间有关系,继承或实现,通常还有一个前提就是存在覆盖。
    多态的好处:多态的出现大大提高了程序的扩展性。
    多态弊端:提高了扩展性,但是只能使用父类的引用访问父类的成员。
    多态的出现代码中的特点(多态使用注意事项)
           在多态中非静态成员函数的特点,在编译时期,参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败;在运行时期,参阅对象所属的类中是否有调用的方法。简单总结就是,成员函数在多态调用时,编译看左边,运行看右边。(理解:父类引用指向其子类对象时,该引用只能调用父类中定义过的成员函数,不能调用子类特有的成员函数,若子类重写了父类函数则调用子类中重写的方法)
           在多态中,成员变量的特点,无论编译和运行,都参考左边(理解:父类应用指向其子类对象时,子父类中有同名变量时,该引用调用的都是父类中的成员变量,不调用子类中的成员变量,不能调用子类中特有成员变量)。
class Fu
{
int x=2;
}
class Zi extends Fu
{
int x= 5;
int y = 3;
}
class DuoTaiDemo
{
public static void main(String[] args)
{
Fu f = new Zi();
System.out.println(f.x);
}
}

            在多态中,静态成员(变量和方法)的特点,只引用父类的静态成员(因为静态成员已经与定义它的类绑定了)
            题外话:静态成员只能被它或其子类直接调用,不能被其他没有关系的类直接调用。


 

0 0
原创粉丝点击