zoukankan      html  css  js  c++  java
  • 面向对象的三大特性

    三大特性

    封装

    一句话:属性私有化,get/set

    在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。

    封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。

    要访问该类的代码和数据,必须通过严格的接口控制。

    封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

    适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

    优点

    1. 提高程序的安全性,保护数据。
    2. 隐藏信息,实现细节。
    3. 统一接口
    4. 减少耦合。

    实现封装

    1. 修改属性的可见性来限制对属性的访问(一般限制为private), 只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。
    2. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问
    public class Student {
        private int age;// 年龄
        private String name;// 名字
        
        // 提供一些public 的get、set方法。
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            if (age > 100 || age < 0) {
                this.age = 3;
            } else {
                this.age = age;
            }
        }
    }
    
    

    采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。

    public class Application {
        public static void main(String[] args) {
            Student student = new Student();
            //student.name; // private私有化之后,外部类无法访问该属性。
            student.setName("小明");
            student.setAge(18); // 年龄在内部处理逻辑
            // student.setAge(999);  //处理不合理的年龄
            String name = student.getName();
            int age = student.getAge();
            System.out.println(name + age +"岁啦");
        }
    }
    

    以上实例中public方法是外部类访问该类成员变量的入口。

    通常情况下,这些方法被称为getter和setter方法。

    因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。

    继承

    一句话:子类继承父类的特征和行为。

    extends 是"扩展"的意思,子类是父类的扩展。

    继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

    继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

    特性

    • 子类拥有父类非 private 的属性、方法。
    • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
    • 子类可以用自己的方式实现父类的方法。(重写)
    • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
    • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

    关键字

    继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,

    当一个类没有继承的两个关键字,则默认继承object祖先类(这个类在 java.lang 包中,所以不需要 import)。

    extends:在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。

    implements:可以同时继承多个接口(接口跟接口之间采用逗号分隔),使java具有多继承的特性。

    public interface A {
        public void eat();
        public void sleep();
    }
     
    public interface B {
        public void show();
    }
     
    public class C implements A,B {
    }
    
    

    super:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

    this:指向自己的引用。

    final :声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:

    区别 前提 构造方法
    this 表示本身调用者这个对象 没有继承也可以使用 this()
    super 代表父类对象的引用 只能在继承条件才可以使用 super()

    注意点

    • super()调用父类的构造方法,必须在构造方法的第一个
    • this()调用自己的构造方法,必须在构造方法的第一个,所以this() super() 不能同时出现
    • super()只能出现在子类的方法或构造方法中!

    继承格式

    class 父类 {
    }
     
    class 子类 extends 父类 {
    }
    
    

    父类Person

    /**
     * 隐式继承Object类
     */
    public class Person {
        private String name;
        public void say() {
            System.out.println("说话说话");
        }
    }
    

    子类Student继承Person

    public class Student extends Person {
    
    }
    
    public class Application {
        public static void main(String[] args) {
            Student student = new Student();
            student.say();
        }
    }
    

    子类继承了父类的公共方法和属性

    继承类型

    继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等

    img

    IDEA快捷键 ctrl + H 查看继承关系

    方法重写

    重写都是方法的重写,与属性无关

    image-20200510214544325

    重写:需要有继承关系,子类重写父类的非静态方法!

    1. 方法名必须相同
    2. 参数列表必须相同
    3. 修饰符可以扩大但不能缩小 public >protected>default>private
    4. 抛出的异常范围:可以被缩小但不能扩大;

    为什么需要重写?父类的功能,子类不一定需要,或者不一定满足。

    多态

    一句话:同一个方法可以根据发送对象的不同而采取多种不同的行为方式。

    使用手机扫描二维码支付时,二维码并不知道客户是通过何种方式进行支付,只有通过二维码后才能判断是走哪种支付方式执行对应流程。

    img

    多态可以实现动态编译:类型在执行过程中才可以确定:增强可扩展性~

    多态是同一个行为具有多个不同表现形式或形态的能力。

    多态就是同一个接口,使用不同的实例而执行不同操作。

    前提条件

    1. 继承
    2. 重写
    3. 父类引用指向子类

    特征

    • 对象能执行的方法和左边的类型有关,和右边的关系不大
    • 子类能调用的方法都是自己的或者继承父类的。
    • 父类型可以指向子类,但是不能调用子类独有的方法。
    • 父类想要执行子类的方法需要向下转型,高转低是强制转换!

    优点

    1. 减耦合
    2. 增强可以替换性
    3. 可扩展性
    4. 灵活性等

    关键词instanceof

    instanceof:测试它左边的对象是否是它右边的类的实例

    判断一个对象是什么类型,instanceof可以判断两个类之间是否存在父子关系

    image-20200512092823693

    public class Application {
        public static void main(String[] args) {
            // instanceof
            // 1.先判断左侧的引用类型与右边类是否有关系
            // 2.再判断左侧的实际类型与右边类是否有关系
    
            // 继承关系
            //      Object
            //      /   
            //  String  Person
            //          /   
            //     Student   Teacher
    
            // 公式 ClassA obj = new ClassB();
            // obj instanceof 任意类
            // 能够通过编译 取决于ClassA 与 任意类 有没有关系
            // true/false 取决于ClassB 与 任意类 有没有关系
    
    
            // 对象的引用类型是Student类
            Student obj1 = new Student();
            System.out.println("=======Student->Student==========");
            System.out.println(obj1 instanceof Student);
            System.out.println(obj1 instanceof Person);
            System.out.println(obj1 instanceof Object);
            // System.out.println(obj1 instanceof Teacher); // Student 和 Teacher 是兄弟关系,报错~
            // System.out.println(obj1 instanceof String); // Student 与 String无直接联系,报错!
    
    
            Person obj2 = new Student();
            System.out.println("=======Person->Student==========");
            System.out.println(obj2 instanceof Student);
            System.out.println(obj2 instanceof Person);
            System.out.println(obj2 instanceof Object);
            System.out.println(obj2 instanceof Teacher);
            // obj2 指向的是Student类,与Teacher无直接联系
            //System.out.println(obj2 instanceof String); // Person 与 String无直接联系,报错!
    
            Object obj3 = new Student();
            System.out.println("=======Object->Student==========");
            System.out.println(obj3 instanceof Student);
            System.out.println(obj3 instanceof Person);
            System.out.println(obj3 instanceof Object);
            System.out.println(obj3 instanceof Teacher);
            System.out.println(obj3 instanceof String);
    
            Person obj4 = new Person();
            System.out.println("=======Person->Person==========");
            //
            System.out.println(obj4 instanceof Student);
            System.out.println(obj4 instanceof Person);
            System.out.println(obj4 instanceof Object);
            System.out.println(obj4 instanceof Teacher);
            // System.out.println(obj4 instanceof String);
            // Person 与 String无直接联系,报错!
        }
    }
    
    

    类型转换

    基础类型转换

    • 低 ------>高 隐式转换
    • 高------->低 强制转换

    引用类型转换

    • 低(子类)----->高(父类)

    • 低转高:Person obj1 = new Student(); 即向上转换,不需要强制转换

    • 高转低 Student obj2 = (Student)obj1; 即向下转换,需要强制转换

    注意:之前学习继承的时候说,子类是父类的扩展,所以子类转换成父类时会丢失一些本身的方法或属性。

    父类型可以指向子类,但是不能调用子类独有的方法。因为子类独有的方法丢失了,无法调用。

    多态小结

    • 多态是方法的多态,属性没有多态

    • 父类和子类

      • 有联系。instanceof
      • 类型转换异常!ClassCastException!
      • 子类转换成父类,向上转型,丢失方法
      • 父类转换成子类,向下转型 (强制转换)
    • 存在条件

      • 继承关系
      • 方法需要重写
      • 父类引用指向子类对象!
    • 不能重写的方法

      • static 静态方法属于类,不属于实例
      • final常量修饰不能继承
      • private 方法私有

    OOP面向对象的编程思想就是抽象

    [代码区](# 多态代码)

    多态的表现

    多态代码

    第一种情况 对象的实际类型确定,指向的引用类型不确定(可以用父类引用类型指向子类对象)

    如下有Person类

    Person.java

    public class Person {
        public void say() {
            System.out.println("father---say");
        }
    }
    
    

    Student.java

    // 继承 Person 类
    public class Student extends Person {
    }
    
    

    有继承关系才可以指向

    Application.java

    /**
     * 测试多态的表现
     */
    public class Application {
        public static void main(String[] args) {
            // 一个对象的实际类型是确定的
            // new Student(); // 创建出一个学生
            // new Person();  // 创建出一个人
    
            // 可以指向的引用类型就不确定了
            Student s1 = new Student(); // new 一个学生 名字叫 学生
            Person s2 = new Student();// new 一个学生 名字叫 人(学生也是人,他继承了人)
            Object s3 = new Student();
            s2.say();
        }
    }
    
    

    运行结果

    father---say
    
    

    子类能调用的方法都是自己的或者继承父类的。如果子类中没有say方法,则调用继承于父类的say方法。

    如果在子类重写了父类的say方法,则调用本身的say方法。如下代码重写了父类的say方法:

    Student.java

    public class Student extends Person {
        @Override
        public void say() { // 重写父类say方法
            System.out.println("son ---- say");
        }
    }
    
    

    Application.java

    /**
     * 测试多态的表现
     */
    public class Application {
        public static void main(String[] args) {
            // 一个对象的实际类型是确定的
            // new Student(); // 创建出一个学生
            // new Person();  // 创建出一个人
    
            // 可以指向的引用类型就不确定了
            Student s1 = new Student(); // new 一个学生 由 学生
            Person s2 = new Student();// new 一个学生 由人接收(学生也是人,他继承了人)
            Object s3 = new Student();
            s1.say();// 学生 说
            s2.say();// 学生 说
            
        }
    }
    
    

    运行结果

    son ---- say
    son ---- say
    
    

    因为实例是确定的,s1,s2都是new 出来的Student()实例对象,方法的功能与实例的实现有关。

    如果在Student类中添加一个eat()方法

    public class Student extends Person {
        @Override
        public void say() {
            System.out.println("son ---- say");
        }
        
        public void eat() {
            System.out.println("son ---- eat");
        }
    }
    
    
    public class Application {
        public static void main(String[] args) {
    
            Student s1 = new Student();
            Person s2 = new Student();
    
            //对象能执行的方法和左边的类型有关,和右边的关系不大
            s1.say();// 学生 说
            s2.say();// 学生 说
    
            s1.eat(); // s1 左边是学生类,学生类里面有say方法。成功调用
            //s2.eat(); // s2 左边是人类,人类中没有eat方法,又不能继承,所以调用失败
        }
    }
    
    

    对象能执行的方法和左边的类型有关,涉及到类型转换,高-->低 会丢失精度。比如

    public class Test {
        public static void main(String[] args) {
            float a = 1.5f;
            long b = 99999999999999L;
            System.out.println((int)a); // 结果打印1 丢失了小数部分
            System.out.println((int)b); // 结果打印276447231  丢失数据溢出部分
        }
    }
    
    

    但在学习继承的时候知道,子类继承父类获取父类的非私有属性和方法,子类是父类的扩展。

    这里引用类型和基本类型的转换是存在区别的,基本类型高精度转型为低精度会丢失数据。而引用类型子类转型为父类会丢失方法或属性。

  • 相关阅读:
    [原创]ASP.NET MVC调用美图秀秀开放平台拼图实现
    使用Lucene检索文档中的关键字
    Unitils+hibernate+Spring+PostgreSql做dao层测试遇到的错误
    初探IronJS
    IntelliJ IDEA 12 创建Web项目 教程 超详细版
    百度面试题:求绝对值最小的数
    jquery+css实现简单的评分功能
    Knockot JS 数字输入插件
    Diagnostic Policy Service 服务处于起不来
    WCF学习笔记(一) 之 开门见山
  • 原文地址:https://www.cnblogs.com/1101-/p/12882780.html
Copyright © 2011-2022 走看看