面向对象

一、初识面向对象

1、面向过程&面向对象

  • 面向过程思想

    • 步骤清晰简单,第一步做什么,第二步做什么。。。

    • 面向过程适合处理一些较为简单的问题

  • 面向对象思想

    • 物以类聚,分类的思维方式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。

    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!

  • 对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,任然需要面向过程的思路去处理。

2、面向对象

  • 面向对象编程(Object-Oriented Programming,OOP)

  • 面向对象编程的本质就是;以类的方式组织代码,以对象的组织(封装)数据。

  • 对象:现实世界中,随处可见的·一种事物就是对象。对象是事物存在的实体。通常将对象划分为两个部分:

    • 静态部分:即属性。

    • 动态部分:方法。

  • :如果将现实世界中的一个事物抽象成对象,具有相同特性和行为的一类事物就称为类,类就是这类对象的统称。类是封装对象的属性和行为的载体。

  • 三(四)大特性

    • 封装

      封装是面向对象编程的核心思想。将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。

    • 继承

      当处理一个问题时,可以将一些有用的类保留下来,这些类通常有相同的属性,甚至相同的方法,当遇到同样问题时可以拿来复用。例如鸽子具有与鸟类相同的属性和行为。便可以在创建信鸽类时将鸟类拿来复用,并且保留鸟类具有的属性和行为。

    • 多态

      将父类对象应用于子类的特征就是多态:多态性允许一统一的风格编写程序,以处理种类繁多的已存在的类以及相关类。该统一风格可以由父类来实现,根据父类统一风格可以由父类实现,就可以实例化子类的对象。由于整个事件的处理都只依赖于父类的方法,所以日后只要维护和调整父类的方法即可,这样就降低了维护的难度,节省了时间。

    • 抽象

      核心的编程思想

  • 从认识角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象

  • 从代码运行角度考虑是先有类后有对象。类是对象的模板。

二、回顾方法的定义与调用

1、方法的定义

修饰符 返回值类型 方法名(参数类型 参数名){
  ...
   方法体
  ...
   return 返回值;
}
  • 修饰符:修饰符是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。

  • 返回值类型:方法可能会返回值,returnValueType是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType的关键字是void。

  • 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。

  • 参数类型:参数像是一个占位符。当方法被调用时,传递只给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。

    • 形式参数:在方法被调用时用于接收外界输入的数据。

    • 实参:调用方法时实际传给方法的数据。

  • 方法体:方法体包含具体的语句,定义该方法的功能。

2、方法的调用

  • 调用方法:对象名.方法名(实参列表)

  • java支持两种调用方法的方式,根据方法是否返回值来选择。

    • 当方法返回一个值的时候,方法调用通常被当做一个值,例如:

      int larger = max(30,40);
    • 如果方法返回值是void,方法调用一定是一条语句。

      System.out.println("Hello World!");

####

三、对象的创建分析

1、权限修饰符

访问包位置privateprotectedpublic
本类 可见 可见 可见
同包其他类或子类 不可见 可见 可见
其他包的类或子类 不可见 不可见 可见

2、类的构造方法:

  • 构造方法没有返回值,也不能写void

  • 构造方法的名称要与本类的名称相同

    权限修饰符 方法名(){
       //构造方法体
    }

3、使用new关键字创建对象

  • 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器(构造方法)的调用。

    package OOP;

    public class Student {
       //属性,字段
       String name;
       int age;

       //方法 alt + insert
       public /*static*/ void study(){
           //在静态方法中不可以使用this关键字
           System.out.println(this.name + "在学习");
      }

       public static void main(String[] args) {
           //实例化
           Student xiaoming = new Student();
           Student xiaohong = new Student();

           xiaoming.age = 3;
           xiaoming.name = "小明";

           System.out.println(xiaoming.name);
           System.out.println(xiaoming.age);

           xiaohong.name = "小红";
           xiaohong.age = 5;

           System.out.println(xiaohong.name);
           System.out.println(xiaohong.age);
           
           /*studey();*/  //在静态方法中不可以直接调用非静态方法,所以报错
      }

    }

4、对象的比较

package OOP;

public class Demo05 {
   public static void main(String[] args) {
       String c1 = new String("abc");
       String c2 = new String("abc");
       String c3 = c1;

       //使用“==”运算符比较c2与c3
       System.out.println("c2 == c3的运算结果为:" + (c2 == c3));//结果为falsa
       
       System.out.println("c2.equals(c3)的运算结果为:" + c2.equals(c3));//结果为true
  }
}
  • equals()方法是String类中的方法,他用于比较两个对象引用所指的内容是否相等;而“==”运算符比较的是两个对象引用的地址是否相等。

5、对象的销毁

  • 两种情况java虚拟机会将对象视为“垃圾”:

    • 对象引用超过其作用范围,这个对象被视为垃圾

    • 将对象赋值为NULL

  • 虽然垃圾回收机制已经很完善,但垃圾回收器只能回收那些由new操作符创建的对象。

四、面向对象三大特性

1、封装

  • 该藏的藏,该漏的漏

    • 我们程序设计要追求“高内聚,低耦合”。

      • 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉。

      • 低耦合:仅暴露少量的方法给外部使用。

  • 封装(数据的隐藏)

    • 通常,应进制直接访问一个对象中数据的实际表示,而应通过接口操作来访问,这称为信息隐藏。

  • 属性私有,get/set

    package OOP;

    public class Student1 {

       /*
       1.提高程序的安全性,可以保护数据
       2.可以隐藏代码的实现细节
       3.统一接口
       4.提高了系统的可维护性
        */

       //属性私有
       private int id;
       private String sex;
       private String name;
       private int age;

       //提供一些可以操作这个属性的方法
       //提供一些public的get、set方法

       //alt + insert 可智能生成get/set方法
       
       //get 获得这个数据
       public String getName(){
           return this.name;
      }

       //set 给这个数据设置值
       public void setName(String name){
           //可在set方法里面设置一些安全性检查,例如判断name是否合法
           this.name = name;
      }

       public int getAge() {
           return age;
      }
       //可在set方法里面设置一些安全性检查,例如判断age是否合法
       public void setId(int age) {
           if(age>120||age<0){
               this.age = 3;
          }else{
               this.age = age;
          }
      }

    }

2、继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好地建模

  • extends的意思是”扩展“。子类是对父类的扩展,ctrl + h 可以显示出继承树

  • 继承并不只是扩展父类的功能,他还可以重写父类的构造方法。

    • 重写(覆盖):就是在子类中将父类的成员方法的名称和参数列表保留,重写成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型

    • 重构:特殊的重写方式,子类与父类的成员方法返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法实现内容。

    • 重写父类方法时,修改方法的修饰权限只能从小的范围到大的范围改变。例如父类的doSomething()方法的权限为protected,子类中不能将其改成private。(public > protected > Default >private)

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

    • 抛出的异常:范围可以被缩小,但不能扩大

    • alt + insert + override :重写快捷键

    • 被final修饰的类不能被继承

      package OOP;

      import java.security.ProtectionDomain;

      public /*final*/ class Test {
         public Test() {//构造方法
             //SomeSentence
        }

         public void doSomething() {//成员方法
             //SomeSentence
        }
         
         protected Test dolt(){//返回值为Test类型
             return new Test();
        }
      }

      class Test2 extends Test{//继承父类
         public Test2(){//构造方法
             super();//调用父类构造方法
             super.doSomething();//调用父类成员方法
        }
         
         public void doSomethingNew() {//新增方法
             //SomeSentence
        }

         public void doSomething() {//重写父类方法
             //SomeNewSentence
        }

         protected Test2 dolt(){//重写父类方法,返回值为Test2类型
             return new Test2();
        }
      }
  • java中类只有单继承,没有多继承

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

  • 继承关系的俩个类,一个为子类(派生类),一个为父类(基类),使用关键字extends来表示。子类和父类之间,从意义上将应该具有“is a”的关系,例如“学生” is a “人 ”

  • Object类

    • java中,所有的类都直接或者间接继承Object类

    • Object类中主要包括clone(),finalize(),equals(),toString()等方法

    • Object类中的getClass() ,notify() ,notifyAll() ,wait()等方法不能被重写,因为这些方法被定义为final类型。

  • super详解

    • 注意点:

      • super调用父类的构造方法,必须在构造方法的第一个

      • super必须只能出现在子类的方法或者构造方法中!

      • super和this不能同时调用构造方法

    • 和this的区别

      • 代表的对象不同:

        • this代表本身调用者这个对象

        • super代表父类对象的应用

      • 前提不同

        • this:没有继承也可以使用

        • super:只有在继承条件才可以使用

      • 构造方法

        • this():本类的构造方法

        • super():父类的构造方法

3、多态

  • 即同一方法可以根据发送对象的不同二采用多种不同的行为方式

  • 利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。

  • 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多

  • 多态存在的条件

    • 有继承关系

    • 子类重写父类方法

    • 父类引用指向子类对象

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

  • 对象能执行哪些方法,主要看对象左边的类型,和右边关系不大

    • 子类能调用的方法都是自己的或者是继承父类的

    • 父类型可以指向子类,但是不能调用子类独有的方法

  • instanceof 与 类型转换

    • instanceof

      X x = new Y();

      System.out.printfln(X instanceof Y);//X与Y之间是否存在父子关系,若存在则返回true,否则返回false
    • 类型转换(高 (父) -- > 低(子))

      Person obj = new Student();

      //obj不能直接用子类的方法,可以强制转换为子类后调用子类方法
      Student student = (Student)obj;
      student.go();

      //也可以用以下方式
      ((Student)obj).go();
    • 总结:

      • 父类引用指向子类的对象

      • 把子类转换为父类:向上转型

      • 把父类转换为子类:强制转换

      • 方便方法的调用,减少重复的代码

五、抽象类与接口

1、抽象类

  • 抽象类的关键字:abstract

  • 使用abstract关键字定义的类称为抽象类,而是用这个关键字定义的方法称为抽象方法。

  • 抽象方法没有方法体,这个方法本身没有任何意义,除非他被重写,而承载这个抽象方法的抽象类必须被继承,实际上抽象类除了被继承之外没有任何意义

  • 抽象类中可以没有抽象方法,但是只要一个类中有一个抽象方法,此类就被标记为抽象类。

  • 抽象类被继承后需要实现其中的所有抽象方法,也就是保证相同的方法名称、参数列表和相同返回值类型创建出非抽象方法,当然也可以是抽象方法,则子类也为抽象类

  • 抽象类,不能用new关键字来创建对象,只能由子类重写来实现

  • 定义抽象方法

    public abstract class Test{
       abstract void doSomething();//定义抽象方法
    }

2、接口

(1)接口简介
  • 接口是抽象的延伸,可以把它看作纯粹的抽象类,接口中的所有方法都没有方法体

    • 普通类:只有具体实现

    • 抽象类:具体实现和规范(抽象方法),有构造方法

    • 接口:只有规范,没有构造方法

      • 接口就是规范,定义的一组规则,体现了现实世界中“如果你是...则必须能....”的思想、

      • 口的本质是契约,就像是法律一样,定制好后都遵守

      • OO的精髓,是对对象的抽象,最能体现这一点的就是接口

  • 声明接口的关键字是:interface

    public interface/*关键字*/ drawTest/*接口名*/{
       //在接口中定义的任何字段都自动是static和final的
       void draw(); //接口内的方法,省略abstract关键字
    }

    //public:接口可以像类一样被权限修饰符修饰,但public关键字仅限用于接口在与其同名的文件中被定义
    //接口中,方法必须被定义成public或abstract形式,其他修饰符不被java编译器认可
(2)接口可以多继承
//一个类实现一个接口,可以用implements关键字
public class Parallelogram extends Quadrangle implements drawTest{
  ...//
}
//多继承语法格式
public class 类名 implements 接口1,接口2...,接口N

七、内部类及OOP实战

  • 内部类就是在一个类的内部再定义一个类,比如,在A类中定义一个B类,那么B类性对于A类来说就称为内部类,而A类相对B类来说就是外部类。

1、成员内部类

(1)、成员内部类简介
  • 在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量(私有属性)

  • 定义:

    public class Outer{//外部类
       private class Inner{//内部类
           
      }
    }
  • 调用

    public class Application{
       public static void main(String[] ages){
           Outer.Inner 名称 = Outer.new Inner();
           Inner.方法();
      }
    }
(2)内部类向上转型为接口
(3)使用this关键字获取内部类与外部类的引用

2、静态内部类

  • 在内部类前添加修饰符static,这个内部类就变成静态内部类了。

  • 一个静态内部类中可以声明static成员,但是在非静态内部类中不可以声明静态成员

  • 静态内部类不可以使用外部类的非静态成员

  • 特点

    • 如果创建静态内部类的对象,不需要其外部类的对象

    • 不能从静态内部类的对象中访问非静态外部类的对象

3、局部内部类

  • 在类的方法或任意的作用域中均可以定义内部类

interface OutInterface2{//定义一个接口
   
}

class OuterClass3{
   public OutInterface2 doit(final String X){//doit()方法参数为final类型
       //在doit()方法中定义一个内部类
       class InterClass2 implements Outerface2{
           InnerClass2(String s){
               s = x;
               System.out.println(s);
          }
      }
       return new InnerClass2("doit");
  }
}

4、匿名内部类

public class Test{
   public static void main(String[] ages){
       //没有名字初始化类,不用将实例保存到变量中~
       new Apple().eat();
  }
}

class Apple{
   public void eat(){
       System.out.println("1);
  }
}

5、内部类的继承

    • 内部类和其他普通类一样,可以被继承。

    • 在某个类继承内部类时,必须硬性给与这个类一个带参数的构造方法,并且该构造方法的参数为需要继承内部类的外部类的引用,同时在构造方法体中使用a.super()语句,这样才为继承提供了必要的对象引用。

      public class OutputInnerClass extends ClassA.ClassB{//继承内部类ClassB
         public OutputInnerClass(ClassA a){
             a.super();
        }
      }

      calss ClassA{
         class ClassB{
             
        }
      }


posted @ 2022-02-12 10:54  文智  阅读(207)  评论(0)    收藏  举报