`
new_Line
  • 浏览: 9769 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
社区版块
存档分类
最新评论

黑马程序员_java面向对象三大特征

 
阅读更多

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

Java是面向对象的程序设计语言,主要表现为java完全支持面向对象的三种基本特征:封装、继承、多态。
封装:
    封装是面向对象三大特征之一,它指的是将对象的实现细节隐藏在对象内部,不允许外部直接访问。
    通过提供的公有方法供外部使用提高了程序的安全性,和代码的可维护性。通过访问修饰符来实现封装。
    Java提供了4中访问修饰符:private、default、protected、public,访问级别按照抒写顺序从小到大。
    具体访问权限如下:
    private(当前类访问权限):
        如果类中的成员使用private修饰,则被修饰的成员只能在此类中供内部访问。
        因此一般使用private修饰成员属性,实现封装。
    default(包访问权限):
        这里的default是指默认不写,不是修饰符叫default。如果类中的成员或者定义类时不使用
        任何访问修饰符,就称为包访问权限,default修饰的成员和类可以被同一包下的其他类访问。
    protected(子类访问权限):如果一个成员使用protected修饰,该成员可以被同一包中的其他类访问,
        也可以被不同包中的子类访问,如果方法被protected修饰,一般是希望子类重写该方法。
    public(公共访问权限):
        被public修饰的成员或类,该成员和类可以被所有类访问。访问权限最大。
        访问修饰符用于控制一个类的成员是否可以被其他类访问,因此局部变量不能使用访问修饰符,
        因为局部变量的作用范围只在所在的一对大括号中有效。对于类而言(此篇中的类不是内部类),
        只能使用public和默认访问修饰符修饰,因为类没有处于任何类的内部,所以不能使用private
        和protected修饰。
          封装代码示例:
            public class Sample {
                /**
                 * 将属性私有化,不允许其他类直接访问
                 */
                private String name;
                private int age;
                /**
                 * Sample类的无参构造器
                 */
                public Sample(){}
                /**
                 * Sample类的有参构造器
                 * @param name
                 * @param age
                 */
                public Sample(String name, int age) {
                    this.name = name;
                    /**
                     * 通过判断,保证录入的年龄合法
                     */
                    if(age < 0 || age > 120){
                        System.out.println("输入的年龄不合法");
                        return;
                    }
                    this.age = age;
                }
                /**
                 * 对外提供获取name的方法
                 * @return 返回name
                 */
                public String getName() {
                    return name;
                }
                /**
                 * 对外提供设置name的方法
                 * @param name 该参数指定对象的name
                 */
                public void setName(String name) {
                    this.name = name;
                }
               
                /**
                 * 对外提供获取age的方法
                 * @return 返回age
                 */
                public int getAge() {
                    return age;
                }
               
                /**
                 * 对外提供该方法,设置age的方法
                 * @param age 该参数指定对象的age
                 */
                public void setAge(int age) {
                    /**
                     * 通过判断,保证录入的年龄合法
                     */
                    if(age < 0 || age > 120){
                        System.out.println("输入的年龄不合法");
                        return;
                    }
                    this.age = age;
                }   
            }
        上面程序演示外部不能直接对age和name进行操作,而是通过Sample类对外提供的get和set
        方法来访问,提高了程序的可维护性。
    使用访问修饰符的基本原则:
        1、类中的属性一般使用private修饰,static修饰的类变量除外。用于辅助实现其他方法的
           方法也用private修饰。
        2、如果一个类是其他类的父类,希望其他类重写该类里的方法,而不是被外界直接调用,
           一般用protected修饰
        3、希望暴露出来给其他类自由调用的方法应该用public修饰,因此一般构造器用public修饰
继承:
    关键字:extends
    概述:类本身就是一种抽象行为,它是从对象中抽取出共性的属性,来描述某一类事物。而类与类之间
          也存在共性的属性和方法,将这些共性向上抽取到一个单独的类中(父类或基类,超类),那么
          多个类(子类)就无需重复定义,只要继承该类即可,子类可以直接访问父类中的非私有属性和行为。
          提高了代码的复用性
              例:public class b{}
                  public class A extends B{}
    好处:提高了代码的复用性,让类与类之间产生了关系,为多态提供了先决条件
    特点:java只支持单继承,不支持多继承
        例:public class A extends B{} //OK
             public class A extends B,C{}//Error
          为什么不支持多继承?
            因为多继承容易带来安全隐患,当多个父类中定义了相同功能,而功能主题不同时,
              子类对象不确定运行哪一个方法。但是java保留了这种机制,用另一种表现形式来实现,
              即多实现。不过java支持多层继承,也就是一个体系
          例:public class A extends B{}
              public class B extends C{}
          如何使用一个体系中的功能?
          查阅父类功能,创建最子类对象
          为什么是创建子类对象?
              1、有可能父类不能创建对象(如:抽象类,接口)
          2、创建子类对象可以更多的功能,包含了子类
    注意:不要纯粹为了简化代码而继承,必须是类与类之间有所属关系才可以继承(is a)
    子父类中属性的特点:
        当子父类中出现一模一样的函数时,子类对象调用该函数,会运行子类中的函数,
        如同父类中的函数被覆盖了一样,这种情况是函数的另一个特征:重写(覆盖)
        举例:
            public class Test{
                  主函数(){
                      Zi z = new Zi();
                      z.show();  //
                  }
              }
                Class Fu{
                  public void show(){Sop(“父类函数运行了”)}
                  //如果把void改为int,编译失败,因为不仅实现不了重写而且
                //违背了函数重载的特性
              }
             Class Zi{
                  public void show(){Sop(“子类函数运行了”)}
             }
    重写:
        子类覆盖父类必须保证子类访问权限大于等于父类(否则编译失败),并且参数列表和返回值
        类型以及方法名一模一样才能实现覆盖。记住:重写子父类方法要一模一样,重载只是参数
        列表不一样。
        注意事项:静态只能覆盖静态,因为覆盖必须是子父类中的函数一模一样,如果去掉其中一个类中
        的static,编译会不通过,因为违反了函数重载的特性
        演示:
            public class Test {
                public static void main(String[] args)
                {
                    Zi z = new Zi();
                    z.show();  //运行结果:子类中的函数运行了
                }
            }
             class  Fu
            {
                static void show()
                {
                    System.out.println("父类中的函数运行了");
                   
                }
            }
            class Zi extends Fu
            {
                 static void show()
                {
                   
                    System.out.println("子类中的函数运行了");
                }
            }
    子父类中构造函数的特点:
        子父类中的构造函数不能实现重写(覆盖),因为子父类中的函数名不可能一样,
        不符合重写的要求。
        为什么创建子类对象时,会先运行父类构造器?
            因为子类构造器的第一行有一条隐式语句super();而super是父类的引用,super()会访问
        父类空参数的构造函数,并且所有子类构造函数中的第一行默认都是super();当父类构造
        函数中没有空参数的构造函数时,必须手动建立super(与之对应的参数)
        演示:
            public class Person {
                String name;
                int age;
                public Person(){}
                public Person(String name, int age)
                {
                    this.name = name;
                    this.age = age;
                }
                public void sleep()
                {
                    System.out.println("睡觉");
                }
                public String toString()
                {
                    return name + "  " + age;
                }
            }
            class Student extends Person
            {
                private String stuNo;
                public Student(){}
                public Student(String name, int age, String stuNo)
                {
                      //通过super显示的给父类构造器传参
                    super(name, age);
                    this.stuNo = stuNo;
                }
                public String toString()
                {
                    return name + "  " + age+ "  " + stuNo;
                }
            }
        为什么子类一定要访问父类中的构造函数?
        因为父类中的非私有数据子类可以直接获取,所以子类在对象建立时,需要先查看父类
        是如何对这些数据进行初始化的
多态:
    初步理解:其实就是子父类(接口或实现类)中的类型转换。子类转父类即小转大,和变量一样会
        自动类型转换,或称之为类型提升,父类转子类即大转小,要做强制类型转换
    程序中的体现:父类或接口的引用指向或者接收子类的对象,不能是子类引用指向父类对象,
        自始至终多态都是子类对象在做变化
    好处:大大提高了程序的扩展性
    前提:1、必须是类与类之间有关系,要么继承,要么实现(接口)
          2、必须存在覆盖
    弊端:只能使用父类中引用指向父类中的成员,但是会由子类中方法对其覆盖,如果掉用父类中
        不存在的方法,会编译失败
    属性的特点:属性不是多态的,当子父类中出现相同的属性时,以左边的引用为准
        演示说明:
            class A{
                Int num = 3;
            }
            Class B extends A
            {
                Int num = 5;
            }
            Main(){
                A a = new B;
                Sop(a.num);//输出3
                B b = new B;
                Sop(b.num);//输出5
            }
    非静态私有函数的特点:
          1、编译时期:参阅引用变量所属类(父类)中是否有调用方法,如果有编译通过,
               如果没有编译失败
            2、运行时期:如果子类中复写了父类中的方法,运行子类中的方法,
               如果子类没有复写,运行父类自己的方法
    静态函数的特点:和属性一样,static方法不是多态的,无论是编译还是运行都参考左边
        演示说明:
            public class DemoTest {
                public static void main(String[] args) {
                    A a = new B();
                    a.show(); //运行结果:父类函数
                }
              }
              class A
              {
                public static void show()
                {
                System.out.println("父类函数");
                }
              }
              class B extends A
              {
                public static void show()
                {
                    System.out.println("子类函数");
                  }
              }
    Instanceof运算符:
        Instanceof的前面是一个引用类型变量,后面是一个类,用于判断前面的对象是否是后面类
        的实例,如果是返回true,否则返回false。避免了ClassCastException异常。
    综合案例体现:
        public class Test {
            public static void main(String[] args)
            {
                Animal a = new Cat();//类型提升,向上转型。和基本数据类型一样,
                //如:byte a = 3; int b = a;
                function(a);
                //function(new Cat);
            }
            public static void function(Animal a)
            {
                a.eat();
                //如果调用父类中不存在的方法,编译失败,因为父类中不存在子类中
                //的特有方法,但如果要使用子类中的特有方法怎么做呢?将父类的引用
                //强制转换为子类类型
                if(a instanceof Cat)
                {
                    Cat c = (Cat)a;
                    c.catchMouse();
                }else if(a instanceof Dog)
                {
                    Dog d = (Dog)a;
                    d.kanHouse();
                }    }
        }
        public interface Animal {
            public abstract void eat();
        }
        public class Cat implements Animal {
            public void eat()
            {
                System.out.println("吃鱼");
            }
            public void catchMouse()
            {
                System.out.println("抓老鼠");
            }
        }
        public class Dog implements Animal {
            public void eat()
            {
                System.out.println("吃骨头");
            }
            public void kanHouse()
            {
                System.out.println("看家");
            }
        }
              ------- android培训java培训、期待与您交流! ----------         

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics