Java基础学习五 面向对象

关联博客:https://www.jianshu.com/p/d37281cbd38a

面向对象

采用面向对象的方式开发一个软件,生命周期当中【整个生命周期中贯穿使用OO面向对象方式】:
面向对象分析:OOA
面向对象设计:OOD
面向对象编程:OOP
类和对象的概念
 - 什么是类?
    - 类在现实世界当中是不存在的,是一个模板,是一个概念。是人大脑思考抽象的结果。
    - 类代表了一类事物
    - 在现实世界当中,对象A与对象B之间具有共同特征,进行抽象总结出一个模板,这个模板被称为类。
 - 什么事对象?
    - 对象是实际存在的个体。现实世界当中实际存在。
 - 描述一下整个软件开发的过程:
    - 程序员先观察现实世界,从现实世界当中寻找对象
    - 寻找了N多个对象之后,发现所有的对象都有共同特征。
    - 程序员在大脑中形成了一个模板【类】。
    - Java程序员可以通过java代码来描述一个类。
    - Java程序中有了类的定义。
    - 然后通过类就可以创建对象。
    - 有了对象之后,可以让对象直接协作起来形成一个系统。
 - 类 --【实例化】--> 对象
 - 对象又被称为:实例/instance
 - 对象 --【抽象】-->类

1. 面向过程和面向对象的区别

  • 面向过程:主要关注点是:实现的具体过程,因果关系【集成显卡的开发思路】
    • 优点:对于业务逻辑比较简单的程序,可以达到快速开发,前期投入成本低。
    • 缺点:采用面向过程的方式开发很艰难解决非常复杂的业务逻辑,另外面向过程的方式导致软件元素之间的“耦合度”非常高,只要其中一环出问题,整个系统受到影响,导致最终的软件“扩展力”差。另外,由于没有独立体的概念,所以无法达到组件复用。
  • 面向对象:主要关注点是:主要关注对象【独立体】能完成哪些功能。【独立显卡的开发思路】
    • 优点:耦合度低,扩展力强。更容易解决现实世界当中更复杂的业务逻辑。组件复用性强。
    • 缺点:前期投入成本较高,需要进行独立体的抽取,大量的系统分析与设计。
  • c语言是纯面向过的、c++半面向对象、Java纯面向对象
  • 现在出现的一些新的编程语言多数都是面向对象的。人在认识现实世界的时候已面向对象的方式。
  • 面向对象更符合人的思维方式

2. 面向对象的三大特征

2.1封装
   代码加注释讲解方式,其中Students类可以新建一个java类使用。
/**
 * 为什么要封装?封装有什么好处?
 * 封装的好处:
 *      1、封装之后,对于那个事物来说,看不到这个事物比较复杂的那一面,只能看到该事物简单的那一面。
 *      复杂性封装,对外提供简单的操作入口。照相机就是一个很好的封装案例,照相机的实现原理非常复杂,
 *      但是对于使用照相机的人来说,操作起来是非常方便的。
 *
 *      2、封装之后才会形成真正的"对象",真正的"独立体"。
 *
 *      3、封装就意味着以后的程序可以重复使用。并且这个事物适应性比较强,在任何场合都可以使用。
 *
 *      4、封装之后,对于事物本身,提高了安全性。【安全级别高】
 *
 */

public class HelloWorld {

    public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口

        Students peo = new Students();

        // 访问实例变量的语法格式:

        // 修改数据:引用.变量名 = 值
        peo.setName("张三");
        peo.setNoID(1233);
        peo.setAge(16);
        peo.setSex(true ? "男" : "女");
        peo.setAddr("深圳");

        // 读取数据:引用.变量名
        System.out.println(peo.getName());
        System.out.println(peo.getNoID());
        System.out.println(peo.getAge());
        System.out.println(peo.getSex());
        System.out.println(peo.getAddr());

    }
}

/**
 * 封装的步骤
 * 1,所以的属性私有化,使用private关键字进行修饰,private表示私有的,修饰所有数据只能在本类中访问。
 * 2,对外提供简单的操作入口,也就是说以后外部程序要想访问属性,必须通过这些简单的入口进行访问。
 *      - 对外提供两个公开的方法,分别是set方法和get方法
 *      - 修改这个属性的值,调用set方法
 *      - 读取这个属性的值,调用get方法
 * 3,set方法的命名规范
 *      public void set+属性首字母大写(形参){}
 * 4,get方法的命名规范
 *      public void get+属性首字母大写(){ return 属性;}
 *
 * 一种属性常访问的时候有几种访问形式?
 *  - 第一种方式:读取这个属性的值,读取get
 *  - 第二种方式:修改这个属性的值,读取set
 *
 *  setter和getter 方法没有static关键字
 *  有static关键字修饰的方法如何调用:类名.方法名(实参)
 *  没有static关键字修饰的方法如何调用:引用.方法名(实参)
 *
 */

class Students {

    int noID;// 学号
    String name; //姓名
    private int age; //年龄
    String sex; //性别
    String addr; // 地址

//=================setter=======================

    public void setAge(int age) {
        if (age<0|age>130) {
            System.out.println("年龄不合法");
            return ;
        }
        this.age = age;
    }
    public void setNoID(int noID) {
        this.noID = noID;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    //=================getter=======================

    public int getAge() {
        return age;
    }

    public int getNoID() {
        return noID;
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }

    public String getAddr() {
        return addr;
    }
}
2.2继承
    2.2.1 继承模块

   代码加注释讲解方式,其中CreditAccounts、Accounts、FF类可以新建java类使用。

/**
 * 关于java语言当中的继承:
 *      1、继承是面向对象三大特征之一
 *      2、继承基本作用:代码复用。但是继承最重要的作用是:有了继承才有以后的"方法覆盖"和"多态机制"。
 *      3、继承语法格式:
 *          [修饰符列表] class 类名 extends 父类名{
 *              类体 = 属性 + 方法
 *          }
 *      4、java语言当中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类。
 *      5、关于继承中的一些术语
 *          B类继承A类,其中
 *              A类称为:父类、基类、超类、superclass
 *              B类称为:子类、派生类、subclass
 *      6、在java语言当中子类继承父类都继承哪些数据?
 *          - 私有的不支持继承
 *          - 构造方法不支持继承
 *          - 其他数据都可以被继承
 *      7、虽然java语言当中只支持单继承,但是一个类也可以间接继承其他类,例如:
 *          C extends B{
 *          }
 *          B extends A{
 *          }
 *          A extends T{
 *          }
 *          C直接继承B类,但是C类间接继承 T A 类
 *      8、java语言中假如一个类没有显示继承任何类,该类默认继承JavaSE库当中提供的java.lang.Object类。
 *      java语言中任何一个类中都有Object类的特征。
 *
 */


public class HelloWorld {

    public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口

        // 对象继承 赋值 取值
        CreditAccounts ca = new CreditAccounts();
        ca.setActno("abc0001");
        ca.setBalance(20000.00);
        ca.setCredit(0.99);
        System.out.println(ca.getActno()+ "," + ca.getCredit() + "," + ca.getCredit() );

        // 间接继承 方法调用
        ca.doSome();
    }
}

class CreditAccounts extends Accounts{

    private double credit;

    public CreditAccounts() {
    }

    public CreditAccounts(double credit) {
        this.credit = credit;
    }

    public double getCredit() {
        return credit;
    }

    public void setCredit(double credit) {
        this.credit = credit;
    }
}

class Accounts extends FF{
    private String actno;
    private  double balance;

    public Accounts() {
    }
    public Accounts(String actno, double balance) {
        this.actno = actno;
        this.balance = balance;
    }

    public String getActno() {
        return actno;
    }

    public void setActno(String actno) {
        this.actno = actno;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}

class FF{
    public void doSome(){
        System.out.println("do Some");
    }
}
    2.2.2 方法的覆盖

   代码加注释讲解方式,其中Animal、Cat、Bird类可以新建java类使用。

/**
 * 关于java语言当中方法的覆盖:
 *      1,方法覆盖有被称为方法重写,英文:override[官方的]/overwrite。
 *      2、什么时候使用方法重新?
 *          当父类中的方法已经无法满足当前子类的业务需求,
 *          子类有必要将父类中继承的方法进行重新编写,
 *          这个重新编写的过程称为方法重写/方法覆盖。
 *      3,什么条件满足之后方法会发生重写?【代码满足什么条件后,就构成方法的覆盖?】
 *          方法重写发生在具有继承关系的父子类之间
 *          返回值类型相同,方法名相同,形参列表相同
 *          访问权限不能更低,可以更高。
 *          抛出异常不能更多,可以更少。
 *      4,注意:
 *          私有方法不能继承,所有不能覆盖。
 *          构造方法不能继承,所以不能覆盖。
 *          静态方法不存在覆盖。
 *          覆盖只针对方法,不谈属性。
 *
 *
 */

public class HelloWorld {

    public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
        //创建动物对象
        Animal a = new Animal();
        a.move();

        Cat c = new Cat();
        c.move();

        Bird b = new Bird();
        b.move();
    }
}

class Bird extends Animal{

    public void move(){
        System.out.println("鸟儿在飞翔");
    }
}

class Cat extends Animal{
    public void move(){
        System.out.println("猫在走猫步");
    }
}

class Animal{
    public void move(){
        System.out.println("动物在移动");
    }
}
2.3多态
关于java语言当中的多态语法机制(概念):
  •    向上转型(upcasting)
          子类型-->父类型  称为:自动类型转换。
      
      向下转型(downcasting)
          父类型-->子类型 称为:强制类型转换。【需要加强制类型转换符】
      
      无论向上转型还是向下转型,两种类型之间必须要有继承关系,否则程序是无法编译通过的。
    
代码加注释讲解方式,其中Animal、Cat、Bird类可以新建java类使用。
public class HelloWorld {

    public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口

        //使用多态语法机制
        // =====父类引用指向子类型对象【多态】 向上转型 =============================================
        /**
         * Animal和Cat之间存在继承关系,Animal是父类,Cat是子类。
         * Cat is a Animal
         *
         * new Cat()创建对象的类型是Cat,a2这个引用的数据类型是Animal,进行了类型转换。
         * 子类型转换成父类型,称为向上转型/upcasting。
         *
         * java语言允许:父类型引用指向子类型对象。
         *
         */
        Animal a2 = new Cat();
        /**
         * java语言是先分析编译阶段,在分析运行阶段,编译无法通过,是无法运行的。
         *
         * 编译阶段编译器检查a2这个引用的数据类型为Animal,由于Animal.class字节码当中有
         * move()方法,所以编译通过了。这个过程我们成为静态绑定,编译阶段绑定。只有静态绑定
         * 成功之后才有后续的运行。
         *
         * 在程序运行阶段,jvm堆内存当中真实创建的对象是Cat对象,那么以下程序在运行阶段一定会
         * 调用Cat对象的move()方法,此时发生了程序的动态绑定,运行阶段绑定。
         *
         * 无论Cat类有没有重写move()方法,运行阶段一定调用的是Cat对象的move()方法,因为底层
         * 真实对象就是Cat对象。
         *
         * 父类型引用指向子类型对象,这种机制导致程序存在"编译阶段绑定"和"运行阶段绑定"两种不同的形态/状态,
         * 这种机制称为:多态语法机制。
         *
         */
         a2.move();// 输出:猫在走猫步

        /**
         * 分析以下程序为啥不能调用?
         *
         *      因为编辑阶段编译器检查到a2的类型是Animal类型,从Animal.class字节码文件当中查找catchMouse()
         *      方法,最终没找到该方法,导致静态绑定失败,也就是说编译失败了。别谈运行了。。
         */
         //a2.catchMouse();

        //===== 父类引用指向子类型对象【多态】  向下转型【只有当访问子类对象当中的特有方法】===================================
        Animal a3 = new Bird();

        /**
         * 以下程序编译时没问题的,因为编译器检查到a3的数据类型是Animal, Animal和Cat是存在继承关系,并且Animal
         * 是父类,Cat是子类型,父类装换成子类型叫做向下转型,语法合格。
         *
         * 程序虽然编译通过了,但是程序运行阶段会出现异常,因为jvm堆内存当中真实存在的对象是Bird类型,Bird对象无法
         * 转换成Cat对象,因为这两种类型不存在继承关系,会出现异常:java.lang.ClassCastException。
         */
         //Cat c3 = (Cat) a3;

        /**
         * 1,以上异常只有在强制类型转换的时候会发生,也就是说"向下转型"存在隐患(编译通过,但运行出错了)
         * 2,向上转型只要编译通过,运行一定不会出现问题,
         * 3,向下转型编译通过,运行可能出现问题,如何避免出现ClassCastException异常呢?
         *      使用instanceof运算符可以避免出现以上的异常。
         * 4,instanceof运算符的使用
         *      语法结构:(引用 instanceof 数据类型名)
         *      运算符执行结果类型是布尔类型,true/false
         * 5,java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判断,避免ClassCastException异常发生。
         *
         */

        if(a3 instanceof Cat){
            Cat c3 = (Cat) a3;
            c3.catchMouse();//调用子类对象中特有的方法
        }else if (a3 instanceof Bird) {
            Bird b2 = (Bird) a3;
            b2.fly();//调用子类对象中特有的方法
        }
    }
}

class Bird extends Animal{

    public void move(){
        System.out.println("鸟儿在飞翔");
    }

    public void fly(){
        System.out.println("鸟儿在fly");
    }
}

class Cat extends Animal{
    public void move(){
        System.out.println("猫在走猫步");
    }
    public void catchMouse(){
        System.out.println("猫在抓老鼠");
    }
}

class Animal{
    public void move(){
        System.out.println("动物在移动");
    }
}

3. 面向对象–>定义类和对象

   代码加注释讲解方式,其中Students类可以新建一个java类使用。
  • 局部变量在栈内存中存储

  • 成员变量中的实例变量实例变量在堆内存的java对象内部存储

    public class HelloWorld {

      public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
          // 通过一个类可以实例化N个对象
          // 实例化对象语法:new 类名();
          // new是java语言当中的一个运算符。
          // new运算符的作用是创建对象,在jvm堆内存当中开辟新的内存空间
          // 方法区内存:在类加载的时候,class字节码代码片段被加载到该内存空间当中。
          // 栈内存(局部变量):方法代码片段执行的时候,会给该方法分配内存空间,在栈内存中压栈。
          // 堆内存:new的对象在堆内存中存储。
          // Student是一个引用类型
          // peo是一个变量名
          // new Student()是一个学生对象
          // peo是一个局部变量【在栈内存中存储】
          // 什么是对象?new运算符在堆内存中开辟内存空间称为对象。
          // 什么是引用?引用是一个变量,只不过这个变量中保存了另一个java对象的内存地址。
          // java语言当中,程序员不能直接操作堆内存,java中没有指针;不像C语言
          // java语言当中,程序员只能通过"引用"去访问堆内存当中对象内部的实例变量。
          Students peo = new Students();
    
          // 访问实例变量的语法格式:
          // 读取数据:引用.变量名
          System.out.println(peo.name);
          System.out.println(peo.noID);
          System.out.println(peo.sex);
          System.out.println(peo.age);
          System.out.println(peo.addr);
    
          // 修改数据:引用.变量名 = 值
          peo.name = "张三";
          peo.noID = 1233;
          peo.age = 16;
          peo.sex = true ? "男" : "女";
          peo.addr = "深圳";
    
          // 再创建一个Student对象
          Students st = peo;
    
          System.out.println(st.name);
          System.out.println(st.noID);
          System.out.println(st.sex);
          System.out.println(st.age);
          System.out.println(st.addr);
      }
    

    }

    /*学生类
    学生类是一个模板
    描述所有学生的共同特征【状态+行为】
    当前类只描述学生的状态信息【属性】
    */

    class Students {
    // 类体 = 属性 + 行为

      // 属性【存储数据采用变量的形式】
      // 由于变量定义在类体当中,方法体之外,这种变量称为成员变量
      // 所有学生都有学号信息
      // 但是每一个学生的学号是不同的
      // 所有访问这个学号必须先创建对象,通过对象去访问学号信息
      // 学号信息不能直接通过"类"去访问,所以这种成员变量有被叫做:实例变量
      // 对象有被称为实例,实例变量有被称为对象变量。【对象级别的变量】
      // 不创建对象,这个noID变量的内存空间是不存在的,只有创建了对象,这个noID的变量内存空间才会创建。
    
      int noID;// 学号
      String name; //姓名
      int age; //年龄
      String sex; //性别
      String addr; // 地址
    

    }

4. 面向对象–>构造方法

  • 构造方法有被称为构造函数/构造器/Constructor
  • 构造方法结构:
    • [修饰符列表] 构造方法名(形式参数列表){ 构造方法体;}
  • 回顾普通方法的语法结构:
    • [修饰符列表] 返回值类型 方法名(形式参数列表){ 方法体;}
  • 对于构造方法来说,"返回值类型"不需要指定,并且也不能写void;只要写上void,这个方法就成为普通方法了。
  • 构造方法的方法名必须和类名保持一致。
  • 构造方法的作用?
    • 构造方法存在的意义是,通过构造方法的调用,可以创建对象。
    • 创建对象的同时,初始化实例变量的内存空间。
  • 构造方法应该怎么调用?
    • 普通方法是这样调用的:方法修饰符中有static的时候:类名.方法名(实参列表)、方法修饰列表中没有static的时候:引用.方法名(实参列表)
    • new 构造方法名(实参列表)
  • 构造方法调用执行之后,有返回值吗?
    每一个构造方法实际上执行结束之后都有返回值,但是这个"return 值;"这样的语句不用写。并且返回值类型是构造方法所在类的类型。由于构造方法的返回值类型是类本身,所以返回值类型不需要填写。
  • 当一个类中没有定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个方法被称为缺省构造器。
  • 当一个类显示的构造方法定义出来了,那么系统则不再默认为这个类提供缺省构造器。建议开发中手动为当前类提供无参数构造方法。因为无参数构造方法太常用了。
  • 构造方法支持重载机制。在一个类中编写多个构造方法,多个构造方法显然已构成方法重载机制。
demo代码示例:
public class HelloWorld {

    public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口

        new Students();
    }

}

class Students {
    //构造方法
     public Students() {
         System.out.println("构造方法");
     }
     
}
5. 面向对象–>参数的传递
  • 对象和引用:

    • 对象:目前在使用new运算符在堆内存中开辟的内存空间称为对象。
    • 引用:是一个变量,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了堆内存当中的对象。
  • 所有访问实例相关的数据,都需要通过"引用."的方式访问,因为只有通过引用才能找到对象。
    -只有一个空的引用,访问对象的实例相关的数据会出现空指针异常。

  • 参数的传递
    -方法调用的时候,涉及参数传递问题,传递的时候,java只遵循一种语法机制,就是将变量中保存的"值"传递过去了,只不过有的时候这个值 是一个字面值,有的时候这个值是另一个java对象的内存地址。

demo代码示例:
public class HelloWorld {

    public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口

        User u = new User(20);
        // 传递u给add方法的时候,实际上传递的是u变量中保存的值,只不过这个值是一个java对象的内存地址。
        add(u);//等同于 add(0x....);

    }

    public static void add(User a){
        a.age++;
        System.out.println("add---->" + a.age);
    }

}
class User{
    int age;//实例变量
    public User(int i){
        age = i;
        System.out.println("age---->" + age);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值