7

7 - 面向对象

Java的核心思想OOP(Object-Oriented Programming)

1. 初识面向对象

面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向过程适于处理一些较为简单的问题。(c语言)

面向对象:是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。面向对象适于处理复杂的问题,适于处理需要多人协作的问题。(c++,c#,java,delphi)

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

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

三大特性:封装、继承、多态。

从认识角度考虑,先有对象后有类,对象是具体的事物,类是对对象的抽象;从代码角度考虑,先有类后有对象,类是对象的模板。

2. 方法回顾与加深

break和return的区别:

  • break:跳出switch;结束循环。

  • return:结束方法;返回一个结果。

静态方法与非静态方法:静态方法(static)可以通过类直接调用;非静态方法需要先实例化这个类(new),再通过对象调用该方法。静态方法和类一起加载,而非静态方法在类实例化之后才存在,因此在静态方法中不能调用非静态方法(静态方法中可以调用其它静态方法)。

3. 对象的创建分析

类和对象的区别

类 = 属性 + 方法

类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物;类都是用来描述/定义某一类具体事物应该具备的特点或行为。

对象是抽象概念的具体实例;能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。

创建与初始化对象

构造器详解

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

类中的构造器也称为构造方法,是在进行创建对象时必须调用的,并且构造器有两个特点:①必须和类的名字相同;②必须没有返回类型,也不能写void。

一个类即使什么也不写,它也会存在一个方法(构造方法)。

构造器作用:①使用new关键字,本质是在调用构造器;②构造器用来初始化对象的值。

注意点:无参构造/无参构造(一旦定义了有参构造,无参构造就必须显式定义)

注:快捷键 Alt + Insert(需要与Fn键组合)、this

创建对象内存分析

package com.oop.demo01;
​
public class Pet {
    public String name;
    public int age;
    
    public void shout(){
        System.out.println("叫!");
    }
}
package com.oop.demo01;
​
public class Application {
    public static void main(String[] args) {
        Pet dog = new Pet();
​
        dog.name = "小白";
        dog.age = 3;
​
        System.out.println(dog.name);
        System.out.println(dog.age);
​
        Pet cat = new Pet();
    }
}

内存使用:

 小结:

①类与对象:类是一个模板(抽象),对象是一个具体的实例;

②方法:定义、调用;

③对应的引用:引用类型(对象是通过引用来操作的,栈-->堆)/基本类型(8种);

④属性:字段、成员变量;默认初始化(数字:0/0.0;char:u0000;boolean:false;引用:null);赋值(修饰符 属性类型 属性名 = 属性值);

⑤对象的创建和使用:必须使用new关键字创建对象,构造器;对象的属性;对象的方法;

⑥类:静态属性(属性)、动态行为(方法)。

4. 面向对象三大特性

Ⅰ. 封装

程序设计追求“高内聚,低耦合”,高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量的方法给外部使用。

封装(数据的隐藏):通常,应禁止直接访问一个对象中数据的实际表示,而通过操作接口来访问,这成为信息隐藏。

封装的意义:①提高程序的安全性,保护数据;②隐藏代码的实现细节;③统一接口;④增强系统可维护性。

注:封装重点是对于属性而言的,属性私有(private关键字),set/get

Ⅱ. 继承

继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好地建模。extends的意思是扩展,子类是父类的扩展。

Java中类只有单继承,没有多继承!

继承是类和类之间的一种关系,除此之外,类和类之间的关系还有依赖、组合、聚合等;继承关系的两个类,一个为子类(派生类),一个为父类(基类),子类继承父类,使用关键字extends来表示;子类和父类之间,从意义上讲应该具有“is a”的关系。

注:在Java中所有的类都默认直接或者间接继承Object类;子类继承了父类,就会拥有父类的全部方法!

super

注意点:

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

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

  • super和this不能同时调用构造函数,因为它们都必须在构造方法的第一个会出现冲突。

和this对比:

  • 代表的对象不同:this代表本身调用者这个对象;super代表父类对象的引用;

  • 前提条件不同:this没有继承也可以使用;super只能在继承条件下才能使用;

  • 构造方法:this();默认调用本类的构造;super();调用的是父类的构造。

方法重写

重写都是方法的重写,与属性无关;非静态方法才可以重写,静态方法的方法调用只和左边(即定义的数据类型)有关。

注意点:

  • 需要有继承关系,子类重写父类的方法!

  • 特点:

    ①方法名必须相同;

    ②参数列表必须相同;

    ③修饰符(范围可以扩大,但不能缩小,public>protected>default>private);

    ④抛出的异常(异常的范围可以被缩小,但不能扩大)。

  • 重写,子类的方法和父类必须要一致,方法体不同。

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

不能重写的方法:

①static:属于类,它不属于实例;

②final:常量;

③private:私有。

Ⅲ. 多态

多态

多态可以实现动态编译,通过多态可以使得程序的可扩展性增强。

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

一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)。

注意点:

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

  • 父类和子类之间有联系,否则会出现类型转换异常(ClassCastException!)

  • 存在条件:①继承关系;②方法需要重写;③父类的引用指向子类对象(Father f1 = new Son())。

instanceof

类型转换:

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

  • 把子类转换为父类,向上转型,不用强制转换,可能会丢失子类本来的一些方法(Person person = student;);

  • 把父类转换为子类,向下转型,需要强制转换(Student student = (Student) person;);

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

static补充

①静态代码块

package com.oop.Demo05;
​
public class Person {
    //2,匿名代码块
    {
        System.out.println("匿名代码块");
    }
​
    //1,静态代码块,只执行一次
    static{
        System.out.println("静态代码块");
    }
​
    //3,构造方法
    public Person(){
        System.out.println("构造方法");
    }
​
    public static void main(String[] args) {
        Person person1 = new Person();
        System.out.println("=================");
        Person person2 = new Person();
​
    }
}
//执行结果
静态代码块
匿名代码块
构造方法
=================
匿名代码块
构造方法

②静态导入包:可以直接写方法名,不用加包作为前缀。

package com.oop.Demo05;
​
//静态导入包
import static java.lang.Math.random;
​
public class Test {
    public static void main(String[] args) {
        System.out.println(random());
    }
}

注:final修饰的类不能够被继承。

5. 抽象类和接口

抽象

abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么方法就是抽象方法;如果修饰类,那么类就是抽象类。

抽象类中可以没有抽象方法,但抽象方法的类一定要声明为抽象类。

抽象类:不能使用new关键字来创建对象,是用来让子类继承的;抽象方法:只有方法的声明,没有方法的实现,是用来让子类实现的。

子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。

抽象类:

package com.oop.Demo06;
​
//抽象类:类 extends ,单继承(但接口可以多继承)
public abstract class Action {
​
    //作为一种约束,希望有人帮我们实现
    //抽象方法,只有方法名字,没有方法实现
    public abstract void doSomething();
    
}

抽象类的子类:

package com.oop.Demo06;
​
//继承了抽象类的子类,都必须要实现它所有的方法;除非子类也是一个抽象类,这时这些方法由子类的子类实现
public class A extends Action{
​
    @Override
    public void doSomething() {
​
    }
​
}

特点(抽象的抽象):

①不能new这个抽象类,只能靠子类去实现它,是一个约束!

②抽象类中可以写普通方法;

③抽象方法必须在抽象类中,即如果一个类中包含抽象方法,那么它一定要是抽象类。

思考:

①不能new,是否存在构造器(抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super()或super(参数列表)调用抽象类中的构造方法);

②抽象类存在的意义(提高开发效率)。

接口

普通类:只有具体实现;

抽象类:具体实现和规范()抽象方法都有;

接口:只有规范。自己无法写方法,专业的约束,约束和实现分离:面向接口编程。

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

接口的本质是契约,就像我们的法律一样,制定好后大家都要遵守。

面向对象的精髓是对对象的抽象,最能体现这一点的就是接口。设计模式所研究的实际上就是如何合理地去抽象。

声明类的关键字:class;声明接口的关键字:interface。

接口1:

package com.oop.Demo07;
​
//interface 定义的关键字
public interface UserServise {
    //接口中的所有定义的属性都是常量 public static final
    int age = 90;
​
    //接口中的所有定义的方法其实都是抽象的 public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

接口2:

package com.oop.Demo07;
​
public interface TimeService {
    void timer();
}

实现类:

package com.oop.Demo07;
​
//一个类可以实现一个接口,通过implements 接口
//实现了接口的类,就需要重写接口中的方法
//利用接口实现多继承
public class UserServiceImpl implements UserServise, TimeService{
​
    @Override
    public void add(String name) {
​
    }
​
    @Override
    public void delete(String name) {
​
    }
​
    @Override
    public void update(String name) {
​
    }
​
    @Override
    public void query(String name) {
​
    }
​
    @Override
    public void timer() {
​
    }
}

作用:

①约束;

②定义一些方法,让不同的人实现;

③接口中的所有定义的方法其实都是抽象的 public abstract;

④接口中的所有定义的属性都是常量 public static final;

⑤接口不能被实例化,接口中没有构造方法;

⑥通过implements可实现多个接口;

⑦实现接口必须要重写接口中的方法。

6. 内部类及OOP实战

内部类

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

①成员内部类;

②静态内部类;

③局部内部类;

④匿名内部类。

Application类:

package com.oop;
​
import com.oop.Demo08.Outer;
​
public class Application{
    public static void main(String[] args) {
​
        //外部类 new
        Outer outer = new Outer();
        //内部类 通过外部类来实例化
        Outer.Inner inner = outer.new Inner();
        inner.in();
        inner.getID();
​
    }
}
//执行结果
这是内部类的方法
10

Outer类和Inner类:

package com.oop.Demo08;
​
public class Outer {
​
    private int id = 10;
    public void out(){
        System.out.println("这是外部类的方法");
    }
​
    //成员内部类;有static修饰符就变成了静态内部类,这时就不能在内部类中获得外部类的非静态的属性或方法了
    public /*static*/ class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }
​
        //获得外部类的私有属性、私有方法
        public void getID() {
            System.out.println(id);
        }
    }
​
    //局部内部类
    public void method(){
        class Inner1{
            public void in(){
​
            }
        }
    }
}
​
//一个java类中可以有多个class类,但只能有一个public class
//可以添加main方法作为测试函数
class A{
​
}

附:狂神b站视频链接

原文地址:https://www.cnblogs.com/java-learning-xx/p/12850073.html